Browse code

ffm: redesign header format to make it extensible

Currently FFM files generated with one versions of ffmpeg generally
cannot be read by another.
By spliting data into chunks, more fields can saftely be appended to
chunks as well as new chunks added.

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2012/10/09 10:49:40
Showing 4 changed files
... ...
@@ -11,6 +11,7 @@ version <next>:
11 11
 - TAK demuxer, decoder and parser
12 12
 - DTS-HD demuxer
13 13
 - remove -same_quant, it hasn't worked for years
14
+- FFM2 support
14 15
 - X-Face image encoder and decoder
15 16
 - metadata (INFO tag) support in WAV muxer
16 17
 - subtitles raw text decoder
... ...
@@ -228,6 +228,141 @@ static int ffm_close(AVFormatContext *s)
228 228
     return 0;
229 229
 }
230 230
 
231
+static int ffm2_read_header(AVFormatContext *s)
232
+{
233
+    FFMContext *ffm = s->priv_data;
234
+    AVStream *st;
235
+    AVIOContext *pb = s->pb;
236
+    AVCodecContext *codec;
237
+    int i;
238
+
239
+    ffm->packet_size = avio_rb32(pb);
240
+    if (ffm->packet_size != FFM_PACKET_SIZE)
241
+        goto fail;
242
+    ffm->write_index = avio_rb64(pb);
243
+    /* get also filesize */
244
+    if (pb->seekable) {
245
+        ffm->file_size = avio_size(pb);
246
+        if (ffm->write_index && 0)
247
+            adjust_write_index(s);
248
+    } else {
249
+        ffm->file_size = (UINT64_C(1) << 63) - 1;
250
+    }
251
+
252
+    while(!url_feof(pb)) {
253
+        unsigned id = avio_rb32(pb);
254
+        unsigned size = avio_rb32(pb);
255
+        int64_t next = avio_tell(pb) + size;
256
+        char rc_eq_buf[128];
257
+
258
+        if(!id)
259
+            break;
260
+
261
+        switch(id) {
262
+        case MKBETAG('M', 'A', 'I', 'N'):
263
+            avio_rb32(pb); /* nb_streams */
264
+            avio_rb32(pb); /* total bitrate */
265
+            break;
266
+        case MKBETAG('C', 'O', 'M', 'M'):
267
+            st = avformat_new_stream(s, NULL);
268
+            if (!st)
269
+                goto fail;
270
+
271
+            avpriv_set_pts_info(st, 64, 1, 1000000);
272
+
273
+            codec = st->codec;
274
+            /* generic info */
275
+            codec->codec_id = avio_rb32(pb);
276
+            codec->codec_type = avio_r8(pb);
277
+            codec->bit_rate = avio_rb32(pb);
278
+            codec->flags = avio_rb32(pb);
279
+            codec->flags2 = avio_rb32(pb);
280
+            codec->debug = avio_rb32(pb);
281
+            if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
282
+                codec->extradata_size = avio_rb32(pb);
283
+                codec->extradata = av_malloc(codec->extradata_size);
284
+                if (!codec->extradata)
285
+                    return AVERROR(ENOMEM);
286
+                avio_read(pb, codec->extradata, codec->extradata_size);
287
+            }
288
+            avio_seek(pb, next, SEEK_SET);
289
+            id = avio_rb32(pb);
290
+            size = avio_rb32(pb);
291
+            next = avio_tell(pb) + size;
292
+            switch(id) {
293
+            case MKBETAG('S', 'T', 'V', 'I'):
294
+                codec->time_base.num = avio_rb32(pb);
295
+                codec->time_base.den = avio_rb32(pb);
296
+                codec->width = avio_rb16(pb);
297
+                codec->height = avio_rb16(pb);
298
+                codec->gop_size = avio_rb16(pb);
299
+                codec->pix_fmt = avio_rb32(pb);
300
+                codec->qmin = avio_r8(pb);
301
+                codec->qmax = avio_r8(pb);
302
+                codec->max_qdiff = avio_r8(pb);
303
+                codec->qcompress = avio_rb16(pb) / 10000.0;
304
+                codec->qblur = avio_rb16(pb) / 10000.0;
305
+                codec->bit_rate_tolerance = avio_rb32(pb);
306
+                avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
307
+                codec->rc_eq = av_strdup(rc_eq_buf);
308
+                codec->rc_max_rate = avio_rb32(pb);
309
+                codec->rc_min_rate = avio_rb32(pb);
310
+                codec->rc_buffer_size = avio_rb32(pb);
311
+                codec->i_quant_factor = av_int2double(avio_rb64(pb));
312
+                codec->b_quant_factor = av_int2double(avio_rb64(pb));
313
+                codec->i_quant_offset = av_int2double(avio_rb64(pb));
314
+                codec->b_quant_offset = av_int2double(avio_rb64(pb));
315
+                codec->dct_algo = avio_rb32(pb);
316
+                codec->strict_std_compliance = avio_rb32(pb);
317
+                codec->max_b_frames = avio_rb32(pb);
318
+                codec->mpeg_quant = avio_rb32(pb);
319
+                codec->intra_dc_precision = avio_rb32(pb);
320
+                codec->me_method = avio_rb32(pb);
321
+                codec->mb_decision = avio_rb32(pb);
322
+                codec->nsse_weight = avio_rb32(pb);
323
+                codec->frame_skip_cmp = avio_rb32(pb);
324
+                codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
325
+                codec->codec_tag = avio_rb32(pb);
326
+                codec->thread_count = avio_r8(pb);
327
+                codec->coder_type = avio_rb32(pb);
328
+                codec->me_cmp = avio_rb32(pb);
329
+                codec->me_subpel_quality = avio_rb32(pb);
330
+                codec->me_range = avio_rb32(pb);
331
+                codec->keyint_min = avio_rb32(pb);
332
+                codec->scenechange_threshold = avio_rb32(pb);
333
+                codec->b_frame_strategy = avio_rb32(pb);
334
+                codec->qcompress = av_int2double(avio_rb64(pb));
335
+                codec->qblur = av_int2double(avio_rb64(pb));
336
+                codec->max_qdiff = avio_rb32(pb);
337
+                codec->refs = avio_rb32(pb);
338
+                break;
339
+            case MKBETAG('S', 'T', 'A', 'U'):
340
+                codec->sample_rate = avio_rb32(pb);
341
+                codec->channels = avio_rl16(pb);
342
+                codec->frame_size = avio_rl16(pb);
343
+                break;
344
+            }
345
+            break;
346
+        }
347
+        avio_seek(pb, next, SEEK_SET);
348
+    }
349
+
350
+    /* get until end of block reached */
351
+    while ((avio_tell(pb) % ffm->packet_size) != 0)
352
+        avio_r8(pb);
353
+
354
+    /* init packet demux */
355
+    ffm->packet_ptr = ffm->packet;
356
+    ffm->packet_end = ffm->packet;
357
+    ffm->frame_offset = 0;
358
+    ffm->dts = 0;
359
+    ffm->read_state = READ_HEADER;
360
+    ffm->first_packet = 1;
361
+    return 0;
362
+ fail:
363
+    ffm_close(s);
364
+    return -1;
365
+}
231 366
 
232 367
 static int ffm_read_header(AVFormatContext *s)
233 368
 {
... ...
@@ -240,6 +375,8 @@ static int ffm_read_header(AVFormatContext *s)
240 240
 
241 241
     /* header */
242 242
     tag = avio_rl32(pb);
243
+    if (tag == MKTAG('F', 'F', 'M', '2'))
244
+        return ffm2_read_header(s);
243 245
     if (tag != MKTAG('F', 'F', 'M', '1'))
244 246
         goto fail;
245 247
     ffm->packet_size = avio_rb32(pb);
... ...
@@ -486,7 +623,7 @@ static int ffm_probe(AVProbeData *p)
486 486
 {
487 487
     if (
488 488
         p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
489
-        p->buf[3] == '1')
489
+        (p->buf[3] == '1' || p->buf[3] == '2'))
490 490
         return AVPROBE_SCORE_MAX + 1;
491 491
     return 0;
492 492
 }
... ...
@@ -83,6 +83,16 @@ static void ffm_write_data(AVFormatContext *s,
83 83
     }
84 84
 }
85 85
 
86
+static void write_header_chunk(AVIOContext *pb, AVIOContext *dpb, unsigned id)
87
+{
88
+    uint8_t *dyn_buf;
89
+    int dyn_size= avio_close_dyn_buf(dpb, &dyn_buf);
90
+    avio_wb32(pb, id);
91
+    avio_wb32(pb, dyn_size);
92
+    avio_write(pb, dyn_buf, dyn_size);
93
+    av_free(dyn_buf);
94
+}
95
+
86 96
 static int ffm_write_header(AVFormatContext *s)
87 97
 {
88 98
     FFMContext *ffm = s->priv_data;
... ...
@@ -101,10 +111,13 @@ static int ffm_write_header(AVFormatContext *s)
101 101
     ffm->packet_size = FFM_PACKET_SIZE;
102 102
 
103 103
     /* header */
104
-    avio_wl32(pb, MKTAG('F', 'F', 'M', '1'));
104
+    avio_wl32(pb, MKTAG('F', 'F', 'M', '2'));
105 105
     avio_wb32(pb, ffm->packet_size);
106 106
     avio_wb64(pb, 0); /* current write position */
107 107
 
108
+    if(avio_open_dyn_buf(&pb) < 0)
109
+        return AVERROR(ENOMEM);
110
+
108 111
     avio_wb32(pb, s->nb_streams);
109 112
     bit_rate = 0;
110 113
     for(i=0;i<s->nb_streams;i++) {
... ...
@@ -113,10 +126,14 @@ static int ffm_write_header(AVFormatContext *s)
113 113
     }
114 114
     avio_wb32(pb, bit_rate);
115 115
 
116
+    write_header_chunk(s->pb, pb, MKBETAG('M', 'A', 'I', 'N'));
117
+
116 118
     /* list of streams */
117 119
     for(i=0;i<s->nb_streams;i++) {
118 120
         st = s->streams[i];
119 121
         avpriv_set_pts_info(st, 64, 1, 1000000);
122
+        if(avio_open_dyn_buf(&pb) < 0)
123
+            return AVERROR(ENOMEM);
120 124
 
121 125
         codec = st->codec;
122 126
         /* generic info */
... ...
@@ -126,6 +143,13 @@ static int ffm_write_header(AVFormatContext *s)
126 126
         avio_wb32(pb, codec->flags);
127 127
         avio_wb32(pb, codec->flags2);
128 128
         avio_wb32(pb, codec->debug);
129
+        if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
130
+            avio_wb32(pb, codec->extradata_size);
131
+            avio_write(pb, codec->extradata, codec->extradata_size);
132
+        }
133
+        write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M'));
134
+        if(avio_open_dyn_buf(&pb) < 0)
135
+            return AVERROR(ENOMEM);
129 136
         /* specific info */
130 137
         switch(codec->codec_type) {
131 138
         case AVMEDIA_TYPE_VIDEO:
... ...
@@ -172,20 +196,21 @@ static int ffm_write_header(AVFormatContext *s)
172 172
             avio_wb64(pb, av_double2int(codec->qblur));
173 173
             avio_wb32(pb, codec->max_qdiff);
174 174
             avio_wb32(pb, codec->refs);
175
+            write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'V', 'I'));
175 176
             break;
176 177
         case AVMEDIA_TYPE_AUDIO:
177 178
             avio_wb32(pb, codec->sample_rate);
178 179
             avio_wl16(pb, codec->channels);
179 180
             avio_wl16(pb, codec->frame_size);
181
+            write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'A', 'U'));
180 182
             break;
181 183
         default:
182 184
             return -1;
183 185
         }
184
-        if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
185
-            avio_wb32(pb, codec->extradata_size);
186
-            avio_write(pb, codec->extradata, codec->extradata_size);
187
-        }
188 186
     }
187
+    pb = s->pb;
188
+
189
+    avio_wb64(pb, 0); // end of header
189 190
 
190 191
     /* flush until end of block reached */
191 192
     while ((avio_tell(pb) % ffm->packet_size) != 0)
... ...
@@ -1,3 +1,3 @@
1
-c76e8f9a9bcd04379dfa3239e272d049 *./tests/data/lavf/lavf.ffm
1
+d33fae310a7f6db1dc7fb74d1a9e0e6a *./tests/data/lavf/lavf.ffm
2 2
 376832 ./tests/data/lavf/lavf.ffm
3 3
 ./tests/data/lavf/lavf.ffm CRC=0x5b136bb1