[FFmpeg-devel] [PATCH 1/4] avformat: Add and use helper function to add attachment streams

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Tue Mar 30 16:45:27 EEST 2021


James Almer:
> On 3/29/2021 5:42 AM, Andreas Rheinhardt wrote:
>> All instances of adding attached pictures to a stream or adding
>> a stream and an attached packet to said stream have several things
>> in common like setting the index and flags of the packet, setting
>> the stream disposition etc. This commit therefore factors this out.
>>
>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>
>> ---
>> I always pondered factoring this out; James' proposal made me do it.
>>
>>   libavformat/apetag.c       | 10 +---------
>>   libavformat/flac_picture.c | 17 ++++-------------
>>   libavformat/id3v2.c        | 21 ++++++---------------
>>   libavformat/internal.h     | 13 +++++++++++++
>>   libavformat/matroskadec.c  | 15 +++------------
>>   libavformat/mov.c          | 25 +++++++------------------
>>   libavformat/utils.c        | 30 ++++++++++++++++++++++++++++++
>>   libavformat/wtvdec.c       | 12 ++----------
>>   8 files changed, 66 insertions(+), 77 deletions(-)
>>
>> diff --git a/libavformat/apetag.c b/libavformat/apetag.c
>> index 23ee6b516d..6f82fbe202 100644
>> --- a/libavformat/apetag.c
>> +++ b/libavformat/apetag.c
>> @@ -79,20 +79,12 @@ static int ape_tag_read_field(AVFormatContext *s)
>>           av_dict_set(&st->metadata, key, filename, 0);
>>             if ((id = ff_guess_image2_codec(filename)) !=
>> AV_CODEC_ID_NONE) {
>> -            int ret;
>> -
>> -            ret = av_get_packet(s->pb, &st->attached_pic, size);
>> +            int ret = ff_add_attached_pic(s, st, s->pb, NULL, size);
>>               if (ret < 0) {
>>                   av_log(s, AV_LOG_ERROR, "Error reading cover art.\n");
>>                   return ret;
>>               }
>> -
>> -            st->disposition      |= AV_DISPOSITION_ATTACHED_PIC;
>> -            st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>>               st->codecpar->codec_id   = id;
>> -
>> -            st->attached_pic.stream_index = st->index;
>> -            st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
>>           } else {
>>               if ((ret = ff_get_extradata(s, st->codecpar, s->pb,
>> size)) < 0)
>>                   return ret;
>> diff --git a/libavformat/flac_picture.c b/libavformat/flac_picture.c
>> index f15cfa877a..96e14f76c9 100644
>> --- a/libavformat/flac_picture.c
>> +++ b/libavformat/flac_picture.c
>> @@ -160,20 +160,11 @@ int ff_flac_parse_picture(AVFormatContext *s,
>> uint8_t *buf, int buf_size, int tr
>>       if (AV_RB64(data->data) == PNGSIG)
>>           id = AV_CODEC_ID_PNG;
>>   -    st = avformat_new_stream(s, NULL);
>> -    if (!st) {
>> -        RETURN_ERROR(AVERROR(ENOMEM));
>> -    }
>> -
>> -    av_packet_unref(&st->attached_pic);
>> -    st->attached_pic.buf          = data;
>> -    st->attached_pic.data         = data->data;
>> -    st->attached_pic.size         = len;
>> -    st->attached_pic.stream_index = st->index;
>> -    st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
>> +    ret = ff_add_attached_pic(s, NULL, NULL, &data, 0);
>> +    if (ret < 0)
>> +        RETURN_ERROR(ret);
>>   -    st->disposition      |= AV_DISPOSITION_ATTACHED_PIC;
>> -    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>> +    st = s->streams[s->nb_streams - 1];
>>       st->codecpar->codec_id   = id;
>>       st->codecpar->width      = width;
>>       st->codecpar->height     = height;
>> diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
>> index f33b7ba93a..863709abbf 100644
>> --- a/libavformat/id3v2.c
>> +++ b/libavformat/id3v2.c
>> @@ -1142,34 +1142,25 @@ int ff_id3v2_parse_apic(AVFormatContext *s,
>> ID3v2ExtraMeta *extra_meta)
>>       for (cur = extra_meta; cur; cur = cur->next) {
>>           ID3v2ExtraMetaAPIC *apic;
>>           AVStream *st;
>> +        int ret;
>>             if (strcmp(cur->tag, "APIC"))
>>               continue;
>>           apic = &cur->data.apic;
>>   -        if (!(st = avformat_new_stream(s, NULL)))
>> -            return AVERROR(ENOMEM);
>> -
>> -        st->disposition      |= AV_DISPOSITION_ATTACHED_PIC;
>> -        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>> +        ret = ff_add_attached_pic(s, NULL, NULL, &apic->buf, 0);
>> +        if (ret < 0)
>> +            return ret;
>> +        st  = s->streams[s->nb_streams - 1];
>>           st->codecpar->codec_id   = apic->id;
>>   -        if (AV_RB64(apic->buf->data) == PNGSIG)
>> +        if (AV_RB64(st->attached_pic.data) == PNGSIG)
>>               st->codecpar->codec_id = AV_CODEC_ID_PNG;
>>             if (apic->description[0])
>>               av_dict_set(&st->metadata, "title", apic->description, 0);
>>             av_dict_set(&st->metadata, "comment", apic->type, 0);
>> -
>> -        av_packet_unref(&st->attached_pic);
>> -        st->attached_pic.buf          = apic->buf;
>> -        st->attached_pic.data         = apic->buf->data;
>> -        st->attached_pic.size         = apic->buf->size -
>> AV_INPUT_BUFFER_PADDING_SIZE;
>> -        st->attached_pic.stream_index = st->index;
>> -        st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
>> -
>> -        apic->buf = NULL;
>>       }
>>         return 0;
>> diff --git a/libavformat/internal.h b/libavformat/internal.h
>> index 8631694d00..b3c5d8a1d5 100644
>> --- a/libavformat/internal.h
>> +++ b/libavformat/internal.h
>> @@ -669,6 +669,19 @@ int ff_framehash_write_header(AVFormatContext *s);
>>    */
>>   int ff_read_packet(AVFormatContext *s, AVPacket *pkt);
>>   +/**
>> + * Add an attached pic to an AVStream.
>> + *
>> + * @param st   if set, the stream to add the attached pic to;
>> + *             if unset, a new stream will be added to s.
>> + * @param pb   AVIOContext to read data from if buf is unset.
>> + * @param buf  if set, it contains the data and size information to
>> be used
>> + *             for the attached pic; if unset, data is read from pb.
>> + * @param size the size of the data to read if buf is unset.
>> + */
>> +int ff_add_attached_pic(AVFormatContext *s, AVStream *st, AVIOContext
>> *pb,
>> +                        AVBufferRef **buf, int size);
>> +
>>   /**
>>    * Interleave an AVPacket per dts so it can be muxed.
>>    *
>> diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
>> index 1dc188c946..e8c76f9cfb 100644
>> --- a/libavformat/matroskadec.c
>> +++ b/libavformat/matroskadec.c
>> @@ -3007,18 +3007,9 @@ static int matroska_read_header(AVFormatContext
>> *s)
>>               attachments[j].stream = st;
>>                 if (st->codecpar->codec_id != AV_CODEC_ID_NONE) {
>> -                AVPacket *pkt = &st->attached_pic;
>> -
>> -                st->disposition         |= AV_DISPOSITION_ATTACHED_PIC;
>> -                st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>> -
>> -                av_packet_unref(pkt);
>> -                pkt->buf          = attachments[j].bin.buf;
>> -                attachments[j].bin.buf = NULL;
>> -                pkt->data         = attachments[j].bin.data;
>> -                pkt->size         = attachments[j].bin.size;
>> -                pkt->stream_index = st->index;
>> -                pkt->flags       |= AV_PKT_FLAG_KEY;
>> +                res = ff_add_attached_pic(s, st, NULL,
>> &attachments[j].bin.buf, 0);
>> +                if (res < 0)
>> +                    goto fail;
>>               } else {
>>                   st->codecpar->codec_type = AVMEDIA_TYPE_ATTACHMENT;
>>                   if (ff_alloc_extradata(st->codecpar,
>> attachments[j].bin.size))
>> diff --git a/libavformat/mov.c b/libavformat/mov.c
>> index cb818ebe0e..097aa2bfb2 100644
>> --- a/libavformat/mov.c
>> +++ b/libavformat/mov.c
>> @@ -196,17 +196,16 @@ static int mov_read_covr(MOVContext *c,
>> AVIOContext *pb, int type, int len)
>>           return 0;
>>       }
>>   -    st = avformat_new_stream(c->fc, NULL);
>> -    if (!st)
>> -        return AVERROR(ENOMEM);
>>       sc = av_mallocz(sizeof(*sc));
>>       if (!sc)
>>           return AVERROR(ENOMEM);
>> -    st->priv_data = sc;
>> -
>> -    ret = av_get_packet(pb, &st->attached_pic, len);
>> -    if (ret < 0)
>> +    ret = ff_add_attached_pic(c->fc, NULL, pb, NULL, len);
>> +    if (ret < 0) {
>> +        av_free(sc);
>>           return ret;
>> +    }
>> +    st = c->fc->streams[c->fc->nb_streams - 1];
>> +    st->priv_data = sc;
>>         if (st->attached_pic.size >= 8 && id != AV_CODEC_ID_BMP) {
>>           if (AV_RB64(st->attached_pic.data) == 0x89504e470d0a1a0a) {
>> @@ -215,13 +214,6 @@ static int mov_read_covr(MOVContext *c,
>> AVIOContext *pb, int type, int len)
>>               id = AV_CODEC_ID_MJPEG;
>>           }
>>       }
>> -
>> -    st->disposition              |= AV_DISPOSITION_ATTACHED_PIC;
>> -
>> -    st->attached_pic.stream_index = st->index;
>> -    st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
>> -
>> -    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>>       st->codecpar->codec_id   = id;
>>         return 0;
>> @@ -7229,11 +7221,8 @@ static void mov_read_chapters(AVFormatContext *s)
>>                       goto finish;
>>                   }
>>   -                if (av_get_packet(sc->pb, &st->attached_pic,
>> sample->size) < 0)
>> +                if (ff_add_attached_pic(s, st, sc->pb, NULL,
>> sample->size) < 0)
>>                       goto finish;
>> -
>> -                st->attached_pic.stream_index = st->index;
>> -                st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
>>               }
>>           } else {
>>               st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
>> diff --git a/libavformat/utils.c b/libavformat/utils.c
>> index 88f6f18f1f..2bd7dd8ec7 100644
>> --- a/libavformat/utils.c
>> +++ b/libavformat/utils.c
>> @@ -474,6 +474,36 @@ int
>> avformat_queue_attached_pictures(AVFormatContext *s)
>>       return 0;
>>   }
>>   +int ff_add_attached_pic(AVFormatContext *s, AVStream *st,
>> AVIOContext *pb,
>> +                        AVBufferRef **buf, int size)
>> +{
>> +    AVPacket *pkt;
>> +    int ret;
>> +
>> +    if (!st && !(st = avformat_new_stream(s, NULL)))
>> +        return AVERROR(ENOMEM);
>> +    pkt = &st->attached_pic;
>> +    if (buf) {
>> +        av_assert1(*buf);
> 
> The code below is going to crash as soon as *buf is dereferenced if it's
> NULL, so unless this is changed to av_assert0(), adding this seems
> pointless.

I disagree: It more directly conveys to every reader that the case of
(buf && !*buf) is illegal.

> 
>> +        av_packet_unref(pkt);
>> +        pkt->buf  = *buf;
>> +        pkt->data = (*buf)->data;
>> +        pkt->size = (*buf)->size - AV_INPUT_BUFFER_PADDING_SIZE;
> 
> I suppose all buffers were allocated with padding, right? (I see
> matroskadec did, but didn't take it into account when setting pkt->size,
> which this patch here fixes).
> 

Not true: ebml_read_binary() sets EbmlBin.size to the size without
padding, whereas EbmlBin.buf->size gets set to the size + padding. The
current code in matroskadec.c uses EbmlBin.size, the code above uses the
size inferred from the AVBufferRef (as the id3v2 code already does).
flac_picture is the third user providing an AVBufferRef; it also adds
padding.

>> +        *buf = NULL;
>> +    } else {
>> +        ret = av_get_packet(pb, pkt, size);
>> +        if (ret < 0)
>> +            return ret;
>> +    }
>> +    st->disposition         |= AV_DISPOSITION_ATTACHED_PIC;
>> +    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>> +
>> +    pkt->stream_index = st->index;
>> +    pkt->flags       |= AV_PKT_FLAG_KEY;
>> +
>> +    return 0;
>> +}
>> +
>>   static int update_stream_avctx(AVFormatContext *s)
>>   {
>>       int i, ret;
>> diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c
>> index 7def9d2348..e67e03a033 100644
>> --- a/libavformat/wtvdec.c
>> +++ b/libavformat/wtvdec.c
>> @@ -434,7 +434,6 @@ static void get_attachment(AVFormatContext *s,
>> AVIOContext *pb, int length)
>>       char description[1024];
>>       unsigned int filesize;
>>       AVStream *st;
>> -    int ret;
>>       int64_t pos = avio_tell(pb);
>>         avio_get_str16le(pb, INT_MAX, mime, sizeof(mime));
>> @@ -447,19 +446,12 @@ static void get_attachment(AVFormatContext *s,
>> AVIOContext *pb, int length)
>>       if (!filesize)
>>           goto done;
>>   -    st = avformat_new_stream(s, NULL);
>> -    if (!st)
>> +    if (ff_add_attached_pic(s, NULL, pb, NULL, filesize) < 0)
>>           goto done;
>> +    st = s->streams[s->nb_streams - 1];
>>       av_dict_set(&st->metadata, "title", description, 0);
>> -    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>>       st->codecpar->codec_id   = AV_CODEC_ID_MJPEG;
>>       st->id = -1;
>> -    ret = av_get_packet(pb, &st->attached_pic, filesize);
>> -    if (ret < 0)
>> -        goto done;
>> -    st->attached_pic.stream_index = st->index;
>> -    st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
>> -    st->disposition              |= AV_DISPOSITION_ATTACHED_PIC;
>>   done:
>>       avio_seek(pb, pos + length, SEEK_SET);
>>   }
> 
> Should be ok.
> _______________________________________________
> 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