Statistics
| Branch: | Revision:

grapes / src / Chunkiser / output-stream-avf.c @ 02577fee

History | View | Annotate | Download (7.2 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 "payload.h"
13
#include "config.h"
14
#include "dechunkiser_iface.h"
15

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

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

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

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

    
89
  return of;
90
}
91

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

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

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

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

    
121
  if (o->streams == 0x03) {
122
    AVCodecContext *c;
123

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

    
152
    return o->outctx;
153
  }
154

    
155
  return NULL;
156
}
157

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

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

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

    
179
    format = config_value_str(cfg_tags, "format");
180
    if (format) {
181
      out->output_format = strdup(format);
182
    }
183
  }
184
  free(cfg_tags);
185

    
186
  return out;
187
}
188

    
189
static void avf_write(struct dechunkiser_ctx *o, int id, uint8_t *data, int size)
190
{
191
  int header_size;
192
  int frames, i;
193
  uint8_t *p;
194

    
195
  if (data[0] == 0) {
196
    fprintf(stderr, "Error! strange chunk: %x!!!\n", data[0]);
197
    return;
198
  } else if (data[0] < 127) {
199
    header_size = VIDEO_PAYLOAD_HEADER_SIZE;
200
  } else {
201
    header_size = AUDIO_PAYLOAD_HEADER_SIZE;
202
  }
203
  if (o->outctx == NULL) {
204
    o->outctx = format_gen(o, data);
205
    if (o->outctx == NULL) {
206
      fprintf(stderr, "Format init failed\n");
207

    
208
      return;
209
    }
210
    av_set_parameters(o->outctx, NULL);
211
    snprintf(o->outctx->filename, sizeof(o->outctx->filename), "%s", o->output_file);
212
    dump_format(o->outctx, 0, o->output_file, 1);
213
    url_fopen(&o->outctx->pb, o->output_file, URL_WRONLY);
214
    av_write_header(o->outctx);
215
  }
216

    
217
  frames = data[header_size - 1];
218
  p = data + header_size + FRAME_HEADER_SIZE * frames;
219
  for (i = 0; i < frames; i++) {
220
    AVPacket pkt;
221
    int64_t pts, dts;
222
    int frame_size;
223

    
224
    frame_header_parse(data + header_size + FRAME_HEADER_SIZE * i,
225
                       &frame_size, &pts, &dts);
226
    //dprintf("Frame %d PTS1: %d\n", i, pts);
227
    av_init_packet(&pkt);
228
    pkt.stream_index = (data[0] > 128) && (((o->streams & 0x01) == 0x01));
229
    if (pts != -1) {
230
      pts += (pts < o->prev_pts - ((1LL << 31) - 1)) ? ((o->prev_pts >> 32) + 1) << 32 : (o->prev_pts >> 32) << 32;
231
      //dprintf(" PTS2: %d\n", pts);
232
      o->prev_pts = pts;
233
      //dprintf("Frame %d has size %d --- PTS: %lld DTS: %lld\n", i, frame_size,
234
      //                                       av_rescale_q(pts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q),
235
      //                                       av_rescale_q(dts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q));
236
      pkt.pts = av_rescale_q(pts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
237
    } else {
238
      pkt.pts = AV_NOPTS_VALUE;
239
    }
240
    dts += (dts < o->prev_dts - ((1LL << 31) - 1)) ? ((o->prev_dts >> 32) + 1) << 32 : (o->prev_dts >> 32) << 32;
241
    o->prev_dts = dts;
242
    pkt.dts = av_rescale_q(dts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
243
    pkt.data = p;
244
    p += frame_size;
245
    pkt.size = frame_size;
246
    av_interleaved_write_frame(o->outctx, &pkt);
247
  }
248
}
249

    
250
static void avf_close(struct dechunkiser_ctx *s)
251
{
252
  av_write_trailer(s->outctx);
253
  url_fclose(s->outctx->pb);
254

    
255
  av_metadata_free(&s->outctx->streams[0]->metadata);
256
  av_free(s->outctx->streams[0]->codec);
257
  av_free(s->outctx->streams[0]->info);
258
  av_free(s->outctx->streams[0]);
259
  av_metadata_free(&s->outctx->metadata);
260
  free(s->outctx);
261
  free(s->output_format);
262
  free(s->output_file);
263
  free(s);
264
}
265

    
266
struct dechunkiser_iface out_avf = {
267
  .open = avf_init,
268
  .write = avf_write,
269
  .close = avf_close,
270
};