grapes / src / Chunkiser / input-stream-avf.c @ 997c2b68
History | View | Annotate | Download (10.7 KB)
1 | 1e8dedd8 | Luca Abeni | /*
|
---|---|---|---|
2 | * Copyright (c) 2009 Luca Abeni
|
||
3 | *
|
||
4 | * This is free software; see gpl-3.0.txt
|
||
5 | */
|
||
6 | |||
7 | #include <libavformat/avformat.h> |
||
8 | #include <stdbool.h> |
||
9 | 0f79759c | Luca Abeni | #include <string.h> |
10 | 1e8dedd8 | Luca Abeni | |
11 | //#include "dbg.h"
|
||
12 | 0f79759c | Luca Abeni | #include "int_coding.h" |
13 | 1e8dedd8 | Luca Abeni | #include "payload.h" |
14 | #include "config.h" |
||
15 | c0c735aa | Luca Abeni | #include "chunkiser_iface.h" |
16 | 1e8dedd8 | Luca Abeni | |
17 | #define STATIC_BUFF_SIZE 1000 * 1024 |
||
18 | fcc01ba5 | Luca Abeni | struct chunkiser_ctx {
|
19 | 1e8dedd8 | Luca Abeni | AVFormatContext *s; |
20 | 1cc19859 | Luca Abeni | int loop; //loop on input file infinitely |
21 | 025da5a8 | Luca Abeni | uint64_t streams; |
22 | 1e8dedd8 | Luca Abeni | int64_t last_ts; |
23 | int64_t base_ts; |
||
24 | a6497b4b | Luca Abeni | AVBitStreamFilterContext *bsf[MAX_STREAMS]; |
25 | 1e8dedd8 | Luca Abeni | }; |
26 | |||
27 | static uint8_t codec_type(enum CodecID cid) |
||
28 | { |
||
29 | switch (cid) {
|
||
30 | case CODEC_ID_MPEG1VIDEO:
|
||
31 | case CODEC_ID_MPEG2VIDEO:
|
||
32 | return 1; |
||
33 | case CODEC_ID_H261:
|
||
34 | return 2; |
||
35 | case CODEC_ID_H263P:
|
||
36 | case CODEC_ID_H263:
|
||
37 | return 3; |
||
38 | case CODEC_ID_MJPEG:
|
||
39 | return 4; |
||
40 | case CODEC_ID_MPEG4:
|
||
41 | return 5; |
||
42 | case CODEC_ID_FLV1:
|
||
43 | return 6; |
||
44 | case CODEC_ID_SVQ3:
|
||
45 | return 7; |
||
46 | case CODEC_ID_DVVIDEO:
|
||
47 | return 8; |
||
48 | case CODEC_ID_H264:
|
||
49 | return 9; |
||
50 | case CODEC_ID_THEORA:
|
||
51 | case CODEC_ID_VP3:
|
||
52 | return 10; |
||
53 | case CODEC_ID_SNOW:
|
||
54 | return 11; |
||
55 | case CODEC_ID_VP6:
|
||
56 | return 12; |
||
57 | case CODEC_ID_DIRAC:
|
||
58 | return 13; |
||
59 | 28e6b134 | Luca Abeni | case CODEC_ID_MP2:
|
60 | case CODEC_ID_MP3:
|
||
61 | return 129; |
||
62 | case CODEC_ID_AAC:
|
||
63 | return 130; |
||
64 | case CODEC_ID_AC3:
|
||
65 | return 131; |
||
66 | case CODEC_ID_VORBIS:
|
||
67 | return 132; |
||
68 | 1e8dedd8 | Luca Abeni | default:
|
69 | fprintf(stderr, "Unknown codec ID %d\n", cid);
|
||
70 | return 0; |
||
71 | } |
||
72 | } |
||
73 | |||
74 | 52f45fc1 | Luca Abeni | static void audio_header_fill(uint8_t *data, AVStream *st) |
75 | { |
||
76 | audio_payload_header_write(data, codec_type(st->codec->codec_id), st->codec->channels, st->codec->sample_rate, st->codec->frame_size); |
||
77 | } |
||
78 | |||
79 | 1e8dedd8 | Luca Abeni | static void video_header_fill(uint8_t *data, AVStream *st) |
80 | { |
||
81 | int num, den;
|
||
82 | |||
83 | num = st->avg_frame_rate.num; |
||
84 | den = st->avg_frame_rate.den; |
||
85 | //fprintf(stderr, "Rate: %d/%d\n", num, den);
|
||
86 | if (num == 0) { |
||
87 | num = st->r_frame_rate.num; |
||
88 | den = st->r_frame_rate.den; |
||
89 | } |
||
90 | if (num > (1 << 16)) { |
||
91 | num /= 1000;
|
||
92 | den /= 1000;
|
||
93 | } |
||
94 | 09154f88 | Luca Abeni | video_payload_header_write(data, codec_type(st->codec->codec_id), st->codec->width, st->codec->height, num, den); |
95 | 1e8dedd8 | Luca Abeni | } |
96 | |||
97 | fb2411d6 | Luca Abeni | static void frame_header_fill(uint8_t *data, int size, AVPacket *pkt, AVStream *st, AVRational new_tb, int64_t base_ts) |
98 | 1e8dedd8 | Luca Abeni | { |
99 | int32_t pts, dts; |
||
100 | |||
101 | if (pkt->pts != AV_NOPTS_VALUE) {
|
||
102 | 7e44761d | Luca Abeni | pts = av_rescale_q(pkt->pts, st->time_base, new_tb), |
103 | pts += av_rescale_q(base_ts, AV_TIME_BASE_Q, new_tb); |
||
104 | 1e8dedd8 | Luca Abeni | } else {
|
105 | pts = -1;
|
||
106 | } |
||
107 | //dprintf("pkt->pts=%ld PTS=%d",pkt->pts, pts);
|
||
108 | if (pkt->dts != AV_NOPTS_VALUE) {
|
||
109 | 7e44761d | Luca Abeni | dts = av_rescale_q(pkt->dts, st->time_base, new_tb); |
110 | dts += av_rescale_q(base_ts, AV_TIME_BASE_Q, new_tb); |
||
111 | 1e8dedd8 | Luca Abeni | } else {
|
112 | fprintf(stderr, "No DTS???\n");
|
||
113 | dts = 0;
|
||
114 | } |
||
115 | //dprintf(" DTS=%d\n",dts);
|
||
116 | frame_header_write(data, size, pts, dts); |
||
117 | } |
||
118 | |||
119 | fcc01ba5 | Luca Abeni | static int input_stream_rewind(struct chunkiser_ctx *s) |
120 | c0c735aa | Luca Abeni | { |
121 | 851db83d | Luca Abeni | int ret;
|
122 | c0c735aa | Luca Abeni | |
123 | 851db83d | Luca Abeni | ret = av_seek_frame(s->s,-1,0,0); |
124 | s->base_ts = s->last_ts; |
||
125 | c0c735aa | Luca Abeni | |
126 | 851db83d | Luca Abeni | return ret;
|
127 | c0c735aa | Luca Abeni | } |
128 | |||
129 | |||
130 | /* Interface functions */
|
||
131 | |||
132 | fcc01ba5 | Luca Abeni | static struct chunkiser_ctx *avf_open(const char *fname, int *period, const char *config) |
133 | 1e8dedd8 | Luca Abeni | { |
134 | fcc01ba5 | Luca Abeni | struct chunkiser_ctx *desc;
|
135 | 1e8dedd8 | Luca Abeni | int i, res;
|
136 | 1cc19859 | Luca Abeni | struct tag *cfg_tags;
|
137 | 025da5a8 | Luca Abeni | int video_streams = 0, audio_streams = 1; |
138 | 1e8dedd8 | Luca Abeni | |
139 | avcodec_register_all(); |
||
140 | av_register_all(); |
||
141 | |||
142 | fcc01ba5 | Luca Abeni | desc = malloc(sizeof(struct chunkiser_ctx)); |
143 | 1e8dedd8 | Luca Abeni | if (desc == NULL) { |
144 | return NULL; |
||
145 | } |
||
146 | res = av_open_input_file(&desc->s, fname, NULL, 0, NULL); |
||
147 | if (res < 0) { |
||
148 | fprintf(stderr, "Error opening %s: %d\n", fname, res);
|
||
149 | |||
150 | return NULL; |
||
151 | } |
||
152 | |||
153 | desc->s->flags |= AVFMT_FLAG_GENPTS; |
||
154 | res = av_find_stream_info(desc->s); |
||
155 | if (res < 0) { |
||
156 | fprintf(stderr, "Cannot find codec parameters for %s\n", fname);
|
||
157 | |||
158 | return NULL; |
||
159 | } |
||
160 | 025da5a8 | Luca Abeni | desc->streams = 0;
|
161 | 1e8dedd8 | Luca Abeni | desc->last_ts = 0;
|
162 | desc->base_ts = 0;
|
||
163 | 1cc19859 | Luca Abeni | desc->loop = 0;
|
164 | cfg_tags = config_parse(config); |
||
165 | if (cfg_tags) {
|
||
166 | 37f8b121 | Luca Abeni | const char *media; |
167 | |||
168 | 1cc19859 | Luca Abeni | config_value_int(cfg_tags, "loop", &desc->loop);
|
169 | 37f8b121 | Luca Abeni | media = config_value_str(cfg_tags, "media");
|
170 | if (media) {
|
||
171 | if (!strcmp(media, "audio")) { |
||
172 | audio_streams = 0;
|
||
173 | video_streams = 1;
|
||
174 | } else if (!strcmp(media, "video")) { |
||
175 | audio_streams = 1;
|
||
176 | video_streams = 0;
|
||
177 | } else if (!strcmp(media, "av")) { |
||
178 | audio_streams = 0;
|
||
179 | video_streams = 0;
|
||
180 | } |
||
181 | } |
||
182 | 1cc19859 | Luca Abeni | } |
183 | dcc42706 | Luca Abeni | free(cfg_tags); |
184 | 1e8dedd8 | Luca Abeni | for (i = 0; i < desc->s->nb_streams; i++) { |
185 | 025da5a8 | Luca Abeni | if (desc->s->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
|
186 | if (video_streams++ == 0) { |
||
187 | desc->streams |= 1ULL << i;
|
||
188 | } |
||
189 | 1e8dedd8 | Luca Abeni | fprintf(stderr, "Video Frame Rate = %d/%d --- Period: %lld\n",
|
190 | desc->s->streams[i]->r_frame_rate.num, |
||
191 | desc->s->streams[i]->r_frame_rate.den, |
||
192 | av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num));
|
||
193 | *period = av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num);
|
||
194 | } |
||
195 | 025da5a8 | Luca Abeni | if (desc->s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
|
196 | if (audio_streams++ == 0) { |
||
197 | desc->streams |= 1ULL << i;
|
||
198 | } |
||
199 | 1e8dedd8 | Luca Abeni | } |
200 | a6497b4b | Luca Abeni | if (desc->s->streams[i]->codec->codec_id == CODEC_ID_MPEG4) {
|
201 | desc->bsf[i] = av_bitstream_filter_init("dump_extra");
|
||
202 | 2360396a | Luca Abeni | } else if (desc->s->streams[i]->codec->codec_id == CODEC_ID_H264) { |
203 | desc->bsf[i] = av_bitstream_filter_init("h264_mp4toannexb");
|
||
204 | a6497b4b | Luca Abeni | } else {
|
205 | desc->bsf[i] = NULL;
|
||
206 | } |
||
207 | 1e8dedd8 | Luca Abeni | } |
208 | |||
209 | dump_format(desc->s, 0, fname, 0); |
||
210 | |||
211 | return desc;
|
||
212 | } |
||
213 | |||
214 | fcc01ba5 | Luca Abeni | static void avf_close(struct chunkiser_ctx *s) |
215 | 1e8dedd8 | Luca Abeni | { |
216 | 94563418 | Luca Abeni | int i;
|
217 | |||
218 | for (i = 0; i < s->s->nb_streams; i++) { |
||
219 | if (s->bsf[i]) {
|
||
220 | av_bitstream_filter_close(s->bsf[i]); |
||
221 | } |
||
222 | } |
||
223 | av_close_input_file(s->s); |
||
224 | free(s); |
||
225 | 1e8dedd8 | Luca Abeni | } |
226 | |||
227 | fcc01ba5 | Luca Abeni | static uint8_t *avf_chunkise(struct chunkiser_ctx *s, int id, int *size, uint64_t *ts) |
228 | 1e8dedd8 | Luca Abeni | { |
229 | 851db83d | Luca Abeni | AVPacket pkt; |
230 | AVRational new_tb; |
||
231 | int res;
|
||
232 | uint8_t *data; |
||
233 | int header_size;
|
||
234 | 1e8dedd8 | Luca Abeni | |
235 | 851db83d | Luca Abeni | res = av_read_frame(s->s, &pkt); |
236 | if (res < 0) { |
||
237 | if (s->loop) {
|
||
238 | if (input_stream_rewind(s) >= 0) { |
||
239 | a6497b4b | Luca Abeni | *size = 0;
|
240 | 851db83d | Luca Abeni | *ts = s->last_ts; |
241 | a6497b4b | Luca Abeni | |
242 | return NULL; |
||
243 | } |
||
244 | } |
||
245 | 851db83d | Luca Abeni | fprintf(stderr, "AVPacket read failed: %d!!!\n", res);
|
246 | *size = -1;
|
||
247 | 1e8dedd8 | Luca Abeni | |
248 | 851db83d | Luca Abeni | return NULL; |
249 | } |
||
250 | 025da5a8 | Luca Abeni | if ((s->streams & (1ULL << pkt.stream_index)) == 0) { |
251 | 851db83d | Luca Abeni | *size = 0;
|
252 | *ts = s->last_ts; |
||
253 | av_free_packet(&pkt); |
||
254 | |||
255 | return NULL; |
||
256 | } |
||
257 | if (s->bsf[pkt.stream_index]) {
|
||
258 | AVPacket new_pkt= pkt; |
||
259 | int res;
|
||
260 | |||
261 | res = av_bitstream_filter_filter(s->bsf[pkt.stream_index], |
||
262 | s->s->streams[pkt.stream_index]->codec, |
||
263 | NULL, &new_pkt.data, &new_pkt.size,
|
||
264 | pkt.data, pkt.size, pkt.flags & AV_PKT_FLAG_KEY); |
||
265 | if(res > 0){ |
||
266 | 1e8dedd8 | Luca Abeni | av_free_packet(&pkt); |
267 | 851db83d | Luca Abeni | new_pkt.destruct= av_destruct_packet; |
268 | } else if(res < 0){ |
||
269 | fprintf(stderr, "%s failed for stream %d, codec %s: ",
|
||
270 | s->bsf[pkt.stream_index]->filter->name, |
||
271 | pkt.stream_index, |
||
272 | s->s->streams[pkt.stream_index]->codec->codec->name); |
||
273 | fprintf(stderr, "%d\n", res);
|
||
274 | *size = 0;
|
||
275 | 1e8dedd8 | Luca Abeni | |
276 | return NULL; |
||
277 | } |
||
278 | 851db83d | Luca Abeni | pkt= new_pkt; |
279 | } |
||
280 | |||
281 | switch (s->s->streams[pkt.stream_index]->codec->codec_type) {
|
||
282 | case CODEC_TYPE_VIDEO:
|
||
283 | header_size = VIDEO_PAYLOAD_HEADER_SIZE; |
||
284 | break;
|
||
285 | 52f45fc1 | Luca Abeni | case CODEC_TYPE_AUDIO:
|
286 | header_size = AUDIO_PAYLOAD_HEADER_SIZE; |
||
287 | break;
|
||
288 | 851db83d | Luca Abeni | default:
|
289 | /* Cannot arrive here... */
|
||
290 | fprintf(stderr, "Internal chunkiser error!\n");
|
||
291 | exit(-1);
|
||
292 | } |
||
293 | *size = pkt.size + header_size + FRAME_HEADER_SIZE; |
||
294 | data = malloc(*size); |
||
295 | if (data == NULL) { |
||
296 | *size = -1;
|
||
297 | 1e8dedd8 | Luca Abeni | av_free_packet(&pkt); |
298 | |||
299 | 851db83d | Luca Abeni | return NULL; |
300 | } |
||
301 | switch (s->s->streams[pkt.stream_index]->codec->codec_type) {
|
||
302 | case CODEC_TYPE_VIDEO:
|
||
303 | video_header_fill(data, s->s->streams[pkt.stream_index]); |
||
304 | 7e44761d | Luca Abeni | new_tb.den = s->s->streams[pkt.stream_index]->avg_frame_rate.num; |
305 | new_tb.num = s->s->streams[pkt.stream_index]->avg_frame_rate.den; |
||
306 | 851db83d | Luca Abeni | if (new_tb.num == 0) { |
307 | 7e44761d | Luca Abeni | new_tb.den = s->s->streams[pkt.stream_index]->r_frame_rate.num; |
308 | new_tb.num = s->s->streams[pkt.stream_index]->r_frame_rate.den; |
||
309 | 851db83d | Luca Abeni | } |
310 | break;
|
||
311 | 52f45fc1 | Luca Abeni | case CODEC_TYPE_AUDIO:
|
312 | audio_header_fill(data, s->s->streams[pkt.stream_index]); |
||
313 | new_tb = (AVRational){s->s->streams[pkt.stream_index]->codec->frame_size, s->s->streams[pkt.stream_index]->codec->sample_rate}; |
||
314 | break;
|
||
315 | 851db83d | Luca Abeni | default:
|
316 | /* Cannot arrive here... */
|
||
317 | fprintf(stderr, "Internal chunkiser error!\n");
|
||
318 | exit(-1);
|
||
319 | } |
||
320 | data[header_size - 1] = 1; |
||
321 | frame_header_fill(data + header_size, *size - header_size - FRAME_HEADER_SIZE, &pkt, s->s->streams[pkt.stream_index], new_tb, s->base_ts); |
||
322 | |||
323 | memcpy(data + header_size + FRAME_HEADER_SIZE, pkt.data, pkt.size); |
||
324 | *ts = av_rescale_q(pkt.dts, s->s->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q); |
||
325 | //dprintf("pkt.dts=%ld TS1=%lu" , pkt.dts, *ts);
|
||
326 | *ts += s->base_ts; |
||
327 | //dprintf(" TS2=%lu\n",*ts);
|
||
328 | s->last_ts = *ts; |
||
329 | av_free_packet(&pkt); |
||
330 | |||
331 | return data;
|
||
332 | 1e8dedd8 | Luca Abeni | } |
333 | |||
334 | #if 0
|
||
335 | int chunk_read_avs1(void *s_h, struct chunk *c)
|
||
336 | {
|
||
337 | AVFormatContext *s = s_h;
|
||
338 | static AVPacket pkt;
|
||
339 | static int inited;
|
||
340 | AVStream *st;
|
||
341 | int res;
|
||
342 | int cnt;
|
||
343 | static uint8_t static_buff[STATIC_BUFF_SIZE];
|
||
344 | uint8_t *p, *pcurr;
|
||
345 | static uint8_t *p1;
|
||
346 | static struct chunk c2;
|
||
347 | int f1;
|
||
348 | static int f2;
|
||
349 | |||
350 | if (p1) {
|
||
351 | c2.id = c->id;
|
||
352 | *c = c2;
|
||
353 | p1 = NULL;
|
||
354 | |||
355 | return f2;
|
||
356 | }
|
||
357 | |||
358 | p = static_buff;
|
||
359 | p1 = static_buff + STATIC_BUFF_SIZE / 2;
|
||
360 | if (inited == 0) {
|
||
361 | inited = 1;
|
||
362 | res = av_read_frame(s, &pkt);
|
||
363 | if (res < 0) {
|
||
364 | fprintf(stderr, "First read failed: %d!!!\n", res);
|
||
365 | |||
366 | return 0;
|
||
367 | }
|
||
368 | if ((pkt.flags & PKT_FLAG_KEY) == 0) {
|
||
369 | fprintf(stderr, "First frame is not key frame!!!\n");
|
||
370 | |||
371 | return 0;
|
||
372 | }
|
||
373 | }
|
||
374 | cnt = 0; f1 = 0; f2 = 0;
|
||
375 | c->stride_size = 2;
|
||
376 | c2.stride_size = 2;
|
||
377 | pcurr = p1;
|
||
378 | if (pkt.size > 0) {
|
||
379 | memcpy(p, pkt.data, pkt.size);
|
||
380 | c->frame[0] = p;
|
||
381 | c->frame_len[0] = pkt.size;
|
||
382 | f1++;
|
||
383 | p += pkt.size;
|
||
384 | }
|
||
385 | while (1) {
|
||
386 | res = av_read_frame(s, &pkt);
|
||
387 | if (res >= 0) {
|
||
388 | st = s->streams[pkt.stream_index];
|
||
389 | if (pkt.flags & PKT_FLAG_KEY) {
|
||
390 | cnt++;
|
||
391 | if (cnt == 2) {
|
||
392 | return f1;
|
||
393 | }
|
||
394 | }
|
||
395 | memcpy(pcurr, pkt.data, pkt.size);
|
||
396 | if (pcurr == p) {
|
||
397 | c->frame[f1] = pcurr;
|
||
398 | c->frame_len[f1] = pkt.size;
|
||
399 | p += pkt.size;
|
||
400 | pcurr = p1;
|
||
401 | f1++;
|
||
402 | } else {
|
||
403 | c2.frame[f2] = pcurr;
|
||
404 | c2.frame_len[f2] = pkt.size;
|
||
405 | p1 += pkt.size;
|
||
406 | pcurr = p;
|
||
407 | f2++;
|
||
408 | }
|
||
409 | } else {
|
||
410 | pkt.size = 0;
|
||
411 | |||
412 | return f1;
|
||
413 | }
|
||
414 | }
|
||
415 | |||
416 | return 0;
|
||
417 | }
|
||
418 | #endif
|
||
419 | c0c735aa | Luca Abeni | |
420 | struct chunkiser_iface in_avf = {
|
||
421 | .open = avf_open, |
||
422 | .close = avf_close, |
||
423 | .chunkise = avf_chunkise, |
||
424 | }; |