[FFmpeg-devel] [PATCH] avformat: add IVR demuxer
Paul B Mahol
onemda at gmail.com
Sun Nov 15 18:29:13 CET 2015
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
Frames/slices that ends in middle of packet do not currently work.
I have no idea why, so looking for help.
Different .R1M variant is not supported, working on it... but if you know
how to fix it speak up.
Useless comments/reviews are ignored.
---
libavformat/Makefile | 1 +
libavformat/allformats.c | 1 +
libavformat/rmdec.c | 284 +++++++++++++++++++++++++++++++++++++++++------
3 files changed, 252 insertions(+), 34 deletions(-)
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 1a03e0c..1645438 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -228,6 +228,7 @@ OBJS-$(CONFIG_ISS_DEMUXER) += iss.o
OBJS-$(CONFIG_IV8_DEMUXER) += iv8.o
OBJS-$(CONFIG_IVF_DEMUXER) += ivfdec.o
OBJS-$(CONFIG_IVF_MUXER) += ivfenc.o
+OBJS-$(CONFIG_IVR_DEMUXER) += rmdec.o rm.o rmsipr.o
OBJS-$(CONFIG_JACOSUB_DEMUXER) += jacosubdec.o subtitles.o
OBJS-$(CONFIG_JACOSUB_MUXER) += jacosubenc.o rawenc.o
OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 8b8d9f2..cc637df 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -169,6 +169,7 @@ void av_register_all(void)
REGISTER_DEMUXER (ISS, iss);
REGISTER_DEMUXER (IV8, iv8);
REGISTER_MUXDEMUX(IVF, ivf);
+ REGISTER_DEMUXER (IVR, ivr);
REGISTER_MUXDEMUX(JACOSUB, jacosub);
REGISTER_DEMUXER (JV, jv);
REGISTER_MUXER (LATM, latm);
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index 4ec78ef..f9c8b4f 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -488,6 +488,47 @@ static int rm_read_header_old(AVFormatContext *s)
return rm_read_audio_stream_info(s, s->pb, st, st->priv_data, 1);
}
+static int rm_read_multi(AVFormatContext *s, AVIOContext *pb,
+ AVStream *st, char *mime)
+{
+ int number_of_streams = avio_rb16(pb);
+ int number_of_mdpr;
+ int i, ret;
+ unsigned size2;
+ for (i = 0; i<number_of_streams; i++)
+ avio_rb16(pb);
+ number_of_mdpr = avio_rb16(pb);
+ if (number_of_mdpr != 1) {
+ avpriv_request_sample(s, "MLTI with multiple (%d) MDPR", number_of_mdpr);
+ }
+ for (i = 0; i < number_of_mdpr; i++) {
+ AVStream *st2;
+ if (i > 0) {
+ st2 = avformat_new_stream(s, NULL);
+ if (!st2) {
+ ret = AVERROR(ENOMEM);
+ return ret;
+ }
+ st2->id = st->id + (i<<16);
+ st2->codec->bit_rate = st->codec->bit_rate;
+ st2->start_time = st->start_time;
+ st2->duration = st->duration;
+ st2->codec->codec_type = AVMEDIA_TYPE_DATA;
+ st2->priv_data = ff_rm_alloc_rmstream();
+ if (!st2->priv_data)
+ return AVERROR(ENOMEM);
+ } else
+ st2 = st;
+
+ size2 = avio_rb32(pb);
+ ret = ff_rm_read_mdpr_codecdata(s, s->pb, st2, st2->priv_data,
+ size2, mime);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
static int rm_read_header(AVFormatContext *s)
{
RMDemuxContext *rm = s->priv_data;
@@ -579,40 +620,9 @@ static int rm_read_header(AVFormatContext *s)
ffio_ensure_seekback(pb, 4);
v = avio_rb32(pb);
if (v == MKBETAG('M', 'L', 'T', 'I')) {
- int number_of_streams = avio_rb16(pb);
- int number_of_mdpr;
- int i;
- unsigned size2;
- for (i = 0; i<number_of_streams; i++)
- avio_rb16(pb);
- number_of_mdpr = avio_rb16(pb);
- if (number_of_mdpr != 1) {
- avpriv_request_sample(s, "MLTI with multiple (%d) MDPR", number_of_mdpr);
- }
- for (i = 0; i < number_of_mdpr; i++) {
- AVStream *st2;
- if (i > 0) {
- st2 = avformat_new_stream(s, NULL);
- if (!st2) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- st2->id = st->id + (i<<16);
- st2->codec->bit_rate = st->codec->bit_rate;
- st2->start_time = st->start_time;
- st2->duration = st->duration;
- st2->codec->codec_type = AVMEDIA_TYPE_DATA;
- st2->priv_data = ff_rm_alloc_rmstream();
- if (!st2->priv_data)
- return AVERROR(ENOMEM);
- } else
- st2 = st;
-
- size2 = avio_rb32(pb);
- if (ff_rm_read_mdpr_codecdata(s, s->pb, st2, st2->priv_data,
- size2, mime) < 0)
- goto fail;
- }
+ ret = rm_read_multi(s, s->pb, st, mime);
+ if (ret < 0)
+ goto fail;
avio_seek(pb, codec_pos + size, SEEK_SET);
} else {
avio_skip(pb, -4);
@@ -1155,3 +1165,209 @@ AVInputFormat ff_rdt_demuxer = {
.read_close = rm_read_close,
.flags = AVFMT_NOFILE,
};
+
+static int ivr_probe(AVProbeData *p)
+{
+ if (memcmp(p->buf, ".R1M\x0\x1\x1", 7) &&
+ memcmp(p->buf, ".REC", 4))
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
+}
+
+static int ivr_read_header(AVFormatContext *s)
+{
+ unsigned tag, offset, type, len, tlen, value;
+ uint8_t key[256], val[256];
+ AVIOContext *pb = s->pb;
+ int i, n, count, nb_streams, ret;
+ AVStream *st;
+ int64_t pos;
+
+ pos = avio_tell(pb);
+ tag = avio_rl32(pb);
+ if (tag == MKTAG('.','R','1','M')) {
+ if (avio_rb16(pb) != 1)
+ return AVERROR_INVALIDDATA;
+ if (avio_r8(pb) != 1)
+ return AVERROR_INVALIDDATA;
+ len = avio_rb32(pb);
+ avio_skip(pb, len);
+ avio_skip(pb, 9);
+ offset = avio_rb32(pb);
+ avio_skip(pb, offset - avio_tell(pb));
+ if (avio_r8(pb) != 1)
+ return AVERROR_INVALIDDATA;
+ len = avio_rb32(pb);
+ avio_skip(pb, len);
+ if (avio_r8(pb) == 3) {
+ avio_skip(pb, 16);
+ pos = avio_tell(pb);
+ tag = avio_rl32(pb);
+ if (tag == MKTAG('.','R','E','C')) {
+ goto done;
+ }
+ avio_seek(pb, -20, SEEK_CUR);
+ }
+ len = avio_rb32(pb);
+ avio_skip(pb, len);
+ if (avio_r8(pb) != 1)
+ return AVERROR_INVALIDDATA;
+ len = avio_rb32(pb);
+ avio_skip(pb, len);
+ avio_skip(pb, 17);
+ pos = avio_tell(pb);
+ tag = avio_rl32(pb);
+ }
+done:
+ if (tag != MKTAG('.','R','E','C'))
+ return AVERROR_INVALIDDATA;
+
+ if (avio_r8(pb) != 0)
+ return AVERROR_INVALIDDATA;
+ count = avio_rb32(pb);
+ for (i = 0; i < count; i++) {
+ type = avio_r8(pb);
+ tlen = avio_rb32(pb);
+ avio_get_str(pb, tlen, key, sizeof(key));
+ len = avio_rb32(pb);
+ if (type == 5) {
+ avio_get_str(pb, len, val, sizeof(val));
+ } else if (type == 4) {
+ avio_skip(pb, len);
+ } else if (len == 4 && type == 3 && !strncmp(key, "StreamCount", tlen)) {
+ nb_streams = value = avio_rb32(pb);
+ } else if (len == 4 && type == 3) {
+ value = avio_rb32(pb);
+ } else {
+ printf("XXX %s\n", key);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ for (n = 0; n < nb_streams; n++) {
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->priv_data = ff_rm_alloc_rmstream();
+ if (!st->priv_data)
+ return AVERROR(ENOMEM);
+
+ if (avio_r8(pb) == 1) {
+ count = avio_rb32(pb);
+ for (i = 0; i < count; i++) {
+ type = avio_r8(pb);
+ tlen = avio_rb32(pb);
+ avio_get_str(pb, tlen, key, sizeof(key));
+ len = avio_rb32(pb);
+ if (type == 5) {
+ avio_get_str(pb, len, val, sizeof(val));
+ } else if (type == 4 && !strncmp(key, "OpaqueData", tlen)) {
+ ffio_ensure_seekback(pb, 4);
+ if (avio_rb32(pb) == MKBETAG('M', 'L', 'T', 'I')) {
+ ret = rm_read_multi(s, pb, st, NULL);
+ } else {
+ avio_seek(pb, -4, SEEK_CUR);
+ ret = ff_rm_read_mdpr_codecdata(s, pb, st, st->priv_data, len, NULL);
+ }
+
+ if (ret < 0)
+ return ret;
+ } else if (type == 4) {
+ avio_skip(pb, len);
+ } else if (len == 4 && type == 3) {
+ value = avio_rb32(pb);
+ } else {
+ printf("%s\n", key);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+ }
+
+ if (avio_r8(pb) != 6)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 12);
+ avio_skip(pb, avio_rb64(pb) + pos - avio_tell(s->pb));
+ if (avio_r8(pb) != 8)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 8);
+
+ return 0;
+}
+
+static int ivr_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ RMDemuxContext *rm = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int index, ret = AVERROR_EOF, opcode;
+ int64_t pos, pts;
+ unsigned size;
+
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+
+ pos = avio_tell(pb);
+
+ for (;;) {
+ if (rm->audio_pkt_cnt) {
+ // If there are queued audio packet return them first
+ AVStream *st;
+
+ st = s->streams[rm->audio_stream_num];
+ ret = ff_rm_retrieve_cache(s, pb, st, st->priv_data, pkt);
+ if (ret < 0) {
+ return ret;
+ }
+ } else {
+ if (rm->remaining_len) {
+ avio_skip(pb, rm->remaining_len);
+ rm->remaining_len = 0;
+ }
+ opcode = avio_r8(pb);
+ if (opcode == 2) {
+ AVStream *st;
+ int seq = 0;
+
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+
+ pts = avio_rb32(pb);
+ index = avio_rb16(pb);
+ avio_skip(pb, 4);
+ size = avio_rb32(pb);
+ avio_skip(pb, 4);
+
+ st = s->streams[index];
+ ret = ff_rm_parse_packet(s, pb, st, st->priv_data, size, pkt,
+ &seq, 0, pts);
+ if (ret < -1) {
+ return ret;
+ } else if (ret) {
+ continue;
+ }
+
+ pkt->pos = pos;
+ pkt->pts = pts;
+ pkt->stream_index = index;
+ } else {
+ printf("%d %lX\n", opcode, avio_tell(pb));
+ return AVERROR(EIO);
+ }
+ }
+
+ break;
+ }
+
+ return ret;
+}
+
+AVInputFormat ff_ivr_demuxer = {
+ .name = "ivr",
+ .long_name = NULL_IF_CONFIG_SMALL("IVR (Internet Video Recording)"),
+ .priv_data_size = sizeof(RMDemuxContext),
+ .read_probe = ivr_probe,
+ .read_header = ivr_read_header,
+ .read_packet = ivr_read_packet,
+ .extensions = "ivr",
+};
--
1.9.1
More information about the ffmpeg-devel
mailing list