Browse code

avformat: add IVR demuxer

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2015/11/12 06:04:57
Showing 6 changed files
... ...
@@ -33,6 +33,7 @@ version <next>:
33 33
 - XMA1 & XMA2 decoder
34 34
 - realtime filter
35 35
 - anoisesrc audio filter source
36
+- IVR demuxer
36 37
 
37 38
 
38 39
 version 2.8:
... ...
@@ -352,6 +352,7 @@ library:
352 352
     @tab A format generated by IndigoVision 8000 video server.
353 353
 @item IVF (On2)                 @tab X @tab X
354 354
     @tab A format used by libvpx
355
+@item Internet Video Recording  @tab   @tab X
355 356
 @item IRCAM                     @tab X @tab X
356 357
 @item LATM                      @tab X @tab X
357 358
 @item LMLM4                     @tab   @tab X
... ...
@@ -228,6 +228,7 @@ OBJS-$(CONFIG_ISS_DEMUXER)               += iss.o
228 228
 OBJS-$(CONFIG_IV8_DEMUXER)               += iv8.o
229 229
 OBJS-$(CONFIG_IVF_DEMUXER)               += ivfdec.o
230 230
 OBJS-$(CONFIG_IVF_MUXER)                 += ivfenc.o
231
+OBJS-$(CONFIG_IVR_DEMUXER)               += rmdec.o rm.o rmsipr.o
231 232
 OBJS-$(CONFIG_JACOSUB_DEMUXER)           += jacosubdec.o subtitles.o
232 233
 OBJS-$(CONFIG_JACOSUB_MUXER)             += jacosubenc.o rawenc.o
233 234
 OBJS-$(CONFIG_JV_DEMUXER)                += jvdec.o
... ...
@@ -169,6 +169,7 @@ void av_register_all(void)
169 169
     REGISTER_DEMUXER (ISS,              iss);
170 170
     REGISTER_DEMUXER (IV8,              iv8);
171 171
     REGISTER_MUXDEMUX(IVF,              ivf);
172
+    REGISTER_DEMUXER (IVR,              ivr);
172 173
     REGISTER_MUXDEMUX(JACOSUB,          jacosub);
173 174
     REGISTER_DEMUXER (JV,               jv);
174 175
     REGISTER_MUXER   (LATM,             latm);
... ...
@@ -63,6 +63,7 @@ typedef struct RMDemuxContext {
63 63
     int remaining_len;
64 64
     int audio_stream_num; ///< Stream number for audio packets
65 65
     int audio_pkt_cnt; ///< Output packet counter
66
+    int data_end;
66 67
 } RMDemuxContext;
67 68
 
68 69
 static int rm_read_close(AVFormatContext *s);
... ...
@@ -488,6 +489,47 @@ static int rm_read_header_old(AVFormatContext *s)
488 488
     return rm_read_audio_stream_info(s, s->pb, st, st->priv_data, 1);
489 489
 }
490 490
 
491
+static int rm_read_multi(AVFormatContext *s, AVIOContext *pb,
492
+                         AVStream *st, char *mime)
493
+{
494
+    int number_of_streams = avio_rb16(pb);
495
+    int number_of_mdpr;
496
+    int i, ret;
497
+    unsigned size2;
498
+    for (i = 0; i<number_of_streams; i++)
499
+        avio_rb16(pb);
500
+    number_of_mdpr = avio_rb16(pb);
501
+    if (number_of_mdpr != 1) {
502
+        avpriv_request_sample(s, "MLTI with multiple (%d) MDPR", number_of_mdpr);
503
+    }
504
+    for (i = 0; i < number_of_mdpr; i++) {
505
+        AVStream *st2;
506
+        if (i > 0) {
507
+            st2 = avformat_new_stream(s, NULL);
508
+            if (!st2) {
509
+                ret = AVERROR(ENOMEM);
510
+                return ret;
511
+            }
512
+            st2->id = st->id + (i<<16);
513
+            st2->codec->bit_rate = st->codec->bit_rate;
514
+            st2->start_time = st->start_time;
515
+            st2->duration   = st->duration;
516
+            st2->codec->codec_type = AVMEDIA_TYPE_DATA;
517
+            st2->priv_data = ff_rm_alloc_rmstream();
518
+            if (!st2->priv_data)
519
+                return AVERROR(ENOMEM);
520
+        } else
521
+            st2 = st;
522
+
523
+        size2 = avio_rb32(pb);
524
+        ret = ff_rm_read_mdpr_codecdata(s, s->pb, st2, st2->priv_data,
525
+                                        size2, mime);
526
+        if (ret < 0)
527
+            return ret;
528
+    }
529
+    return 0;
530
+}
531
+
491 532
 static int rm_read_header(AVFormatContext *s)
492 533
 {
493 534
     RMDemuxContext *rm = s->priv_data;
... ...
@@ -579,40 +621,9 @@ static int rm_read_header(AVFormatContext *s)
579 579
             ffio_ensure_seekback(pb, 4);
580 580
             v = avio_rb32(pb);
581 581
             if (v == MKBETAG('M', 'L', 'T', 'I')) {
582
-                int number_of_streams = avio_rb16(pb);
583
-                int number_of_mdpr;
584
-                int i;
585
-                unsigned size2;
586
-                for (i = 0; i<number_of_streams; i++)
587
-                    avio_rb16(pb);
588
-                number_of_mdpr = avio_rb16(pb);
589
-                if (number_of_mdpr != 1) {
590
-                    avpriv_request_sample(s, "MLTI with multiple (%d) MDPR", number_of_mdpr);
591
-                }
592
-                for (i = 0; i < number_of_mdpr; i++) {
593
-                    AVStream *st2;
594
-                    if (i > 0) {
595
-                        st2 = avformat_new_stream(s, NULL);
596
-                        if (!st2) {
597
-                            ret = AVERROR(ENOMEM);
598
-                            goto fail;
599
-                        }
600
-                        st2->id = st->id + (i<<16);
601
-                        st2->codec->bit_rate = st->codec->bit_rate;
602
-                        st2->start_time = st->start_time;
603
-                        st2->duration   = st->duration;
604
-                        st2->codec->codec_type = AVMEDIA_TYPE_DATA;
605
-                        st2->priv_data = ff_rm_alloc_rmstream();
606
-                        if (!st2->priv_data)
607
-                            return AVERROR(ENOMEM);
608
-                    } else
609
-                        st2 = st;
610
-
611
-                    size2 = avio_rb32(pb);
612
-                    if (ff_rm_read_mdpr_codecdata(s, s->pb, st2, st2->priv_data,
613
-                                                  size2, mime) < 0)
614
-                        goto fail;
615
-                }
582
+                ret = rm_read_multi(s, s->pb, st, mime);
583
+                if (ret < 0)
584
+                    goto fail;
616 585
                 avio_seek(pb, codec_pos + size, SEEK_SET);
617 586
             } else {
618 587
                 avio_skip(pb, -4);
... ...
@@ -1155,3 +1166,233 @@ AVInputFormat ff_rdt_demuxer = {
1155 1155
     .read_close     = rm_read_close,
1156 1156
     .flags          = AVFMT_NOFILE,
1157 1157
 };
1158
+
1159
+static int ivr_probe(AVProbeData *p)
1160
+{
1161
+    if (memcmp(p->buf, ".R1M\x0\x1\x1", 7) &&
1162
+        memcmp(p->buf, ".REC", 4))
1163
+        return 0;
1164
+
1165
+    return AVPROBE_SCORE_MAX;
1166
+}
1167
+
1168
+static int ivr_read_header(AVFormatContext *s)
1169
+{
1170
+    unsigned tag, type, len, tlen, value;
1171
+    int i, j, n, count, nb_streams, ret;
1172
+    uint8_t key[256], val[256];
1173
+    AVIOContext *pb = s->pb;
1174
+    AVStream *st;
1175
+    int64_t pos, offset, temp;
1176
+
1177
+    pos = avio_tell(pb);
1178
+    tag = avio_rl32(pb);
1179
+    if (tag == MKTAG('.','R','1','M')) {
1180
+        if (avio_rb16(pb) != 1)
1181
+            return AVERROR_INVALIDDATA;
1182
+        if (avio_r8(pb) != 1)
1183
+            return AVERROR_INVALIDDATA;
1184
+        len = avio_rb32(pb);
1185
+        avio_skip(pb, len);
1186
+        avio_skip(pb, 5);
1187
+        temp = avio_rb64(pb);
1188
+        while (!avio_feof(pb) && temp) {
1189
+            offset = temp;
1190
+            temp = avio_rb64(pb);
1191
+        }
1192
+        avio_skip(pb, offset - avio_tell(pb));
1193
+        if (avio_r8(pb) != 1)
1194
+            return AVERROR_INVALIDDATA;
1195
+        len = avio_rb32(pb);
1196
+        avio_skip(pb, len);
1197
+        if (avio_r8(pb) != 2)
1198
+            return AVERROR_INVALIDDATA;
1199
+        avio_skip(pb, 16);
1200
+        pos = avio_tell(pb);
1201
+        tag = avio_rl32(pb);
1202
+    }
1203
+
1204
+    if (tag != MKTAG('.','R','E','C'))
1205
+        return AVERROR_INVALIDDATA;
1206
+
1207
+    if (avio_r8(pb) != 0)
1208
+        return AVERROR_INVALIDDATA;
1209
+    count = avio_rb32(pb);
1210
+    for (i = 0; i < count; i++) {
1211
+        if (avio_feof(pb))
1212
+            return AVERROR_INVALIDDATA;
1213
+
1214
+        type = avio_r8(pb);
1215
+        tlen = avio_rb32(pb);
1216
+        avio_get_str(pb, tlen, key, sizeof(key));
1217
+        len = avio_rb32(pb);
1218
+        if (type == 5) {
1219
+            avio_get_str(pb, len, val, sizeof(val));
1220
+            av_log(s, AV_LOG_DEBUG, "%s = '%s'\n", key, val);
1221
+        } else if (type == 4) {
1222
+            av_log(s, AV_LOG_DEBUG, "%s = '0x", key);
1223
+            for (j = 0; j < len; j++)
1224
+                av_log(s, AV_LOG_DEBUG, "%X", avio_r8(pb));
1225
+            av_log(s, AV_LOG_DEBUG, "'\n");
1226
+        } else if (len == 4 && type == 3 && !strncmp(key, "StreamCount", tlen)) {
1227
+            nb_streams = value = avio_rb32(pb);
1228
+        } else if (len == 4 && type == 3) {
1229
+            value = avio_rb32(pb);
1230
+            av_log(s, AV_LOG_DEBUG, "%s = %d\n", key, value);
1231
+        } else {
1232
+            av_log(s, AV_LOG_DEBUG, "Skipping unsupported key: %s\n", key);
1233
+            avio_skip(pb, len);
1234
+        }
1235
+    }
1236
+
1237
+    for (n = 0; n < nb_streams; n++) {
1238
+        st = avformat_new_stream(s, NULL);
1239
+        if (!st)
1240
+            return AVERROR(ENOMEM);
1241
+        st->priv_data = ff_rm_alloc_rmstream();
1242
+        if (!st->priv_data)
1243
+            return AVERROR(ENOMEM);
1244
+
1245
+        if (avio_r8(pb) != 1)
1246
+            return AVERROR_INVALIDDATA;
1247
+
1248
+        count = avio_rb32(pb);
1249
+        for (i = 0; i < count; i++) {
1250
+            if (avio_feof(pb))
1251
+                return AVERROR_INVALIDDATA;
1252
+
1253
+            type = avio_r8(pb);
1254
+            tlen  = avio_rb32(pb);
1255
+            avio_get_str(pb, tlen, key, sizeof(key));
1256
+            len  = avio_rb32(pb);
1257
+            if (type == 5) {
1258
+                avio_get_str(pb, len, val, sizeof(val));
1259
+                av_log(s, AV_LOG_DEBUG, "%s = '%s'\n", key, val);
1260
+            } else if (type == 4 && !strncmp(key, "OpaqueData", tlen)) {
1261
+                ret = ffio_ensure_seekback(pb, 4);
1262
+                if (ret < 0)
1263
+                    return ret;
1264
+                if (avio_rb32(pb) == MKBETAG('M', 'L', 'T', 'I')) {
1265
+                    ret = rm_read_multi(s, pb, st, NULL);
1266
+                } else {
1267
+                    avio_seek(pb, -4, SEEK_CUR);
1268
+                    ret = ff_rm_read_mdpr_codecdata(s, pb, st, st->priv_data, len, NULL);
1269
+                }
1270
+
1271
+                if (ret < 0)
1272
+                    return ret;
1273
+            } else if (type == 4) {
1274
+                int j;
1275
+
1276
+                av_log(s, AV_LOG_DEBUG, "%s = '0x", key);
1277
+                for (j = 0; j < len; j++)
1278
+                    av_log(s, AV_LOG_DEBUG, "%X", avio_r8(pb));
1279
+                av_log(s, AV_LOG_DEBUG, "'\n");
1280
+            } else if (len == 4 && type == 3 && !strncmp(key, "Duration", tlen)) {
1281
+                st->duration = avio_rb32(pb);
1282
+            } else if (len == 4 && type == 3) {
1283
+                value = avio_rb32(pb);
1284
+                av_log(s, AV_LOG_DEBUG, "%s = %d\n", key, value);
1285
+            } else {
1286
+                av_log(s, AV_LOG_DEBUG, "Skipping unsupported key: %s\n", key);
1287
+                avio_skip(pb, len);
1288
+            }
1289
+        }
1290
+    }
1291
+
1292
+    if (avio_r8(pb) != 6)
1293
+        return AVERROR_INVALIDDATA;
1294
+    avio_skip(pb, 12);
1295
+    avio_skip(pb, avio_rb64(pb) + pos - avio_tell(s->pb));
1296
+    if (avio_r8(pb) != 8)
1297
+        return AVERROR_INVALIDDATA;
1298
+    avio_skip(pb, 8);
1299
+
1300
+    return 0;
1301
+}
1302
+
1303
+static int ivr_read_packet(AVFormatContext *s, AVPacket *pkt)
1304
+{
1305
+    RMDemuxContext *rm = s->priv_data;
1306
+    int ret = AVERROR_EOF, opcode;
1307
+    AVIOContext *pb = s->pb;
1308
+    unsigned size, index;
1309
+    int64_t pos, pts;
1310
+
1311
+    if (avio_feof(pb) || rm->data_end)
1312
+        return AVERROR_EOF;
1313
+
1314
+    pos = avio_tell(pb);
1315
+
1316
+    for (;;) {
1317
+        if (rm->audio_pkt_cnt) {
1318
+            // If there are queued audio packet return them first
1319
+            AVStream *st;
1320
+
1321
+            st = s->streams[rm->audio_stream_num];
1322
+            ret = ff_rm_retrieve_cache(s, pb, st, st->priv_data, pkt);
1323
+            if (ret < 0) {
1324
+                return ret;
1325
+            }
1326
+        } else {
1327
+            if (rm->remaining_len) {
1328
+                avio_skip(pb, rm->remaining_len);
1329
+                rm->remaining_len = 0;
1330
+            }
1331
+
1332
+            if (avio_feof(pb))
1333
+                return AVERROR_EOF;
1334
+
1335
+            opcode = avio_r8(pb);
1336
+            if (opcode == 2) {
1337
+                AVStream *st;
1338
+                int seq = 1;
1339
+
1340
+                pts = avio_rb32(pb);
1341
+                index = avio_rb16(pb);
1342
+                if (index >= s->nb_streams)
1343
+                    return AVERROR_INVALIDDATA;
1344
+
1345
+                avio_skip(pb, 4);
1346
+                size = avio_rb32(pb);
1347
+                avio_skip(pb, 4);
1348
+
1349
+                st = s->streams[index];
1350
+                ret = ff_rm_parse_packet(s, pb, st, st->priv_data, size, pkt,
1351
+                                         &seq, 0, pts);
1352
+                if (ret < -1) {
1353
+                    return ret;
1354
+                } else if (ret) {
1355
+                    continue;
1356
+                }
1357
+
1358
+                pkt->pos = pos;
1359
+                pkt->pts = pts;
1360
+                pkt->stream_index = index;
1361
+            } else if (opcode == 7) {
1362
+                pos = avio_rb64(pb);
1363
+                if (!pos) {
1364
+                    rm->data_end = 1;
1365
+                    return AVERROR_EOF;
1366
+                }
1367
+            } else {
1368
+                av_log(s, AV_LOG_ERROR, "Unsupported opcode=%d at %lX\n", opcode, avio_tell(pb) - 1);
1369
+                return AVERROR(EIO);
1370
+            }
1371
+        }
1372
+
1373
+        break;
1374
+    }
1375
+
1376
+    return ret;
1377
+}
1378
+
1379
+AVInputFormat ff_ivr_demuxer = {
1380
+    .name           = "ivr",
1381
+    .long_name      = NULL_IF_CONFIG_SMALL("IVR (Internet Video Recording)"),
1382
+    .priv_data_size = sizeof(RMDemuxContext),
1383
+    .read_probe     = ivr_probe,
1384
+    .read_header    = ivr_read_header,
1385
+    .read_packet    = ivr_read_packet,
1386
+    .extensions     = "ivr",
1387
+};
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR  57
33
-#define LIBAVFORMAT_VERSION_MINOR  14
33
+#define LIBAVFORMAT_VERSION_MINOR  15
34 34
 #define LIBAVFORMAT_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \