grapes / src / Chunkiser / input-stream-avf.c @ fcc01ba5
History | View | Annotate | Download (9.26 KB)
1 |
/*
|
---|---|
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 |
#include "chunkiser_iface.h" |
14 |
|
15 |
#define STATIC_BUFF_SIZE 1000 * 1024 |
16 |
struct chunkiser_ctx {
|
17 |
AVFormatContext *s; |
18 |
int loop; //loop on input file infinitely |
19 |
int audio_stream;
|
20 |
int video_stream;
|
21 |
int64_t last_ts; |
22 |
int64_t base_ts; |
23 |
AVBitStreamFilterContext *bsf[MAX_STREAMS]; |
24 |
}; |
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 |
payload_header_write(data, codec_type(st->codec->codec_id), st->codec->width, st->codec->height, num, den); |
80 |
} |
81 |
|
82 |
static void frame_header_fill(uint8_t *data, int size, AVPacket *pkt, AVStream *st, int64_t base_ts) |
83 |
{ |
84 |
AVRational fps; |
85 |
int32_t pts, dts; |
86 |
|
87 |
fps = st->avg_frame_rate; |
88 |
if (fps.num == 0) { |
89 |
fps = st->r_frame_rate; |
90 |
} |
91 |
if (pkt->pts != AV_NOPTS_VALUE) {
|
92 |
pts = av_rescale_q(pkt->pts, st->time_base, (AVRational){fps.den, fps.num}), |
93 |
pts += av_rescale_q(base_ts, AV_TIME_BASE_Q, (AVRational){fps.den, fps.num}); |
94 |
} else {
|
95 |
pts = -1;
|
96 |
} |
97 |
//dprintf("pkt->pts=%ld PTS=%d",pkt->pts, pts);
|
98 |
if (pkt->dts != AV_NOPTS_VALUE) {
|
99 |
dts = av_rescale_q(pkt->dts, st->time_base, (AVRational){fps.den, fps.num}); |
100 |
dts += av_rescale_q(base_ts, AV_TIME_BASE_Q, (AVRational){fps.den, fps.num}); |
101 |
} else {
|
102 |
fprintf(stderr, "No DTS???\n");
|
103 |
dts = 0;
|
104 |
} |
105 |
//dprintf(" DTS=%d\n",dts);
|
106 |
frame_header_write(data, size, pts, dts); |
107 |
} |
108 |
|
109 |
static int input_stream_rewind(struct chunkiser_ctx *s) |
110 |
{ |
111 |
int ret;
|
112 |
|
113 |
ret = av_seek_frame(s->s,-1,0,0); |
114 |
s->base_ts = s->last_ts; |
115 |
|
116 |
return ret;
|
117 |
} |
118 |
|
119 |
|
120 |
/* Interface functions */
|
121 |
|
122 |
static struct chunkiser_ctx *avf_open(const char *fname, int *period, const char *config) |
123 |
{ |
124 |
struct chunkiser_ctx *desc;
|
125 |
int i, res;
|
126 |
struct tag *cfg_tags;
|
127 |
|
128 |
avcodec_register_all(); |
129 |
av_register_all(); |
130 |
|
131 |
desc = malloc(sizeof(struct chunkiser_ctx)); |
132 |
if (desc == NULL) { |
133 |
return NULL; |
134 |
} |
135 |
res = av_open_input_file(&desc->s, fname, NULL, 0, NULL); |
136 |
if (res < 0) { |
137 |
fprintf(stderr, "Error opening %s: %d\n", fname, res);
|
138 |
|
139 |
return NULL; |
140 |
} |
141 |
|
142 |
desc->s->flags |= AVFMT_FLAG_GENPTS; |
143 |
res = av_find_stream_info(desc->s); |
144 |
if (res < 0) { |
145 |
fprintf(stderr, "Cannot find codec parameters for %s\n", fname);
|
146 |
|
147 |
return NULL; |
148 |
} |
149 |
desc->video_stream = -1;
|
150 |
desc->audio_stream = -1;
|
151 |
desc->last_ts = 0;
|
152 |
desc->base_ts = 0;
|
153 |
desc->loop = 0;
|
154 |
cfg_tags = config_parse(config); |
155 |
if (cfg_tags) {
|
156 |
config_value_int(cfg_tags, "loop", &desc->loop);
|
157 |
} |
158 |
free(cfg_tags); |
159 |
for (i = 0; i < desc->s->nb_streams; i++) { |
160 |
if (desc->video_stream == -1 && desc->s->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) { |
161 |
desc->video_stream = i; |
162 |
fprintf(stderr, "Video Frame Rate = %d/%d --- Period: %lld\n",
|
163 |
desc->s->streams[i]->r_frame_rate.num, |
164 |
desc->s->streams[i]->r_frame_rate.den, |
165 |
av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num));
|
166 |
*period = av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num);
|
167 |
} |
168 |
if (desc->audio_stream == -1 && desc->s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) { |
169 |
desc->audio_stream = i; |
170 |
} |
171 |
if (desc->s->streams[i]->codec->codec_id == CODEC_ID_MPEG4) {
|
172 |
desc->bsf[i] = av_bitstream_filter_init("dump_extra");
|
173 |
} else if (desc->s->streams[i]->codec->codec_id == CODEC_ID_H264) { |
174 |
desc->bsf[i] = av_bitstream_filter_init("h264_mp4toannexb");
|
175 |
} else {
|
176 |
desc->bsf[i] = NULL;
|
177 |
} |
178 |
} |
179 |
|
180 |
dump_format(desc->s, 0, fname, 0); |
181 |
|
182 |
return desc;
|
183 |
} |
184 |
|
185 |
static void avf_close(struct chunkiser_ctx *s) |
186 |
{ |
187 |
int i;
|
188 |
|
189 |
for (i = 0; i < s->s->nb_streams; i++) { |
190 |
if (s->bsf[i]) {
|
191 |
av_bitstream_filter_close(s->bsf[i]); |
192 |
} |
193 |
} |
194 |
av_close_input_file(s->s); |
195 |
free(s); |
196 |
} |
197 |
|
198 |
static uint8_t *avf_chunkise(struct chunkiser_ctx *s, int id, int *size, uint64_t *ts) |
199 |
{ |
200 |
AVPacket pkt; |
201 |
int res;
|
202 |
uint8_t *data; |
203 |
int header_size;
|
204 |
|
205 |
res = av_read_frame(s->s, &pkt); |
206 |
if (res < 0) { |
207 |
if (s->loop) {
|
208 |
if (input_stream_rewind(s) >= 0) { |
209 |
*size = 0;
|
210 |
*ts = s->last_ts; |
211 |
|
212 |
return NULL; |
213 |
} |
214 |
} |
215 |
fprintf(stderr, "AVPacket read failed: %d!!!\n", res);
|
216 |
*size = -1;
|
217 |
|
218 |
return NULL; |
219 |
} |
220 |
if (pkt.stream_index != s->video_stream) {
|
221 |
*size = 0;
|
222 |
*ts = s->last_ts; |
223 |
av_free_packet(&pkt); |
224 |
|
225 |
return NULL; |
226 |
} |
227 |
if (s->bsf[pkt.stream_index]) {
|
228 |
AVPacket new_pkt= pkt; |
229 |
int res;
|
230 |
|
231 |
res = av_bitstream_filter_filter(s->bsf[pkt.stream_index], |
232 |
s->s->streams[pkt.stream_index]->codec, |
233 |
NULL, &new_pkt.data, &new_pkt.size,
|
234 |
pkt.data, pkt.size, pkt.flags & AV_PKT_FLAG_KEY); |
235 |
if(res > 0){ |
236 |
av_free_packet(&pkt); |
237 |
new_pkt.destruct= av_destruct_packet; |
238 |
} else if(res < 0){ |
239 |
fprintf(stderr, "%s failed for stream %d, codec %s: ",
|
240 |
s->bsf[pkt.stream_index]->filter->name, |
241 |
pkt.stream_index, |
242 |
s->s->streams[pkt.stream_index]->codec->codec->name); |
243 |
fprintf(stderr, "%d\n", res);
|
244 |
*size = 0;
|
245 |
|
246 |
return NULL; |
247 |
} |
248 |
pkt= new_pkt; |
249 |
} |
250 |
|
251 |
if (s->s->streams[pkt.stream_index]->codec->codec_type == CODEC_TYPE_VIDEO) {
|
252 |
header_size = VIDEO_PAYLOAD_HEADER_SIZE; |
253 |
} |
254 |
*size = pkt.size + header_size + FRAME_HEADER_SIZE; |
255 |
data = malloc(*size); |
256 |
if (data == NULL) { |
257 |
*size = -1;
|
258 |
av_free_packet(&pkt); |
259 |
|
260 |
return NULL; |
261 |
} |
262 |
if (s->s->streams[pkt.stream_index]->codec->codec_type == CODEC_TYPE_VIDEO) {
|
263 |
video_header_fill(data, s->s->streams[pkt.stream_index]); |
264 |
} |
265 |
data[VIDEO_PAYLOAD_HEADER_SIZE - 1] = 1; |
266 |
frame_header_fill(data + VIDEO_PAYLOAD_HEADER_SIZE, *size - header_size - FRAME_HEADER_SIZE, &pkt, s->s->streams[pkt.stream_index], s->base_ts); |
267 |
|
268 |
memcpy(data + header_size + FRAME_HEADER_SIZE, pkt.data, pkt.size); |
269 |
*ts = av_rescale_q(pkt.dts, s->s->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q); |
270 |
//dprintf("pkt.dts=%ld TS1=%lu" , pkt.dts, *ts);
|
271 |
*ts += s->base_ts; |
272 |
//dprintf(" TS2=%lu\n",*ts);
|
273 |
s->last_ts = *ts; |
274 |
av_free_packet(&pkt); |
275 |
|
276 |
return data;
|
277 |
} |
278 |
|
279 |
#if 0
|
280 |
int chunk_read_avs1(void *s_h, struct chunk *c)
|
281 |
{
|
282 |
AVFormatContext *s = s_h;
|
283 |
static AVPacket pkt;
|
284 |
static int inited;
|
285 |
AVStream *st;
|
286 |
int res;
|
287 |
int cnt;
|
288 |
static uint8_t static_buff[STATIC_BUFF_SIZE];
|
289 |
uint8_t *p, *pcurr;
|
290 |
static uint8_t *p1;
|
291 |
static struct chunk c2;
|
292 |
int f1;
|
293 |
static int f2;
|
294 |
|
295 |
if (p1) {
|
296 |
c2.id = c->id;
|
297 |
*c = c2;
|
298 |
p1 = NULL;
|
299 |
|
300 |
return f2;
|
301 |
}
|
302 |
|
303 |
p = static_buff;
|
304 |
p1 = static_buff + STATIC_BUFF_SIZE / 2;
|
305 |
if (inited == 0) {
|
306 |
inited = 1;
|
307 |
res = av_read_frame(s, &pkt);
|
308 |
if (res < 0) {
|
309 |
fprintf(stderr, "First read failed: %d!!!\n", res);
|
310 |
|
311 |
return 0;
|
312 |
}
|
313 |
if ((pkt.flags & PKT_FLAG_KEY) == 0) {
|
314 |
fprintf(stderr, "First frame is not key frame!!!\n");
|
315 |
|
316 |
return 0;
|
317 |
}
|
318 |
}
|
319 |
cnt = 0; f1 = 0; f2 = 0;
|
320 |
c->stride_size = 2;
|
321 |
c2.stride_size = 2;
|
322 |
pcurr = p1;
|
323 |
if (pkt.size > 0) {
|
324 |
memcpy(p, pkt.data, pkt.size);
|
325 |
c->frame[0] = p;
|
326 |
c->frame_len[0] = pkt.size;
|
327 |
f1++;
|
328 |
p += pkt.size;
|
329 |
}
|
330 |
while (1) {
|
331 |
res = av_read_frame(s, &pkt);
|
332 |
if (res >= 0) {
|
333 |
st = s->streams[pkt.stream_index];
|
334 |
if (pkt.flags & PKT_FLAG_KEY) {
|
335 |
cnt++;
|
336 |
if (cnt == 2) {
|
337 |
return f1;
|
338 |
}
|
339 |
}
|
340 |
memcpy(pcurr, pkt.data, pkt.size);
|
341 |
if (pcurr == p) {
|
342 |
c->frame[f1] = pcurr;
|
343 |
c->frame_len[f1] = pkt.size;
|
344 |
p += pkt.size;
|
345 |
pcurr = p1;
|
346 |
f1++;
|
347 |
} else {
|
348 |
c2.frame[f2] = pcurr;
|
349 |
c2.frame_len[f2] = pkt.size;
|
350 |
p1 += pkt.size;
|
351 |
pcurr = p;
|
352 |
f2++;
|
353 |
}
|
354 |
} else {
|
355 |
pkt.size = 0;
|
356 |
|
357 |
return f1;
|
358 |
}
|
359 |
}
|
360 |
|
361 |
return 0;
|
362 |
}
|
363 |
#endif
|
364 |
|
365 |
struct chunkiser_iface in_avf = {
|
366 |
.open = avf_open, |
367 |
.close = avf_close, |
368 |
.chunkise = avf_chunkise, |
369 |
}; |