Statistics
| Branch: | Revision:

grapes / src / Chunkiser / output-stream-avf.c @ 0faee466

History | View | Annotate | Download (4.87 KB)

1 1e8dedd8 Luca Abeni
/*
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 0faee466 Luca Abeni
#include "config.h"
14 c0c735aa Luca Abeni
#include "dechunkiser_iface.h"
15 1e8dedd8 Luca Abeni
16
struct output_stream {
17
  const char *output_format;
18
  const char *output_file;
19
  int64_t prev_pts, prev_dts;
20
  AVFormatContext *outctx;
21
};
22
23
static enum CodecID libav_codec_id(uint8_t mytype)
24
{
25
  switch (mytype) {
26
    case 1:
27
      return CODEC_ID_MPEG2VIDEO;
28
    case 2:
29
      return CODEC_ID_H261;
30
    case 3:
31
      return CODEC_ID_H263P;
32
    case 4:
33
      return CODEC_ID_MJPEG;
34
    case 5:
35
      return CODEC_ID_MPEG4;
36
    case 6:
37
      return CODEC_ID_FLV1;
38
    case 7:
39
      return CODEC_ID_SVQ3;
40
    case 8:
41
      return CODEC_ID_DVVIDEO;
42
    case 9:
43
      return CODEC_ID_H264;
44
    case 10:
45
      return CODEC_ID_THEORA;
46
    case 11:
47
      return CODEC_ID_SNOW;
48
    case 12:
49
      return CODEC_ID_VP6;
50
    case 13:
51
      return CODEC_ID_DIRAC;
52
    default:
53
      fprintf(stderr, "Unknown codec %d\n", mytype);
54
      return 0;
55
  }
56
}
57
58
static AVFormatContext *format_init(struct output_stream *o, const uint8_t *data)
59
{
60
  AVFormatContext *of;
61
  AVCodecContext *c;
62
  AVOutputFormat *outfmt;
63
  int width, height, frame_rate_n, frame_rate_d;
64
  uint8_t codec;
65
66
  av_register_all();
67
68
  payload_header_parse(data, &codec, &width, &height, &frame_rate_n, &frame_rate_d);
69
  //dprintf("Frame size: %dx%d -- Frame rate: %d / %d\n", width, height, frame_rate_n, frame_rate_d);
70
  outfmt = av_guess_format(o->output_format, o->output_file, NULL);
71
  of = avformat_alloc_context();
72
  if (of == NULL) {
73
    return NULL;
74
  }
75
  of->oformat = outfmt;
76
  av_new_stream(of, 0);
77
  c = of->streams[0]->codec;
78
  c->codec_id = libav_codec_id(codec);
79
  c->codec_type = CODEC_TYPE_VIDEO;
80
  c->width = width;
81
  c->height= height;
82
  c->time_base.den = frame_rate_n;
83
  c->time_base.num = frame_rate_d;
84
  of->streams[0]->avg_frame_rate.num = frame_rate_n;
85
  of->streams[0]->avg_frame_rate.den = frame_rate_d;
86
  c->pix_fmt = PIX_FMT_YUV420P;
87
88
  o->prev_pts = 0;
89
  o->prev_dts = 0;
90
91
  return of;
92
}
93
94 e296176d Luca Abeni
static struct output_stream *avf_init(const char *fname, const char *config)
95 1e8dedd8 Luca Abeni
{
96 be9e4a42 Luca Abeni
  struct output_stream *out;
97 0faee466 Luca Abeni
  struct tag *cfg_tags;
98 be9e4a42 Luca Abeni
99
  out = malloc(sizeof(struct output_stream));
100
  if (out == NULL) {
101
    return NULL;
102
  }
103
104
  memset(out, 0, sizeof(struct output_stream));
105
  out->output_format = "nut";
106 e296176d Luca Abeni
  if (fname) {
107 be9e4a42 Luca Abeni
    out->output_file = strdup(fname);
108 1e8dedd8 Luca Abeni
  } else {
109 be9e4a42 Luca Abeni
    out->output_file = "/dev/stdout";
110 1e8dedd8 Luca Abeni
  }
111 0faee466 Luca Abeni
  cfg_tags = config_parse(config);
112
  if (cfg_tags) {
113
    const char *format;
114
115
    format = config_value_str(cfg_tags, "format");
116
    if (format) {
117
      out->output_format = strdup(format);
118
    }
119
  }
120 1e8dedd8 Luca Abeni
121 be9e4a42 Luca Abeni
  return out;
122 1e8dedd8 Luca Abeni
}
123
124 0c461e28 Luca Abeni
static void avf_write(struct output_stream *o, int id, uint8_t *data, int size)
125 1e8dedd8 Luca Abeni
{
126
  const int header_size = VIDEO_PAYLOAD_HEADER_SIZE; 
127
  int frames, i;
128 0c461e28 Luca Abeni
  uint8_t *p;
129 1e8dedd8 Luca Abeni
130
  if (data[0] > 127) {
131
    fprintf(stderr, "Error! Non video chunk: %x!!!\n", data[0]);
132
    return;
133
  }
134
  if (o->outctx == NULL) {
135
    o->outctx = format_init(o, data);
136
    if (o->outctx == NULL) {
137
      fprintf(stderr, "Format init failed\n");
138
139
      return;
140
    }
141
    av_set_parameters(o->outctx, NULL);
142
    snprintf(o->outctx->filename, sizeof(o->outctx->filename), "%s", o->output_file);
143
    dump_format(o->outctx, 0, o->output_file, 1);
144
    url_fopen(&o->outctx->pb, o->output_file, URL_WRONLY);
145
    av_write_header(o->outctx);
146
  }
147
148
  frames = data[header_size - 1];
149
  p = data + header_size + FRAME_HEADER_SIZE * frames;
150
  for (i = 0; i < frames; i++) {
151
    AVPacket pkt;
152
    int64_t pts, dts;
153
    int frame_size;
154
155
    frame_header_parse(data + header_size + FRAME_HEADER_SIZE * i,
156
                       &frame_size, &pts, &dts);
157
    //dprintf("Frame %d PTS1: %d\n", i, pts);
158
    av_init_packet(&pkt);
159
    pkt.stream_index = 0;        // FIXME!
160
    if (pts != -1) {
161
      pts += (pts < o->prev_pts - ((1LL << 31) - 1)) ? ((o->prev_pts >> 32) + 1) << 32 : (o->prev_pts >> 32) << 32;
162
      //dprintf(" PTS2: %d\n", pts);
163
      o->prev_pts = pts;
164
      //dprintf("Frame %d has size %d --- PTS: %lld DTS: %lld\n", i, frame_size,
165
      //                                       av_rescale_q(pts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q),
166
      //                                       av_rescale_q(dts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q));
167
      pkt.pts = av_rescale_q(pts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
168
    } else {
169
      pkt.pts = AV_NOPTS_VALUE;
170
    }
171
    dts += (dts < o->prev_dts - ((1LL << 31) - 1)) ? ((o->prev_dts >> 32) + 1) << 32 : (o->prev_dts >> 32) << 32;
172
    o->prev_dts = dts;
173
    pkt.dts = av_rescale_q(dts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
174 0c461e28 Luca Abeni
    pkt.data = p;
175 1e8dedd8 Luca Abeni
    p += frame_size;
176
    pkt.size = frame_size;
177
    av_interleaved_write_frame(o->outctx, &pkt);
178
  }
179
}
180 c0c735aa Luca Abeni
181
struct dechunkiser_iface out_avf = {
182
  .open = avf_init,
183
  .write = avf_write,
184
};