Statistics
| Branch: | Revision:

grapes / src / Chunkiser / input-stream-avf.c @ 176b8de8

History | View | Annotate | Download (12.7 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
#include <string.h>
10

    
11
//#include "dbg.h"
12
#include "libav-compat.h"
13
#include "int_coding.h"
14
#include "payload.h"
15
#include "grapes_config.h"
16
#include "ffmpeg_compat.h"
17
#include "chunkiser_iface.h"
18

    
19
#define STATIC_BUFF_SIZE 1000 * 1024
20
#define VFRAMES_DEFAULT 1
21
#define AFRAMES_DEFAULT 1
22
struct chunkiser_ctx {
23
  AVFormatContext *s;
24
  int loop;        //loop on input file infinitely
25
  uint64_t streams;
26
  int64_t last_ts;
27
  int64_t base_ts;
28
  AVBitStreamFilterContext *bsf[MAX_STREAMS];
29
  int v_frames_max;
30
  int v_frames;
31
  uint8_t *v_data;
32
  int v_size;
33
  int a_frames_max;
34
  int a_frames;
35
  uint8_t *a_data;
36
  int a_size;
37
};
38

    
39
static uint8_t codec_type(enum CodecID cid)
40
{
41
  switch (cid) {
42
    case CODEC_ID_MPEG1VIDEO:
43
    case CODEC_ID_MPEG2VIDEO:
44
      return 1;
45
    case CODEC_ID_H261:
46
      return 2;
47
    case CODEC_ID_H263P:
48
    case CODEC_ID_H263:
49
      return 3;
50
    case CODEC_ID_MJPEG:
51
      return 4;
52
    case CODEC_ID_MPEG4:
53
      return 5;
54
    case CODEC_ID_FLV1:
55
      return 6;
56
    case CODEC_ID_SVQ3:
57
      return 7;
58
    case CODEC_ID_DVVIDEO:
59
      return 8;
60
    case CODEC_ID_H264:
61
      return 9;
62
    case CODEC_ID_THEORA:
63
    case CODEC_ID_VP3:
64
      return 10;
65
    case CODEC_ID_SNOW:
66
      return 11;
67
    case CODEC_ID_VP6:
68
      return 12;
69
    case CODEC_ID_DIRAC:
70
      return 13;
71
    case CODEC_ID_MP2:
72
    case CODEC_ID_MP3:
73
      return 129;
74
    case CODEC_ID_AAC:
75
      return 130;
76
    case CODEC_ID_AC3:
77
      return 131;
78
    case CODEC_ID_VORBIS:
79
      return 132;
80
    default:
81
      fprintf(stderr, "Unknown codec ID %d\n", cid);
82
      return 0;
83
  }
84
}
85

    
86
static void audio_header_fill(uint8_t *data, AVStream *st)
87
{
88
  audio_payload_header_write(data, codec_type(st->codec->codec_id), st->codec->channels, st->codec->sample_rate, st->codec->frame_size);
89
}
90

    
91
static void video_header_fill(uint8_t *data, AVStream *st)
92
{
93
  int num, den;
94

    
95
  num = st->avg_frame_rate.num;
96
  den = st->avg_frame_rate.den;
97
//fprintf(stderr, "Rate: %d/%d\n", num, den);
98
  if (num == 0) {
99
    num = st->r_frame_rate.num;
100
    den = st->r_frame_rate.den;
101
  }
102
  if (num > (1 << 16)) {
103
    num /= 1000;
104
    den /= 1000;
105
  }
106
  video_payload_header_write(data, codec_type(st->codec->codec_id), st->codec->width, st->codec->height, num, den);
107
}
108

    
109
static void frame_header_fill(uint8_t *data, int size, AVPacket *pkt, AVStream *st, AVRational new_tb, int64_t base_ts)
110
{
111
  int32_t pts, dts;
112

    
113
  if (pkt->pts != AV_NOPTS_VALUE) {
114
    pts = av_rescale_q(pkt->pts, st->time_base, new_tb),
115
    pts += av_rescale_q(base_ts, AV_TIME_BASE_Q, new_tb);
116
  } else {
117
    pts = -1;
118
  }
119
  //dprintf("pkt->pts=%ld PTS=%d",pkt->pts, pts);
120
  if (pkt->dts != AV_NOPTS_VALUE) {
121
    dts = av_rescale_q(pkt->dts, st->time_base, new_tb);
122
    dts += av_rescale_q(base_ts, AV_TIME_BASE_Q, new_tb);
123
  } else {
124
    fprintf(stderr, "No DTS???\n");
125
    dts = 0;
126
  }
127
  //dprintf(" DTS=%d\n",dts);
128
  frame_header_write(data, size, pts, dts);
129
}
130

    
131
static int input_stream_rewind(struct chunkiser_ctx *s)
132
{
133
  int ret;
134

    
135
  ret = av_seek_frame(s->s,-1,0,0);
136
  s->base_ts = s->last_ts;
137

    
138
  return ret;
139
}
140

    
141

    
142
/* Interface functions */
143

    
144
static struct chunkiser_ctx *avf_open(const char *fname, int *period, const char *config)
145
{
146
  struct chunkiser_ctx *desc;
147
  int i, res;
148
  struct tag *cfg_tags;
149
  int video_streams = 0, audio_streams = 0;
150

    
151
  avcodec_register_all();
152
  av_register_all();
153

    
154
  desc = malloc(sizeof(struct chunkiser_ctx));
155
  if (desc == NULL) {
156
    return NULL;
157
  }
158
  res = av_open_input_file(&desc->s, fname, NULL, 0, NULL);
159
  if (res < 0) {
160
    fprintf(stderr, "Error opening %s: %d\n", fname, res);
161

    
162
    return NULL;
163
  }
164

    
165
  desc->s->flags |= AVFMT_FLAG_GENPTS;
166
  res = av_find_stream_info(desc->s);
167
  if (res < 0) {
168
    fprintf(stderr, "Cannot find codec parameters for %s\n", fname);
169

    
170
    return NULL;
171
  }
172
  desc->streams = 0;
173
  desc->last_ts = 0;
174
  desc->base_ts = 0;
175
  desc->loop = 0;
176
  //initialize buffers
177
  desc->v_frames_max = VFRAMES_DEFAULT;
178
  desc->v_frames = 0;
179
  desc->v_data = NULL;
180
  desc->v_size = 0;
181
  desc->a_frames_max = AFRAMES_DEFAULT;
182
  desc->a_frames = 0;
183
  desc->a_data = NULL;
184
  desc->a_size = 0;
185
  cfg_tags = grapes_config_parse(config);
186
  if (cfg_tags) {
187
    const char *media;
188

    
189
    grapes_config_value_int(cfg_tags, "loop", &desc->loop);
190
    media = grapes_config_value_str(cfg_tags, "media");
191
    if (media) {
192
      if (!strcmp(media, "audio")) {
193
        audio_streams = 0;
194
        video_streams = 1;
195
      } else if (!strcmp(media, "video")) {
196
        audio_streams = 1;
197
        video_streams = 0;
198
      } else if (!strcmp(media, "av")) {
199
        audio_streams = 0;
200
        video_streams = 0;
201
      }
202
    }
203
    grapes_config_value_int(cfg_tags, "vframes", &desc->v_frames_max);
204
    grapes_config_value_int(cfg_tags, "aframes", &desc->a_frames_max);
205
  }
206
  free(cfg_tags);
207
  for (i = 0; i < desc->s->nb_streams; i++) {
208
    if (desc->s->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
209
      if (video_streams++ == 0) {
210
        desc->streams |= 1ULL << i;
211
      }
212
      fprintf(stderr, "Video Frame Rate = %d/%d --- Period: %lld\n",
213
              desc->s->streams[i]->r_frame_rate.num,
214
              desc->s->streams[i]->r_frame_rate.den,
215
              av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num));
216
      *period = av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num);
217
    }
218
    if (desc->s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
219
      if (audio_streams++ == 0) {
220
        desc->streams |= 1ULL << i;
221
      }
222
    }
223
    if (desc->s->streams[i]->codec->codec_id == CODEC_ID_MPEG4) {
224
      desc->bsf[i] = av_bitstream_filter_init("dump_extra");
225
    } else if (desc->s->streams[i]->codec->codec_id == CODEC_ID_H264) {
226
      desc->bsf[i] = av_bitstream_filter_init("h264_mp4toannexb");
227
    } else {
228
      desc->bsf[i] = NULL;
229
    }
230
  }
231

    
232
  dump_format(desc->s, 0, fname, 0);
233

    
234

    
235
  return desc;
236
}
237

    
238
static void avf_close(struct chunkiser_ctx *s)
239
{
240
  int i;
241

    
242
  for (i = 0; i < s->s->nb_streams; i++) {
243
    if (s->bsf[i]) {
244
      av_bitstream_filter_close(s->bsf[i]);
245
    }
246
  }
247
  av_close_input_file(s->s);
248

    
249
  //free buffers
250
  free(s->v_data);
251
  free(s->a_data);
252

    
253
  free(s);
254
}
255

    
256
static AVRational get_new_tb(AVStream *stream)
257
{
258
  AVRational new_tb;
259

    
260
  switch (stream->codec->codec_type) {
261
    case CODEC_TYPE_VIDEO:
262
      new_tb.den = stream->avg_frame_rate.num;
263
      new_tb.num = stream->avg_frame_rate.den;
264
      if (new_tb.num == 0) {
265
        new_tb.den = stream->r_frame_rate.num;
266
        new_tb.num = stream->r_frame_rate.den;
267
      }
268
      break;
269
    case CODEC_TYPE_AUDIO:
270
      new_tb = (AVRational){stream->codec->frame_size, stream->codec->sample_rate};
271
      break;
272
    default:
273
      /* Cannot arrive here... */
274
      fprintf(stderr, "Internal chunkiser error!\n");
275
      exit(-1);
276
  }
277

    
278
  return new_tb;
279
}
280

    
281
static void header_fill(uint8_t *data, AVStream *stream)
282
{
283
  switch (stream->codec->codec_type) {
284
    case CODEC_TYPE_VIDEO:
285
      video_header_fill(data, stream);
286
      break;
287
    case CODEC_TYPE_AUDIO:
288
      audio_header_fill(data, stream);
289
      break;
290
    default:
291
      /* Cannot arrive here... */
292
      fprintf(stderr, "Internal chunkiser error!\n");
293
      exit(-1);
294
  }
295
}
296

    
297
static int get_header_size(AVStream *stream)
298
{
299
  switch (stream->codec->codec_type) {
300
    case CODEC_TYPE_VIDEO:
301
      return VIDEO_PAYLOAD_HEADER_SIZE;
302
      break;
303
    case CODEC_TYPE_AUDIO:
304
      return AUDIO_PAYLOAD_HEADER_SIZE;
305
      break;
306
    default:
307
      /* Cannot arrive here... */
308
      fprintf(stderr, "Internal chunkiser error!\n");
309
      exit(-1);
310
  }
311

    
312
  return -1;
313
}
314

    
315
static uint8_t *avf_chunkise(struct chunkiser_ctx *s, int id, int *size, uint64_t *ts)
316
{
317
  AVPacket pkt;
318
  AVRational new_tb;
319
  int res;
320
  uint8_t **data;
321
  int header_size;
322
  int *frames;
323
  int *chunksize;
324
  int frames_max;
325
  uint8_t *frame_pos;
326
  uint8_t *ret;
327

    
328
  res = av_read_frame(s->s, &pkt);
329
  if (res < 0) {
330
    if (s->loop) {
331
      if (input_stream_rewind(s) >= 0) {
332
        *size = 0;
333
        *ts = s->last_ts;
334

    
335
        return NULL;
336
      }
337
    }
338
    fprintf(stderr, "AVPacket read failed: %d!!!\n", res);
339
    *size = -1;
340

    
341
    return NULL;
342
  }
343
  if ((s->streams & (1ULL << pkt.stream_index)) == 0) {
344
    *size = 0;
345
    *ts = s->last_ts;
346
    av_free_packet(&pkt);
347

    
348
    return NULL;
349
  }
350
  if (s->bsf[pkt.stream_index]) {
351
    AVPacket new_pkt= pkt;
352
    int res;
353

    
354
    res = av_bitstream_filter_filter(s->bsf[pkt.stream_index],
355
                                     s->s->streams[pkt.stream_index]->codec,
356
                                     NULL, &new_pkt.data, &new_pkt.size,
357
                                     pkt.data, pkt.size, pkt.flags & AV_PKT_FLAG_KEY);
358
    if(res > 0){
359
      av_free_packet(&pkt);
360
      new_pkt.destruct= av_destruct_packet;
361
    } else if(res < 0){
362
      fprintf(stderr, "%s failed for stream %d, codec %d: ",
363
                      s->bsf[pkt.stream_index]->filter->name,
364
                      pkt.stream_index,
365
                      s->s->streams[pkt.stream_index]->codec->codec_id);
366
      fprintf(stderr, "%d\n", res);
367
      *size = 0;
368

    
369
      return NULL;
370
    }
371
    pkt= new_pkt;
372
  }
373

    
374
  switch (s->s->streams[pkt.stream_index]->codec->codec_type) {
375
    case CODEC_TYPE_VIDEO:
376
      frames = &s->v_frames;
377
      data = &s->v_data;
378
      chunksize = &s->v_size;
379
      frames_max = s->v_frames_max;
380
      break;
381
    case CODEC_TYPE_AUDIO:
382
      frames = &s->a_frames;
383
      data = &s->a_data;
384
      chunksize = &s->a_size;
385
      frames_max = s->a_frames_max;
386
      break;
387
    default:
388
      /* Cannot arrive here... */
389
      fprintf(stderr, "Internal chunkiser error!\n");
390
      exit(-1);
391
  }
392

    
393
  header_size = get_header_size(s->s->streams[pkt.stream_index]);
394
  if (!*frames) {
395
    *chunksize = pkt.size + header_size + FRAME_HEADER_SIZE;
396
    *data = malloc(*chunksize);
397
    // we will fill the header at the end
398
  } else {
399
    *chunksize += pkt.size + FRAME_HEADER_SIZE;
400
    *data = realloc(*data, *chunksize);
401
  }
402

    
403
  if (*data == NULL) {
404
    *size = -1;
405
    av_free_packet(&pkt);
406

    
407
    return NULL;
408
  }
409

    
410
  new_tb = get_new_tb(s->s->streams[pkt.stream_index]);
411
  frame_pos = *data + *chunksize - pkt.size - FRAME_HEADER_SIZE;
412
  frame_header_fill(frame_pos, pkt.size, &pkt, s->s->streams[pkt.stream_index], new_tb, s->base_ts);
413
  memcpy(frame_pos + FRAME_HEADER_SIZE, pkt.data, pkt.size);
414
  (*frames)++;
415

    
416
  *ts = av_rescale_q(pkt.dts, s->s->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
417
  //dprintf("pkt.dts=%ld TS1=%lu" , pkt.dts, *ts);
418
  *ts += s->base_ts;
419
  //dprintf(" TS2=%lu\n",*ts);
420
  s->last_ts = *ts;
421
  av_free_packet(&pkt);
422

    
423
  if (*frames == frames_max) {
424
    header_fill(*data, s->s->streams[pkt.stream_index]);
425
    (*data)[header_size - 1] = *frames;
426
    ret = *data;
427
    *size = *chunksize;
428
    *frames = 0;
429
    *data = NULL;
430
    *chunksize = 0;
431
  } else {
432
    *size = 0;
433
    ret = NULL;
434
  }
435

    
436
  return ret;
437
}
438

    
439
#if 0
440
int chunk_read_avs1(void *s_h, struct chunk *c)
441
{
442
    AVFormatContext *s = s_h;
443
    static AVPacket pkt;
444
    static int inited;
445
    AVStream *st;
446
    int res;
447
    int cnt;
448
    static uint8_t static_buff[STATIC_BUFF_SIZE];
449
    uint8_t *p, *pcurr;
450
    static uint8_t *p1;
451
    static struct chunk c2;
452
    int f1;
453
    static int f2;
454

455
    if (p1) {
456
        c2.id = c->id;
457
        *c = c2;
458
        p1 = NULL;
459

460
        return f2;
461
    }
462

463
    p = static_buff;
464
    p1 = static_buff + STATIC_BUFF_SIZE / 2;
465
    if (inited == 0) {
466
        inited = 1;
467
        res = av_read_frame(s, &pkt);
468
        if (res < 0) {
469
            fprintf(stderr, "First read failed: %d!!!\n", res);
470

471
            return 0;
472
        }
473
        if ((pkt.flags & PKT_FLAG_KEY) == 0) {
474
            fprintf(stderr, "First frame is not key frame!!!\n");
475

476
            return 0;
477
        }
478
    }
479
    cnt = 0; f1 = 0; f2 = 0;
480
    c->stride_size = 2;
481
    c2.stride_size = 2;
482
    pcurr = p1;
483
    if (pkt.size > 0) {
484
        memcpy(p, pkt.data, pkt.size);
485
        c->frame[0] = p;
486
        c->frame_len[0] = pkt.size;
487
        f1++;
488
        p += pkt.size;
489
    }
490
    while (1) {
491
        res = av_read_frame(s, &pkt);
492
        if (res >= 0) {
493
            st = s->streams[pkt.stream_index];
494
            if (pkt.flags & PKT_FLAG_KEY) {
495
                cnt++;
496
                if (cnt == 2) {
497
                    return f1;
498
                }
499
            }
500
            memcpy(pcurr, pkt.data, pkt.size);
501
            if (pcurr == p) {
502
                c->frame[f1] = pcurr;
503
                c->frame_len[f1] = pkt.size;
504
                p += pkt.size;
505
                pcurr = p1;
506
                f1++;
507
            } else {
508
                c2.frame[f2] = pcurr;
509
                c2.frame_len[f2] = pkt.size;
510
                p1 += pkt.size;
511
                pcurr = p;
512
                f2++;
513
            }
514
        } else {
515
            pkt.size = 0;
516

517
            return f1;
518
        }
519
    }
520

521
    return 0;
522
}
523
#endif
524

    
525
struct chunkiser_iface in_avf = {
526
  .open = avf_open,
527
  .close = avf_close,
528
  .chunkise = avf_chunkise,
529
};