Statistics
| Branch: | Revision:

grapes / src / Chunkiser / output-stream-avf.c @ be9e4a42

History | View | Annotate | Download (4.64 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 "dechunkiser_iface.h"
14

    
15
struct output_stream {
16
  const char *output_format;
17
  const char *output_file;
18
  int64_t prev_pts, prev_dts;
19
  AVFormatContext *outctx;
20
};
21

    
22
static enum CodecID libav_codec_id(uint8_t mytype)
23
{
24
  switch (mytype) {
25
    case 1:
26
      return CODEC_ID_MPEG2VIDEO;
27
    case 2:
28
      return CODEC_ID_H261;
29
    case 3:
30
      return CODEC_ID_H263P;
31
    case 4:
32
      return CODEC_ID_MJPEG;
33
    case 5:
34
      return CODEC_ID_MPEG4;
35
    case 6:
36
      return CODEC_ID_FLV1;
37
    case 7:
38
      return CODEC_ID_SVQ3;
39
    case 8:
40
      return CODEC_ID_DVVIDEO;
41
    case 9:
42
      return CODEC_ID_H264;
43
    case 10:
44
      return CODEC_ID_THEORA;
45
    case 11:
46
      return CODEC_ID_SNOW;
47
    case 12:
48
      return CODEC_ID_VP6;
49
    case 13:
50
      return CODEC_ID_DIRAC;
51
    default:
52
      fprintf(stderr, "Unknown codec %d\n", mytype);
53
      return 0;
54
  }
55
}
56

    
57
static AVFormatContext *format_init(struct output_stream *o, const uint8_t *data)
58
{
59
  AVFormatContext *of;
60
  AVCodecContext *c;
61
  AVOutputFormat *outfmt;
62
  int width, height, frame_rate_n, frame_rate_d;
63
  uint8_t codec;
64

    
65
  av_register_all();
66

    
67
  payload_header_parse(data, &codec, &width, &height, &frame_rate_n, &frame_rate_d);
68
  //dprintf("Frame size: %dx%d -- Frame rate: %d / %d\n", width, height, frame_rate_n, frame_rate_d);
69
  outfmt = av_guess_format(o->output_format, o->output_file, NULL);
70
  of = avformat_alloc_context();
71
  if (of == NULL) {
72
    return NULL;
73
  }
74
  of->oformat = outfmt;
75
  av_new_stream(of, 0);
76
  c = of->streams[0]->codec;
77
  c->codec_id = libav_codec_id(codec);
78
  c->codec_type = CODEC_TYPE_VIDEO;
79
  c->width = width;
80
  c->height= height;
81
  c->time_base.den = frame_rate_n;
82
  c->time_base.num = frame_rate_d;
83
  of->streams[0]->avg_frame_rate.num = frame_rate_n;
84
  of->streams[0]->avg_frame_rate.den = frame_rate_d;
85
  c->pix_fmt = PIX_FMT_YUV420P;
86

    
87
  o->prev_pts = 0;
88
  o->prev_dts = 0;
89

    
90
  return of;
91
}
92

    
93
static struct output_stream *avf_init(const char *fname, const char *config)
94
{
95
  struct output_stream *out;
96

    
97
  out = malloc(sizeof(struct output_stream));
98
  if (out == NULL) {
99
    return NULL;
100
  }
101

    
102
  memset(out, 0, sizeof(struct output_stream));
103
  out->output_format = "nut";
104
  if (fname) {
105
    out->output_file = strdup(fname);
106
  } else {
107
    out->output_file = "/dev/stdout";
108
  }
109

    
110
  return out;
111
}
112

    
113
static void avf_write(struct output_stream *o, int id, uint8_t *data, int size)
114
{
115
  const int header_size = VIDEO_PAYLOAD_HEADER_SIZE; 
116
  int frames, i;
117
  uint8_t *p;
118

    
119
  if (data[0] > 127) {
120
    fprintf(stderr, "Error! Non video chunk: %x!!!\n", data[0]);
121
    return;
122
  }
123
  if (o->outctx == NULL) {
124
    o->outctx = format_init(o, data);
125
    if (o->outctx == NULL) {
126
      fprintf(stderr, "Format init failed\n");
127

    
128
      return;
129
    }
130
    av_set_parameters(o->outctx, NULL);
131
    snprintf(o->outctx->filename, sizeof(o->outctx->filename), "%s", o->output_file);
132
    dump_format(o->outctx, 0, o->output_file, 1);
133
    url_fopen(&o->outctx->pb, o->output_file, URL_WRONLY);
134
    av_write_header(o->outctx);
135
  }
136

    
137
  frames = data[header_size - 1];
138
  p = data + header_size + FRAME_HEADER_SIZE * frames;
139
  for (i = 0; i < frames; i++) {
140
    AVPacket pkt;
141
    int64_t pts, dts;
142
    int frame_size;
143

    
144
    frame_header_parse(data + header_size + FRAME_HEADER_SIZE * i,
145
                       &frame_size, &pts, &dts);
146
    //dprintf("Frame %d PTS1: %d\n", i, pts);
147
    av_init_packet(&pkt);
148
    pkt.stream_index = 0;        // FIXME!
149
    if (pts != -1) {
150
      pts += (pts < o->prev_pts - ((1LL << 31) - 1)) ? ((o->prev_pts >> 32) + 1) << 32 : (o->prev_pts >> 32) << 32;
151
      //dprintf(" PTS2: %d\n", pts);
152
      o->prev_pts = pts;
153
      //dprintf("Frame %d has size %d --- PTS: %lld DTS: %lld\n", i, frame_size,
154
      //                                       av_rescale_q(pts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q),
155
      //                                       av_rescale_q(dts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q));
156
      pkt.pts = av_rescale_q(pts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
157
    } else {
158
      pkt.pts = AV_NOPTS_VALUE;
159
    }
160
    dts += (dts < o->prev_dts - ((1LL << 31) - 1)) ? ((o->prev_dts >> 32) + 1) << 32 : (o->prev_dts >> 32) << 32;
161
    o->prev_dts = dts;
162
    pkt.dts = av_rescale_q(dts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
163
    pkt.data = p;
164
    p += frame_size;
165
    pkt.size = frame_size;
166
    av_interleaved_write_frame(o->outctx, &pkt);
167
  }
168
}
169

    
170
struct dechunkiser_iface out_avf = {
171
  .open = avf_init,
172
  .write = avf_write,
173
};