Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (4.51 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 struct output_stream out;
23

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

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

    
67
  av_register_all();
68

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

    
89
  o->prev_pts = 0;
90
  o->prev_dts = 0;
91

    
92
  return of;
93
}
94

    
95
static struct output_stream *avf_init(const char *config)
96
{
97
  out.output_format = "nut";
98
  if (config) {
99
    out.output_file = strdup(config);
100
  } else {
101
    out.output_file = "/dev/stdout";
102
  }
103
  out.outctx = NULL;
104

    
105
  return &out;
106
}
107

    
108
static void avf_write(struct output_stream *o, int id, uint8_t *data, int size)
109
{
110
  const int header_size = VIDEO_PAYLOAD_HEADER_SIZE; 
111
  int frames, i;
112
  uint8_t *p;
113

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

    
123
      return;
124
    }
125
    av_set_parameters(o->outctx, NULL);
126
    snprintf(o->outctx->filename, sizeof(o->outctx->filename), "%s", o->output_file);
127
    dump_format(o->outctx, 0, o->output_file, 1);
128
    url_fopen(&o->outctx->pb, o->output_file, URL_WRONLY);
129
    av_write_header(o->outctx);
130
  }
131

    
132
  frames = data[header_size - 1];
133
  p = data + header_size + FRAME_HEADER_SIZE * frames;
134
  for (i = 0; i < frames; i++) {
135
    AVPacket pkt;
136
    int64_t pts, dts;
137
    int frame_size;
138

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

    
165
struct dechunkiser_iface out_avf = {
166
  .open = avf_init,
167
  .write = avf_write,
168
};