Statistics
| Branch: | Revision:

grapes / src / Chunkiser / output-stream-avf.c @ 4cf7f313

History | View | Annotate | Download (7.83 KB)

1
/*
2
 *  Copyright (c) 2010 Luca Abeni
3
 *
4
 *  This is free software; see gpl-3.0.txt
5
 */
6

    
7
#include <libavformat/avformat.h>
8
#include <stdio.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 "dechunkiser_iface.h"
16

    
17
struct dechunkiser_ctx {
18
  enum CodecID video_codec_id;
19
  enum CodecID audio_codec_id;
20
  int streams;
21
  int selected_streams;
22
  int width, height;
23
  int channels;
24
  int sample_rate, frame_size;
25
  AVRational video_time_base;
26
  AVRational audio_time_base;
27

    
28
  char *output_format;
29
  char *output_file;
30
  int64_t prev_pts, prev_dts;
31
  AVFormatContext *outctx;
32
};
33

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

    
84
  outfmt = av_guess_format(o->output_format, o->output_file, NULL);
85
  of = avformat_alloc_context();
86
  if (of == NULL) {
87
    return NULL;
88
  }
89
  of->oformat = outfmt;
90

    
91
  return of;
92
}
93

    
94
static AVFormatContext *format_gen(struct dechunkiser_ctx *o, const uint8_t *data)
95
{
96
  uint8_t codec;
97

    
98
  codec = data[0];
99
  if ((codec < 128) && ((o->streams & 0x01) == 0)) {
100
    int width, height, frame_rate_n, frame_rate_d;
101

    
102
    o->streams |= 0x01;
103
    o->video_codec_id = libav_codec_id(codec);
104
    video_payload_header_parse(data, &codec, &width, &height, &frame_rate_n, &frame_rate_d);
105
    o->width = width;
106
    o->height= height;
107
    o->video_time_base.den = frame_rate_n;
108
    o->video_time_base.num = frame_rate_d;
109
  } else if ((codec > 128) && ((o->streams & 0x02) == 0)) {
110
    uint8_t channels;
111
    int sample_rate, frame_size;
112

    
113
    audio_payload_header_parse(data, &codec, &channels, &sample_rate, &frame_size);
114
    o->streams |= 0x02;
115
    o->audio_codec_id = libav_codec_id(codec);
116
    o->sample_rate = sample_rate;
117
    o->channels = channels;
118
    o->frame_size = frame_size;
119
    o->audio_time_base.num = frame_size;
120
    o->audio_time_base.den = sample_rate;
121
  }
122

    
123
  if (o->streams == o->selected_streams) {
124
    AVCodecContext *c;
125

    
126
    o->outctx = format_init(o);
127
    if (o->streams & 0x01) {
128
      av_new_stream(o->outctx, 0);
129
      c = o->outctx->streams[o->outctx->nb_streams - 1]->codec;
130
      c->codec_id = o->video_codec_id;
131
      c->codec_type = CODEC_TYPE_VIDEO;
132
      c->width = o->width;
133
      c->height= o->height;
134
      c->time_base.den = o->video_time_base.den;
135
      c->time_base.num = o->video_time_base.num;
136
      o->outctx->streams[0]->avg_frame_rate.num = o->video_time_base.den;
137
      o->outctx->streams[0]->avg_frame_rate.den = o->video_time_base.num;
138
      c->pix_fmt = PIX_FMT_YUV420P;
139
    }
140
    if (o->streams & 0x02) {
141
      av_new_stream(o->outctx, 1);
142
      c = o->outctx->streams[o->outctx->nb_streams - 1]->codec;
143
      c->codec_id = o->audio_codec_id;
144
      c->codec_type = CODEC_TYPE_AUDIO;
145
      c->sample_rate = o->sample_rate;
146
      c->channels = o->channels;
147
      c->frame_size = o->frame_size;
148
      c->time_base.num = o->audio_time_base.num;
149
      c->time_base.den = o->audio_time_base.den;
150
    }
151
    o->prev_pts = 0;
152
    o->prev_dts = 0;
153

    
154
    return o->outctx;
155
  }
156

    
157
  return NULL;
158
}
159

    
160
static struct dechunkiser_ctx *avf_init(const char *fname, const char *config)
161
{
162
  struct dechunkiser_ctx *out;
163
  struct tag *cfg_tags;
164

    
165
  out = malloc(sizeof(struct dechunkiser_ctx));
166
  if (out == NULL) {
167
    return NULL;
168
  }
169

    
170
  memset(out, 0, sizeof(struct dechunkiser_ctx));
171
  out->output_format = strdup("nut");
172
  out->selected_streams = 0x01;
173
  if (fname) {
174
    out->output_file = strdup(fname);
175
  } else {
176
    out->output_file = strdup("/dev/stdout");
177
  }
178
  cfg_tags = config_parse(config);
179
  if (cfg_tags) {
180
    const char *format;
181

    
182
    format = config_value_str(cfg_tags, "format");
183
    if (format) {
184
      out->output_format = strdup(format);
185
    }
186
    format = config_value_str(cfg_tags, "media");
187
    if (format) {
188
      if (!strcmp(format, "video")) {
189
        out->selected_streams = 0x01;
190
      } else if (!strcmp(format, "audio")) {
191
        out->selected_streams = 0x02;
192
      } else if (!strcmp(format, "av")) {
193
        out->selected_streams = 0x03;
194
      }
195
    }
196
  }
197
  free(cfg_tags);
198

    
199
  return out;
200
}
201

    
202
static void avf_write(struct dechunkiser_ctx *o, int id, uint8_t *data, int size)
203
{
204
  int header_size;
205
  int frames, i, media_type;
206
  uint8_t *p;
207

    
208
  if (data[0] == 0) {
209
    fprintf(stderr, "Error! strange chunk: %x!!!\n", data[0]);
210
    return;
211
  } else if (data[0] < 127) {
212
    header_size = VIDEO_PAYLOAD_HEADER_SIZE;
213
    media_type = 1;
214
  } else {
215
    header_size = AUDIO_PAYLOAD_HEADER_SIZE;
216
    media_type = 2;
217
  }
218
  if (o->outctx == NULL) {
219
    o->outctx = format_gen(o, data);
220
    if (o->outctx == NULL) {
221
//      fprintf(stderr, "Format init failed\n");
222

    
223
      return;
224
    }
225
    av_set_parameters(o->outctx, NULL);
226
    snprintf(o->outctx->filename, sizeof(o->outctx->filename), "%s", o->output_file);
227
    dump_format(o->outctx, 0, o->output_file, 1);
228
    url_fopen(&o->outctx->pb, o->output_file, URL_WRONLY);
229
    av_write_header(o->outctx);
230
  }
231
  if ((o->streams & media_type) == 0) {
232
    return;                /* Received a chunk for a non-selected stream */
233
  }
234
  frames = data[header_size - 1];
235
  p = data + header_size + FRAME_HEADER_SIZE * frames;
236
  for (i = 0; i < frames; i++) {
237
    AVPacket pkt;
238
    int64_t pts, dts;
239
    int frame_size;
240

    
241
    frame_header_parse(data + header_size + FRAME_HEADER_SIZE * i,
242
                       &frame_size, &pts, &dts);
243
    //dprintf("Frame %d PTS1: %d\n", i, pts);
244
    av_init_packet(&pkt);
245
    pkt.stream_index = (media_type == 2) && (((o->streams & 0x01) == 0x01));
246
    if (pts != -1) {
247
      pts += (pts < o->prev_pts - ((1LL << 31) - 1)) ? ((o->prev_pts >> 32) + 1) << 32 : (o->prev_pts >> 32) << 32;
248
      //dprintf(" PTS2: %d\n", pts);
249
      o->prev_pts = pts;
250
      //dprintf("Frame %d has size %d --- PTS: %lld DTS: %lld\n", i, frame_size,
251
      //                                       av_rescale_q(pts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q),
252
      //                                       av_rescale_q(dts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q));
253
      pkt.pts = av_rescale_q(pts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
254
    } else {
255
      pkt.pts = AV_NOPTS_VALUE;
256
    }
257
    dts += (dts < o->prev_dts - ((1LL << 31) - 1)) ? ((o->prev_dts >> 32) + 1) << 32 : (o->prev_dts >> 32) << 32;
258
    o->prev_dts = dts;
259
    pkt.dts = av_rescale_q(dts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
260
    pkt.data = p;
261
    p += frame_size;
262
    pkt.size = frame_size;
263
    av_interleaved_write_frame(o->outctx, &pkt);
264
  }
265
}
266

    
267
static void avf_close(struct dechunkiser_ctx *s)
268
{
269
  int i;
270

    
271
  av_write_trailer(s->outctx);
272
  url_fclose(s->outctx->pb);
273

    
274
  for (i = 0; i < s->outctx->nb_streams; i++) {
275
    av_metadata_free(&s->outctx->streams[i]->metadata);
276
    av_free(s->outctx->streams[i]->codec);
277
    av_free(s->outctx->streams[i]->info);
278
    av_free(s->outctx->streams[i]);
279
  }
280
  av_metadata_free(&s->outctx->metadata);
281
  free(s->outctx);
282
  free(s->output_format);
283
  free(s->output_file);
284
  free(s);
285
}
286

    
287
struct dechunkiser_iface out_avf = {
288
  .open = avf_init,
289
  .write = avf_write,
290
  .close = avf_close,
291
};