Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (7.85 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 "libav-compat.h"
13
#include "int_coding.h"
14
#include "payload.h"
15
#include "grapes_config.h"
16
#include "ffmpeg_compat.h"
17
#include "dechunkiser_iface.h"
18

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

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

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

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

    
93
  return of;
94
}
95

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

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

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

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

    
125
  if (o->streams == o->selected_streams) {
126
    AVCodecContext *c;
127

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

    
156
    return o->outctx;
157
  }
158

    
159
  return NULL;
160
}
161

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

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

    
172
  memset(out, 0, sizeof(struct dechunkiser_ctx));
173
  out->output_format = strdup("nut");
174
  out->selected_streams = 0x03;
175
  if (fname && fname[0]) {
176
    out->output_file = strdup(fname);
177
  } else {
178
    out->output_file = strdup("/dev/stdout");
179
  }
180
  cfg_tags = grapes_config_parse(config);
181
  if (cfg_tags) {
182
    const char *format;
183

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

    
201
  return out;
202
}
203

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

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

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

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

    
269
static void avf_close(struct dechunkiser_ctx *s)
270
{
271
  int i;
272

    
273
  av_write_trailer(s->outctx);
274
  url_fclose(s->outctx->pb);
275

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

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