Statistics
| Branch: | Revision:

grapes / src / Chunkiser / input-stream-ipb.c @ 734f6960

History | View | Annotate | Download (11.4 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 "int_coding.h"
13
#include "payload.h"
14
#include "config.h"
15
#include "chunkiser_iface.h"
16

    
17
#define STATIC_BUFF_SIZE 1000 * 1024
18

    
19
struct log_info {
20
  int i_frames[16];
21
  int p_frames[16];
22
  int b_frames[16];
23
  int frame_number;
24
  FILE *log;
25
};
26

    
27
struct chunkiser_ctx {
28
  AVFormatContext *s;
29
  int loop;        //loop on input file infinitely
30
  uint64_t streams;
31
  int64_t last_ts;
32
  int64_t base_ts;
33
  uint8_t *i_chunk;
34
  uint8_t *p_chunk;
35
  uint8_t *b_chunk;
36
  int i_chunk_size;
37
  int p_chunk_size;
38
  int b_chunk_size;
39
  int p_ready;
40
  int b_ready;
41
  AVBitStreamFilterContext *bsf[MAX_STREAMS];
42

    
43
  struct log_info chunk_log;
44
};
45

    
46
static void chunk_print(FILE *log, int id, int *frames)
47
{
48
  int i = 0;
49

    
50
  fprintf(log, "Chunk %d:", id);
51
  while (frames[i] != -1) {
52
    fprintf(log, " %d", frames[i++]);
53
  }
54
  fprintf(log, "\n");
55
  frames[0] = -1;
56
}
57

    
58
static void frame_add(int *frames, int frame_id)
59
{
60
  int i = 0;
61

    
62
  while (frames[i] != -1) i++;
63
  frames[i] = frame_id;
64
  frames[i + 1] = -1;
65
}
66

    
67
static int frame_type(AVPacket *pkt)
68
{
69
  if ((pkt->dts == AV_NOPTS_VALUE) || (pkt->pts == AV_NOPTS_VALUE)) {
70
    return -1;
71
  }
72
  
73
  if (pkt->flags & PKT_FLAG_KEY) {
74
    return FF_I_TYPE;
75
  }
76
  if (pkt->dts == pkt->pts) {
77
    return FF_B_TYPE;
78
  }
79

    
80
  return FF_P_TYPE;
81
}
82

    
83
static uint8_t codec_type(enum CodecID cid)
84
{
85
  switch (cid) {
86
    case CODEC_ID_MPEG1VIDEO:
87
    case CODEC_ID_MPEG2VIDEO:
88
      return 1;
89
    case CODEC_ID_H261:
90
      return 2;
91
    case CODEC_ID_H263P:
92
    case CODEC_ID_H263:
93
      return 3;
94
    case CODEC_ID_MJPEG:
95
      return 4;
96
    case CODEC_ID_MPEG4:
97
      return 5;
98
    case CODEC_ID_FLV1:
99
      return 6;
100
    case CODEC_ID_SVQ3:
101
      return 7;
102
    case CODEC_ID_DVVIDEO:
103
      return 8;
104
    case CODEC_ID_H264:
105
      return 9;
106
    case CODEC_ID_THEORA:
107
    case CODEC_ID_VP3:
108
      return 10;
109
    case CODEC_ID_SNOW:
110
      return 11;
111
    case CODEC_ID_VP6:
112
      return 12;
113
    case CODEC_ID_DIRAC:
114
      return 13;
115
    case CODEC_ID_MP2:
116
    case CODEC_ID_MP3:
117
      return 129;
118
    case CODEC_ID_AAC:
119
      return 130;
120
    case CODEC_ID_AC3:
121
      return 131;
122
    case CODEC_ID_VORBIS:
123
      return 132;
124
    default:
125
      fprintf(stderr, "Unknown codec ID %d\n", cid);
126
      return 0;
127
  }
128
}
129

    
130
static void video_header_fill(uint8_t *data, AVStream *st)
131
{
132
  int num, den;
133

    
134
  num = st->avg_frame_rate.num;
135
  den = st->avg_frame_rate.den;
136
//fprintf(stderr, "Rate: %d/%d\n", num, den);
137
  if (num == 0) {
138
    num = st->r_frame_rate.num;
139
    den = st->r_frame_rate.den;
140
  }
141
  if (num > (1 << 16)) {
142
    num /= 1000;
143
    den /= 1000;
144
  }
145
  video_payload_header_write(data, codec_type(st->codec->codec_id), st->codec->width, st->codec->height, num, den);
146
  data[VIDEO_PAYLOAD_HEADER_SIZE - 1] = 0;
147
}
148

    
149
static void frame_header_fill(uint8_t *data, int size, AVPacket *pkt, AVStream *st, AVRational new_tb, int64_t base_ts)
150
{
151
  int32_t pts, dts;
152

    
153
  if (pkt->pts != AV_NOPTS_VALUE) {
154
    pts = av_rescale_q(pkt->pts, st->time_base, new_tb),
155
    pts += av_rescale_q(base_ts, AV_TIME_BASE_Q, new_tb);
156
  } else {
157
    pts = -1;
158
  }
159
  //dprintf("pkt->pts=%ld PTS=%d",pkt->pts, pts);
160
  if (pkt->dts != AV_NOPTS_VALUE) {
161
    dts = av_rescale_q(pkt->dts, st->time_base, new_tb);
162
    dts += av_rescale_q(base_ts, AV_TIME_BASE_Q, new_tb);
163
  } else {
164
    fprintf(stderr, "No DTS???\n");
165
    dts = 0;
166
  }
167
  //dprintf(" DTS=%d\n",dts);
168
  frame_header_write(data, size, pts, dts);
169
}
170

    
171
static int input_stream_rewind(struct chunkiser_ctx *s)
172
{
173
  int ret;
174

    
175
  ret = av_seek_frame(s->s,-1,0,0);
176
  s->base_ts = s->last_ts;
177

    
178
  return ret;
179
}
180

    
181

    
182
/* Interface functions */
183

    
184
static struct chunkiser_ctx *ipb_open(const char *fname, int *period, const char *config)
185
{
186
  struct chunkiser_ctx *desc;
187
  int i, res;
188
  struct tag *cfg_tags;
189
  int video_streams = 0, audio_streams = 1;
190

    
191
  avcodec_register_all();
192
  av_register_all();
193

    
194
  desc = malloc(sizeof(struct chunkiser_ctx));
195
  if (desc == NULL) {
196
    return NULL;
197
  }
198
  res = av_open_input_file(&desc->s, fname, NULL, 0, NULL);
199
  if (res < 0) {
200
    fprintf(stderr, "Error opening %s: %d\n", fname, res);
201

    
202
    return NULL;
203
  }
204

    
205
  desc->s->flags |= AVFMT_FLAG_GENPTS;
206
  res = av_find_stream_info(desc->s);
207
  if (res < 0) {
208
    fprintf(stderr, "Cannot find codec parameters for %s\n", fname);
209

    
210
    return NULL;
211
  }
212
  desc->streams = 0;
213
  desc->last_ts = 0;
214
  desc->base_ts = 0;
215
  desc->loop = 0;
216
  desc->i_chunk = NULL;
217
  desc->i_chunk_size = 0;
218
  desc->p_chunk = NULL;
219
  desc->p_chunk_size = 0;
220
  desc->b_chunk = NULL;
221
  desc->b_chunk_size = 0;
222
  desc->p_ready = 0;
223
  desc->b_ready = 0;
224
  desc->chunk_log.i_frames[0] = -1;
225
  desc->chunk_log.p_frames[0] = -1;
226
  desc->chunk_log.b_frames[0] = -1;
227
  desc->chunk_log.frame_number = 0;
228
  desc->chunk_log.log = fopen("chunk_log.txt", "w");
229
  cfg_tags = config_parse(config);
230
  if (cfg_tags) {
231
    const char *media;
232

    
233
    config_value_int(cfg_tags, "loop", &desc->loop);
234
    media = config_value_str(cfg_tags, "media");
235
    if (media) {
236
      if (!strcmp(media, "audio")) {
237
        audio_streams = 0;
238
        video_streams = 1;
239
      } else if (!strcmp(media, "video")) {
240
        audio_streams = 1;
241
        video_streams = 0;
242
      } else if (!strcmp(media, "av")) {
243
        audio_streams = 0;
244
        video_streams = 0;
245
      }
246
    }
247
  }
248
  free(cfg_tags);
249
  for (i = 0; i < desc->s->nb_streams; i++) {
250
    if (desc->s->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
251
      if (video_streams++ == 0) {
252
        desc->streams |= 1ULL << i;
253
      }
254
      fprintf(stderr, "Video Frame Rate = %d/%d --- Period: %"PRIu64"\n",
255
              desc->s->streams[i]->r_frame_rate.num,
256
              desc->s->streams[i]->r_frame_rate.den,
257
              av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num));
258
      *period = av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num);
259
    }
260
    if (desc->s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
261
      if (audio_streams++ == 0) {
262
        desc->streams |= 1ULL << i;
263
      }
264
    }
265
    if (desc->s->streams[i]->codec->codec_id == CODEC_ID_MPEG4) {
266
      desc->bsf[i] = av_bitstream_filter_init("dump_extra");
267
    } else if (desc->s->streams[i]->codec->codec_id == CODEC_ID_H264) {
268
      desc->bsf[i] = av_bitstream_filter_init("h264_mp4toannexb");
269
    } else {
270
      desc->bsf[i] = NULL;
271
    }
272
  }
273

    
274
  dump_format(desc->s, 0, fname, 0);
275

    
276
  return desc;
277
}
278

    
279
static void ipb_close(struct chunkiser_ctx *s)
280
{
281
  int i;
282

    
283
  for (i = 0; i < s->s->nb_streams; i++) {
284
    if (s->bsf[i]) {
285
      av_bitstream_filter_close(s->bsf[i]);
286
    }
287
  }
288
  av_close_input_file(s->s);
289
  free(s->i_chunk);
290
  free(s->p_chunk);
291
  free(s->b_chunk);
292
  fclose(s->chunk_log.log);
293
  free(s);
294
}
295

    
296
static uint8_t *ipb_chunkise(struct chunkiser_ctx *s, int id, int *size, uint64_t *ts)
297
{
298
  AVPacket pkt;
299
  AVRational new_tb;
300
  int res;
301
  uint8_t *data, *result;
302

    
303
  res = av_read_frame(s->s, &pkt);
304
  if (res < 0) {
305
    if (s->loop) {
306
      if (input_stream_rewind(s) >= 0) {
307
        *size = 0;
308
        *ts = s->last_ts;
309

    
310
        return NULL;
311
      }
312
    }
313
    fprintf(stderr, "AVPacket read failed: %d!!!\n", res);
314
    *size = -1;
315

    
316
    return NULL;
317
  }
318
  if ((s->streams & (1ULL << pkt.stream_index)) == 0) {
319
    *size = 0;
320
    *ts = s->last_ts;
321
    av_free_packet(&pkt);
322

    
323
    return NULL;
324
  }
325
  if (frame_type(&pkt) < 0) {
326
    fprintf(stderr, "Strange frame type!!!\n");
327
    *size = 0;
328
    *ts = s->last_ts;
329
    av_free_packet(&pkt);
330

    
331
    return NULL;
332
  }
333
  s->chunk_log.frame_number++;
334
  if (s->bsf[pkt.stream_index]) {
335
    AVPacket new_pkt= pkt;
336
    int res;
337

    
338
    res = av_bitstream_filter_filter(s->bsf[pkt.stream_index],
339
                                     s->s->streams[pkt.stream_index]->codec,
340
                                     NULL, &new_pkt.data, &new_pkt.size,
341
                                     pkt.data, pkt.size, pkt.flags & AV_PKT_FLAG_KEY);
342
    if(res > 0){
343
      av_free_packet(&pkt);
344
      new_pkt.destruct= av_destruct_packet;
345
      new_pkt.flags = pkt.flags;
346
    } else if(res < 0){
347
      fprintf(stderr, "%s failed for stream %d, codec %s: ",
348
                      s->bsf[pkt.stream_index]->filter->name,
349
                      pkt.stream_index,
350
                      s->s->streams[pkt.stream_index]->codec->codec->name);
351
      fprintf(stderr, "%d\n", res);
352
      *size = 0;
353

    
354
      return NULL;
355
    }
356
    pkt= new_pkt;
357
  }
358

    
359
  *size = 0;
360
  result = NULL; 
361
  switch(frame_type(&pkt)) {
362
    case FF_I_TYPE:
363
      fprintf(stderr, "I Frame!\n");
364
      result = s->i_chunk;
365
      *size = s->i_chunk_size;
366
      if (*size) chunk_print(s->chunk_log.log, id, s->chunk_log.i_frames);
367
      s->i_chunk = NULL;
368
      s->p_ready = 1;
369
      s->b_ready = 1;
370
      if (s->i_chunk == NULL) {
371

    
372
        s->i_chunk = malloc(VIDEO_PAYLOAD_HEADER_SIZE);
373
        s->i_chunk_size = VIDEO_PAYLOAD_HEADER_SIZE;
374
        video_header_fill(s->i_chunk, s->s->streams[pkt.stream_index]);
375
      }
376
      frame_add(s->chunk_log.i_frames, s->chunk_log.frame_number);
377
      s->i_chunk_size += pkt.size + FRAME_HEADER_SIZE;
378
      s->i_chunk = realloc(s->i_chunk, s->i_chunk_size);
379
      data = s->i_chunk + (s->i_chunk_size - (pkt.size + FRAME_HEADER_SIZE));
380
      break;
381
    case FF_P_TYPE:
382
      fprintf(stderr, "P Frame!\n");
383
      if (s->p_ready) {
384
        result = s->p_chunk;
385
        *size = s->p_chunk_size;
386
        s->p_chunk = NULL;
387
        s->p_ready = 0;
388
        if (*size) chunk_print(s->chunk_log.log, id, s->chunk_log.p_frames);
389
      }
390
      if (s->p_chunk == NULL) {
391
        s->p_chunk = malloc(VIDEO_PAYLOAD_HEADER_SIZE);
392
        s->p_chunk_size = VIDEO_PAYLOAD_HEADER_SIZE;
393
        video_header_fill(s->p_chunk, s->s->streams[pkt.stream_index]);
394
      }
395
      frame_add(s->chunk_log.p_frames, s->chunk_log.frame_number);
396
      s->p_chunk_size += pkt.size + FRAME_HEADER_SIZE;
397
      s->p_chunk = realloc(s->p_chunk, s->p_chunk_size);
398
      data = s->p_chunk + (s->p_chunk_size - (pkt.size + FRAME_HEADER_SIZE));
399
      break;
400
    case FF_B_TYPE:
401
      fprintf(stderr, "B Frame!\n");
402
      if (s->b_ready) {
403
        result = s->b_chunk;
404
        *size = s->b_chunk_size;
405
        s->b_chunk = NULL;
406
        s->b_ready = 0;
407
        if (*size) chunk_print(s->chunk_log.log, id, s->chunk_log.b_frames);
408
      }
409
      if (s->b_chunk == NULL) {
410
        s->b_chunk = malloc(VIDEO_PAYLOAD_HEADER_SIZE);
411
        s->b_chunk_size = VIDEO_PAYLOAD_HEADER_SIZE;
412
        video_header_fill(s->b_chunk, s->s->streams[pkt.stream_index]);
413
      }
414
      frame_add(s->chunk_log.b_frames, s->chunk_log.frame_number);
415
      s->b_chunk_size += pkt.size + FRAME_HEADER_SIZE;
416
      s->b_chunk = realloc(s->b_chunk, s->b_chunk_size);
417
      data = s->b_chunk + (s->b_chunk_size - (pkt.size + FRAME_HEADER_SIZE));
418
      break;
419
  }
420

    
421
  new_tb.den = s->s->streams[pkt.stream_index]->avg_frame_rate.num;
422
  new_tb.num = s->s->streams[pkt.stream_index]->avg_frame_rate.den;
423
  if (new_tb.num == 0) {
424
    new_tb.den = s->s->streams[pkt.stream_index]->r_frame_rate.num;
425
    new_tb.num = s->s->streams[pkt.stream_index]->r_frame_rate.den;
426
  }
427
  frame_header_fill(data, pkt.size, &pkt, s->s->streams[pkt.stream_index], new_tb, s->base_ts); // PKT Size???
428
  memcpy(data + FRAME_HEADER_SIZE, pkt.data, pkt.size);
429
  *ts = av_rescale_q(pkt.dts, s->s->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
430
  //dprintf("pkt.dts=%ld TS1=%lu" , pkt.dts, *ts);
431
  *ts += s->base_ts;
432
  //dprintf(" TS2=%lu\n",*ts);
433
  s->last_ts = *ts;
434
  av_free_packet(&pkt);
435

    
436
  return result;
437
}
438

    
439
struct chunkiser_iface in_ipb = {
440
  .open = ipb_open,
441
  .close = ipb_close,
442
  .chunkise = ipb_chunkise,
443
};