[FFmpeg-devel] [SCISYS Possible Spam] Re: [PATCH] Patch for memory optimization with QuickTime/MP4

Jörg Beckmann Joerg.Beckmann at scisys.com
Mon Dec 2 12:05:52 EET 2019


The for-loop and the warning are copied from somewhere else in the decoder. I'm also quite sure that it cannot really happen. 

One cannot set the option to discard old frames and also try to seek. I did not manage to create an example with calls to switch_root while reading from a file. But if it is possible somehow and the option is set, there are no old fragments to seek in. Therefore I think, seek should be forbidden if the option is set.

Cheers,
Jörg

-----Ursprüngliche Nachricht-----
Von: ffmpeg-devel <ffmpeg-devel-bounces at ffmpeg.org> Im Auftrag von Carl Eugen Hoyos
Gesendet: Montag, 2. Dezember 2019 10:15
An: FFmpeg development discussions and patches <ffmpeg-devel at ffmpeg.org>
Betreff: [SCISYS Possible Spam] Re: [FFmpeg-devel] [PATCH] Patch for memory optimization with QuickTime/MP4

Am Mo., 2. Dez. 2019 um 10:05 Uhr schrieb Jörg Beckmann
<Joerg.Beckmann at scisys.com>:
>
> Hi,
>
> this patch invents a new option "discard_fragments" for the MP4/Quicktime/MOV decoder. If the option is not set, nothing changes at all. If it is set, old fragments are discarded as far as possible on each call to switch_root. For pure audio streams, the memory usage is now constant. For video streams, the memory usage is reduced. I've tested it with audio streams received from a professional DAB+ receiver and with video streams created on my own with "ffmpeg -i <video>.m4v -c:a:0 copy -c:v copy -c:s copy -f ismv -movflags frag_keyframe -movflags faststart tcp://localhost:1234?listen" and "ffmpeg -i tcp://localhost:1234 -c:a copy -c:v copy -c:s copy -y <output>". Does someone know sources for MP4 video streams? I could not find any with more than a few minutes. That's not sufficient to test memory usage.
>
> Cheers,
> Jörg
> ---
> libavformat/isom.h |  1 +
> libavformat/mov.c  | 52 +++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 52 insertions(+), 1 deletion(-)
>
> diff --git a/libavformat/isom.h b/libavformat/isom.h index 
> 4943b80ccf..9b4753f4d7 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -268,6 +268,7 @@ typedef struct MOVContext {
>      int advanced_editlist;
>      int ignore_chapters;
>      int seek_individually;
> +    int discard_fragments;
>      int64_t next_root_atom; ///< offset of the next root atom
>      int export_all;
>      int export_xmp;
> diff --git a/libavformat/mov.c b/libavformat/mov.c index 
> 7553a7fdfc..3a5cfa23f8 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -7698,8 +7698,11 @@ static int should_retry(AVIOContext *pb, int 
> error_code) {  static int mov_switch_root(AVFormatContext *s, int64_t 
> target, int index) {
> -    int ret;
> +    int ret, i;
>      MOVContext *mov = s->priv_data;
> +    AVStream *st = NULL;
> +    MOVStreamContext *sc;
> +    MOVFragment *frag;
>      if (index >= 0 && index < mov->frag_index.nb_items)
>          target = mov->frag_index.item[index].moof_offset;
> @@ -7721,6 +7724,46 @@ static int mov_switch_root(AVFormatContext *s, int64_t target, int index)
>      mov->found_mdat = 0;
> +    if (mov->discard_fragments) {
> +        frag = &mov->fragment;
> +
> +        for (i = 0; i < mov->fc->nb_streams; i++) {
> +            if (mov->fc->streams[i]->id == frag->track_id) {
> +                st = mov->fc->streams[i];
> +                break;
> +            }
> +        }
> +

> +        if (!st) {
> +            av_log(mov->fc, AV_LOG_WARNING, "could not find 
> + corresponding track id %u\n", frag->track_id);

How can this happen?

> +        } else {
> +            sc = st->priv_data;
> +
> +            switch (st->codecpar->codec_type) {
> +                case AVMEDIA_TYPE_AUDIO:
> +                case AVMEDIA_TYPE_SUBTITLE:
> +                    /* Freeing VIDEO tables leads to corrupted video when writing to eg. MKV */
> +                    av_freep(&st->index_entries);
> +                    st->nb_index_entries = 0;
> +                    st->index_entries_allocated_size = 0;
> +
> +                    sc->current_index = 0;
> +                    sc->current_sample = 0;
> +
> +                    av_freep(&sc->ctts_data);
> +                    sc->ctts_data = NULL;
> +                    sc->ctts_allocated_size = 0;
> +                    sc->ctts_count = 0;
> +                    break;
> +            }
> +
> +            av_free(mov->frag_index.item->stream_info);
> +            av_freep(&mov->frag_index.item);
> +            mov->frag_index.allocated_size = 0;
> +            mov->frag_index.nb_items = 0;
> +        }
> +    }
> +
>      ret = mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX });
>      if (ret < 0)
>          return ret;
> @@ -7975,6 +8018,9 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
>      int sample;
>      int i;
> +    if (mc->discard_fragments)  // Seeking is not possible if fragments are discarded.
> +        return AVERROR(ENOTSUP);

I guess this is only true if the stream actually is fragmented.

> +
>      if (stream_index >= s->nb_streams)
>          return AVERROR_INVALIDDATA;
> @@ -8063,6 +8109,10 @@ static const AVOption mov_options[] = {
>      { "decryption_key", "The media decryption key (hex)", OFFSET(decryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
>      { "enable_drefs", "Enable external track support.", OFFSET(enable_drefs), AV_OPT_TYPE_BOOL,
>          {.i64 = 0}, 0, 1, FLAGS },
> +    {"discard_fragments",
> +            "Discards fragments after they have been read to support live streams.",
> +            OFFSET(discard_fragments), AV_OPT_TYPE_BOOL, { .i64 = 0 },
> +            0, 1, FLAGS },

Carl Eugen
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel at ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-devel mailing list