Signed-off-by: Paul B Mahol <onemda@gmail.com>
Paul B Mahol authored on 2015/11/12 06:04:57... | ... |
@@ -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, \ |