On 11/16/15, Paul B Mahol <one...@gmail.com> wrote: > On 11/16/15, Michael Niedermayer <mich...@niedermayer.cc> wrote: >> On Mon, Nov 16, 2015 at 11:25:33AM +0100, Paul B Mahol wrote: >>> 2n version attached >> >>> Makefile | 1 >>> allformats.c | 1 >>> rmdec.c | 303 >>> ++++++++++++++++++++++++++++++++++++++++++++++++++++------- >>> 3 files changed, 271 insertions(+), 34 deletions(-) >>> f8930413dadf24053ff1e19ebbacf90ae801f7d0 >>> 0001-avformat-add-IVR-demuxer.patch >>> From bada349bdba599b92bcb1d3bc16b630c182174f9 Mon Sep 17 00:00:00 2001 >>> From: Paul B Mahol <one...@gmail.com> >>> Date: Wed, 11 Nov 2015 22:04:57 +0100 >>> Subject: [PATCH] avformat: add IVR demuxer >>> >>> Signed-off-by: Paul B Mahol <one...@gmail.com> >>> --- >>> >>> Problem with slices/frames ending in middle of packet is still there. >>> >>> Reproducible with Opener_rm_hi.ivr >>> >>> --- >>> libavformat/Makefile | 1 + >>> libavformat/allformats.c | 1 + >>> libavformat/rmdec.c | 303 >>> +++++++++++++++++++++++++++++++++++++++++------ >>> 3 files changed, 271 insertions(+), 34 deletions(-) >>> >>> diff --git a/libavformat/Makefile b/libavformat/Makefile >>> index bdfe35c..e3f19dd 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 73b1e4a..9ac40c5 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..21e8ec5 100644 >>> --- a/libavformat/rmdec.c >>> +++ b/libavformat/rmdec.c >>> @@ -63,6 +63,7 @@ typedef struct RMDemuxContext { >>> int remaining_len; >>> int audio_stream_num; ///< Stream number for audio packets >>> int audio_pkt_cnt; ///< Output packet counter >>> + int data_end; >>> } RMDemuxContext; >>> >>> static int rm_read_close(AVFormatContext *s); >>> @@ -488,6 +489,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 +621,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 +1166,227 @@ 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, type, len, tlen, value; >>> + int i, j, n, count, nb_streams, ret; >>> + uint8_t key[256], val[256]; >>> + AVIOContext *pb = s->pb; >>> + AVStream *st; >>> + int64_t pos, offset, temp; >>> + >>> + 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, 5); >>> + temp = avio_rb64(pb); >>> + while (!avio_feof(pb) && temp) { >>> + offset = temp; >>> + temp = avio_rb64(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) != 2) >>> + return AVERROR_INVALIDDATA; >>> + avio_skip(pb, 16); >>> + pos = avio_tell(pb); >>> + tag = avio_rl32(pb); >>> + } >>> + >>> + 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++) { >> >> there should be a eof check in the loop somewhere to avoid iterating >> at the end for 2^31-1 times > > done and done. >> >> >>> + 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)); >>> + av_log(s, AV_LOG_DEBUG, "%s = '%s'\n", key, val); >>> + } else if (type == 4) { >>> + av_log(s, AV_LOG_DEBUG, "%s = '0x", key); >>> + for (j = 0; j < len; j++) >>> + av_log(s, AV_LOG_DEBUG, "%X", avio_r8(pb)); >>> + av_log(s, AV_LOG_DEBUG, "'\n"); >>> + } 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); >>> + av_log(s, AV_LOG_DEBUG, "%s = %d\n", key, value); >>> + } else { >>> + av_log(s, AV_LOG_DEBUG, "Skipping unsupported key: %s\n", >>> key); >>> + avio_skip(pb, len); >>> + } >>> + } >>> + >>> + 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) >>> + 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)); >>> + av_log(s, AV_LOG_DEBUG, "%s = '%s'\n", key, val); >>> + } else if (type == 4 && !strncmp(key, "OpaqueData", tlen)) >>> { >>> + ret = ffio_ensure_seekback(pb, 4); >>> + if (ret < 0) >>> + return ret; >>> + 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) { >>> + int j; >>> + >>> + av_log(s, AV_LOG_DEBUG, "%s = '0x", key); >>> + for (j = 0; j < len; j++) >>> + av_log(s, AV_LOG_DEBUG, "%X", avio_r8(pb)); >>> + av_log(s, AV_LOG_DEBUG, "'\n"); >>> + } else if (len == 4 && type == 3 && !strncmp(key, >>> "Duration", >>> tlen)) { >>> + st->duration = avio_rb32(pb); >>> + } else if (len == 4 && type == 3) { >>> + value = avio_rb32(pb); >>> + av_log(s, AV_LOG_DEBUG, "%s = %d\n", key, value); >>> + } else { >>> + av_log(s, AV_LOG_DEBUG, "Skipping unsupported key: >>> %s\n", >>> key); >>> + avio_skip(pb, len); >>> + } >>> + } >>> + } >>> + >>> + 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) || rm->data_end) >>> + 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]; >> >> index should be checked before use > > checked. > >> >> >>> + 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 if (opcode == 7) { >>> + pos = avio_rb64(pb); >>> + if (!pos) { >>> + rm->data_end = 1; >>> + return AVERROR_EOF; >>> + } else { >>> + avio_seek(pb, pos, SEEK_SET); >>> + continue; >> >> can this cause infinite loops with seeking back ? >> > > removed. > >> [...] >> >> -- >> Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB >> >> The worst form of inequality is to try to make unequal things equal. >> -- Aristotle >> >
If there are no more comments I will apply this soon. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel