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