diff mbox series

[FFmpeg-devel] avformat/mov: Add support for still image AVIF parsing

Message ID 20220419205704.3548965-1-vigneshv@google.com
State New
Headers show
Series [FFmpeg-devel] avformat/mov: Add support for still image AVIF parsing | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_armv7_RPi4 success Make finished
andriy/make_fate_armv7_RPi4 success Make fate finished

Commit Message

Vignesh Venkatasubramanian April 19, 2022, 8:57 p.m. UTC
Add support for parsing AVIF still images. This patches supports
AVIF still images that have exactly 1 item (i.e.) no alpha channel.
Essentially, we will have to parse the "iloc" box and populate
the mov index.

With this patch, we can decode still AVIF images like so:
ffmpeg -i image.avif image.png

Partially fixes trac ticket #7621

Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
---
 libavformat/isom.h |   1 +
 libavformat/mov.c  | 137 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 138 insertions(+)

Comments

Paul B Mahol April 19, 2022, 9:19 p.m. UTC | #1
On Tue, Apr 19, 2022 at 10:57 PM Vignesh Venkatasubramanian <
vigneshv-at-google.com@ffmpeg.org> wrote:

> Add support for parsing AVIF still images. This patches supports
> AVIF still images that have exactly 1 item (i.e.) no alpha channel.
> Essentially, we will have to parse the "iloc" box and populate
> the mov index.
>
> With this patch, we can decode still AVIF images like so:
> ffmpeg -i image.avif image.png
>
> Partially fixes trac ticket #7621
>

LGTM


>
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
>  libavformat/isom.h |   1 +
>  libavformat/mov.c  | 137 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 138 insertions(+)
>
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index 5caf42b15d..02d681e3ae 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -315,6 +315,7 @@ typedef struct MOVContext {
>      int have_read_mfra_size;
>      uint32_t mfra_size;
>      uint32_t max_stts_delta;
> +    int is_still_picture_avif;
>  } MOVContext;
>
>  int ff_mp4_read_descr_len(AVIOContext *pb);
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 6c847de164..e925690584 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -1136,6 +1136,7 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext
> *pb, MOVAtom atom)
>          c->isom = 1;
>      av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand:
> %.4s\n",(char *)&type);
>      av_dict_set(&c->fc->metadata, "major_brand", type, 0);
> +    c->is_still_picture_avif = !strncmp(type, "avif", 4);
>      minor_ver = avio_rb32(pb); /* minor version */
>      av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
>
> @@ -7430,6 +7431,141 @@ static int mov_read_SAND(MOVContext *c,
> AVIOContext *pb, MOVAtom atom)
>      return 0;
>  }
>
> +static int rb_size(AVIOContext *pb, uint64_t* value, int size)
> +{
> +    if (size == 0)
> +        *value = 0;
> +    else if (size == 1)
> +        *value = avio_r8(pb);
> +    else if (size == 2)
> +        *value = avio_rb16(pb);
> +    else if (size == 4)
> +        *value = avio_rb32(pb);
> +    else if (size == 8)
> +        *value = avio_rb64(pb);
> +    else
> +        return -1;
> +    return size;
> +}
> +
> +static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
> +{
> +    int version, offset_size, length_size, base_offset_size, index_size;
> +    int item_count, extent_count;
> +    uint64_t base_offset, extent_offset, extent_length;
> +    uint8_t value;
> +    AVStream *st;
> +    MOVStreamContext *sc;
> +
> +    if (!c->is_still_picture_avif) {
> +        // * For non-avif, we simply ignore the iloc box.
> +        // * For animated avif, we don't care about the iloc box as all
> the
> +        //   necessary information can be found in the moov box.
> +        return 0;
> +    }
> +
> +    if (c->fc->nb_streams) {
> +        av_log(c->fc, AV_LOG_INFO, "Duplicate iloc box found\n");
> +        return 0;
> +    }
> +
> +    st = avformat_new_stream(c->fc, NULL);
> +    if (!st)
> +        return AVERROR(ENOMEM);
> +    st->id = c->fc->nb_streams;
> +    sc = av_mallocz(sizeof(MOVStreamContext));
> +    if (!sc)
> +        return AVERROR(ENOMEM);
> +
> +    st->priv_data = sc;
> +    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
> +    st->codecpar->codec_id = AV_CODEC_ID_AV1;
> +    sc->ffindex = st->index;
> +    c->trak_index = st->index;
> +    st->avg_frame_rate.num = st->avg_frame_rate.den = 1;
> +    st->time_base.num = st->time_base.den = 1;
> +    st->nb_frames = 1;
> +    sc->time_scale = 1;
> +    sc = st->priv_data;
> +    sc->pb = c->fc->pb;
> +    sc->pb_is_copied = 1;
> +
> +    version = avio_r8(pb);
> +    avio_rb24(pb);  // flags.
> +
> +    value = avio_r8(pb);
> +    offset_size = (value >> 4) & 0xF;
> +    length_size = value & 0xF;
> +    value = avio_r8(pb);
> +    base_offset_size = (value >> 4) & 0xF;
> +    index_size = !version ? 0 : (value & 0xF);
> +    if (index_size)
> +        return AVERROR_PATCHWELCOME;
> +    item_count = (version < 2) ? avio_rb16(pb) : avio_rb32(pb);
> +    if (item_count > 1) {
> +        // For still AVIF images, we only support one item. Second item
> will
> +        // generally be found for AVIF images with alpha channel. We don't
> +        // support them as of now.
> +        return AVERROR_PATCHWELCOME;
> +    }
> +
> +    // Populate the necessary fields used by mov_build_index.
> +    sc->stsc_count = item_count;
> +    sc->stsc_data = av_malloc_array(item_count, sizeof(*sc->stsc_data));
> +    if (!sc->stsc_data)
> +        return AVERROR(ENOMEM);
> +    sc->stsc_data[0].first = 1;
> +    sc->stsc_data[0].count = 1;
> +    sc->stsc_data[0].id = 1;
> +    sc->chunk_count = item_count;
> +    sc->chunk_offsets =
> +        av_malloc_array(item_count, sizeof(*sc->chunk_offsets));
> +    if (!sc->chunk_offsets)
> +        return AVERROR(ENOMEM);
> +    sc->sample_count = item_count;
> +    sc->sample_sizes =
> +        av_malloc_array(item_count, sizeof(*sc->sample_sizes));
> +    if (!sc->sample_sizes)
> +        return AVERROR(ENOMEM);
> +    sc->stts_count = item_count;
> +    sc->stts_data = av_malloc_array(item_count, sizeof(*sc->stts_data));
> +    if (!sc->stts_data)
> +        return AVERROR(ENOMEM);
> +    sc->stts_data[0].count = 1;
> +    // Not used for still images. But needed by mov_build_index.
> +    sc->stts_data[0].duration = 0;
> +
> +    for (int i = 0; i < item_count; i++) {
> +        (version < 2) ? avio_rb16(pb) : avio_rb32(pb);  // item_id;
> +        if (version > 0)
> +            avio_rb16(pb);  // construction_method.
> +        avio_rb16(pb);  // data_reference_index.
> +        if (rb_size(pb, &base_offset, base_offset_size) < 0)
> +            return AVERROR_INVALIDDATA;
> +        extent_count = avio_rb16(pb);
> +        if (extent_count > 1) {
> +            // For still AVIF images, we only support one extent item.
> +            return AVERROR_PATCHWELCOME;
> +        }
> +        for (int j = 0; j < extent_count; j++) {
> +            if (rb_size(pb, &extent_offset, offset_size) < 0 ||
> +                rb_size(pb, &extent_length, length_size) < 0)
> +                return AVERROR_INVALIDDATA;
> +            sc->sample_sizes[0] = extent_length;
> +            sc->chunk_offsets[0] = base_offset + extent_offset;
> +        }
> +    }
> +
> +    mov_build_index(c, st);
> +
> +    // For still AVIF images, the iloc box contains all the necessary
> +    // information that would generally be provided by the moov box. So
> simply
> +    // mark that we have found the moov box so that parsing can continue.
> +    c->found_moov = 1;
> +
> +    return atom.size;
> +}
> +
>  static const MOVParseTableEntry mov_default_parse_table[] = {
>  { MKTAG('A','C','L','R'), mov_read_aclr },
>  { MKTAG('A','P','R','G'), mov_read_avid },
> @@ -7532,6 +7668,7 @@ static const MOVParseTableEntry
> mov_default_parse_table[] = {
>  { MKTAG('k','i','n','d'), mov_read_kind },
>  { MKTAG('S','A','3','D'), mov_read_SA3D }, /* ambisonic audio box */
>  { MKTAG('S','A','N','D'), mov_read_SAND }, /* non diegetic audio box */
> +{ MKTAG('i','l','o','c'), mov_read_iloc },
>  { 0, NULL }
>  };
>
> --
> 2.36.0.rc0.470.gd361397f0d-goog
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
Gyan Doshi April 20, 2022, 4:24 a.m. UTC | #2
On 2022-04-20 02:49 am, Paul B Mahol wrote:
> On Tue, Apr 19, 2022 at 10:57 PM Vignesh Venkatasubramanian <
> vigneshv-at-google.com@ffmpeg.org> wrote:
>
>> Add support for parsing AVIF still images. This patches supports
>> AVIF still images that have exactly 1 item (i.e.) no alpha channel.
>> Essentially, we will have to parse the "iloc" box and populate
>> the mov index.
>>
>> With this patch, we can decode still AVIF images like so:
>> ffmpeg -i image.avif image.png
>>
>> Partially fixes trac ticket #7621
>>
> LGTM

Will push tomorrow if no one else has.

Regards,
Gyan
Gyan Doshi April 21, 2022, 9 a.m. UTC | #3
On 2022-04-20 09:54 am, Gyan Doshi wrote:
>
>
> On 2022-04-20 02:49 am, Paul B Mahol wrote:
>> On Tue, Apr 19, 2022 at 10:57 PM Vignesh Venkatasubramanian <
>> vigneshv-at-google.com@ffmpeg.org> wrote:
>>
>>> Add support for parsing AVIF still images. This patches supports
>>> AVIF still images that have exactly 1 item (i.e.) no alpha channel.
>>> Essentially, we will have to parse the "iloc" box and populate
>>> the mov index.
>>>
>>> With this patch, we can decode still AVIF images like so:
>>> ffmpeg -i image.avif image.png
>>>
>>> Partially fixes trac ticket #7621
>>>
>> LGTM
>
> Will push tomorrow if no one else has.

Can you provide a sample AVIF image and command that this patch allows 
decoding of?

I tried a couple of samples from Netflix[1] and MS[2] and none worked, 
even with forcing MOV demuxer ("moov atom not found" or "error reading 
header").

[1]: http://download.opencontent.netflix.com/?prefix=AV1/Chimera/AVIF/
[2]: 
https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Microsoft

Regards,
Gyan
Vignesh Venkatasubramanian April 21, 2022, 4:16 p.m. UTC | #4
On Thu, Apr 21, 2022 at 2:08 AM Gyan Doshi <ffmpeg@gyani.pro> wrote:
>
>
>
> On 2022-04-20 09:54 am, Gyan Doshi wrote:
> >
> >
> > On 2022-04-20 02:49 am, Paul B Mahol wrote:
> >> On Tue, Apr 19, 2022 at 10:57 PM Vignesh Venkatasubramanian <
> >> vigneshv-at-google.com@ffmpeg.org> wrote:
> >>
> >>> Add support for parsing AVIF still images. This patches supports
> >>> AVIF still images that have exactly 1 item (i.e.) no alpha channel.
> >>> Essentially, we will have to parse the "iloc" box and populate
> >>> the mov index.
> >>>
> >>> With this patch, we can decode still AVIF images like so:
> >>> ffmpeg -i image.avif image.png
> >>>
> >>> Partially fixes trac ticket #7621
> >>>
> >> LGTM
> >
> > Will push tomorrow if no one else has.
>
> Can you provide a sample AVIF image and command that this patch allows
> decoding of?
>
> I tried a couple of samples from Netflix[1] and MS[2] and none worked,
> even with forcing MOV demuxer ("moov atom not found" or "error reading
> header").

Thanks for verifying. The test files you tried are invalid/not
supported by this patch. Please see the explanation below.

>
> [1]: http://download.opencontent.netflix.com/?prefix=AV1/Chimera/AVIF/

These files are not valid AVIF since they don't have the major brand
set to "mif1" and not "avif". They are also missing a few other
mandatory boxes. libavif (the reference AVIF library) also is not able
to parse these files. These files were likely made when the AVIF
specification was not yet finalized.

$ ./avifdec --info Chimera-AV1-8bit-1280x720-3363kbps-100.avif
ERROR: Failed to decode image: BMFF parsing failed
Diagnostics:
 * [Strict] Item ID 1 of type 'av01' is missing mandatory pixi property

> [2]:
> https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Microsoft
>

These files have EXIF metadata and will contain more than one item
entry in the iloc box. This patch does not support that (however, i
have a follow-up patch to fix this). The files in this directory
return AVERROR_PATCHWELCOME as intended.

For a set of working AVIF files that are supported by this patch you
can try the files under "Link-U" and "Netflix" subdirectories of this repo:

https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Link-U

https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix/avif

The command is as mentioned in the commit message:
./ffmpeg -i <avif file> output.png

Please let me know if you have more questions. Thank you!


> Regards,
> Gyan
>
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".



--
Vignesh
Gyan Doshi April 22, 2022, 4:17 a.m. UTC | #5
On 2022-04-21 09:46 pm, Vignesh Venkatasubramanian wrote:
> On Thu, Apr 21, 2022 at 2:08 AM Gyan Doshi <ffmpeg@gyani.pro> wrote:
>>
>>
>> On 2022-04-20 09:54 am, Gyan Doshi wrote:
>>>
>>> On 2022-04-20 02:49 am, Paul B Mahol wrote:
>>>> On Tue, Apr 19, 2022 at 10:57 PM Vignesh Venkatasubramanian <
>>>> vigneshv-at-google.com@ffmpeg.org> wrote:
>>>>
>>>>> Add support for parsing AVIF still images. This patches supports
>>>>> AVIF still images that have exactly 1 item (i.e.) no alpha channel.
>>>>> Essentially, we will have to parse the "iloc" box and populate
>>>>> the mov index.
>>>>>
>>>>> With this patch, we can decode still AVIF images like so:
>>>>> ffmpeg -i image.avif image.png
>>>>>
>>>>> Partially fixes trac ticket #7621
>>>>>
>>>> LGTM
>>> Will push tomorrow if no one else has.
>> Can you provide a sample AVIF image and command that this patch allows
>> decoding of?
>>
>> I tried a couple of samples from Netflix[1] and MS[2] and none worked,
>> even with forcing MOV demuxer ("moov atom not found" or "error reading
>> header").
> Thanks for verifying. The test files you tried are invalid/not
> supported by this patch. Please see the explanation below.
>
>> [1]: http://download.opencontent.netflix.com/?prefix=AV1/Chimera/AVIF/
> These files are not valid AVIF since they don't have the major brand
> set to "mif1" and not "avif". They are also missing a few other
> mandatory boxes. libavif (the reference AVIF library) also is not able
> to parse these files. These files were likely made when the AVIF
> specification was not yet finalized.
>
> $ ./avifdec --info Chimera-AV1-8bit-1280x720-3363kbps-100.avif
> ERROR: Failed to decode image: BMFF parsing failed
> Diagnostics:
>   * [Strict] Item ID 1 of type 'av01' is missing mandatory pixi property
>
>> [2]:
>> https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Microsoft
>>
> These files have EXIF metadata and will contain more than one item
> entry in the iloc box. This patch does not support that (however, i
> have a follow-up patch to fix this). The files in this directory
> return AVERROR_PATCHWELCOME as intended.
>
> For a set of working AVIF files that are supported by this patch you
> can try the files under "Link-U" and "Netflix" subdirectories of this repo:
>
> https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Link-U
>
> https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix/avif
Ok, these work.

> The command is as mentioned in the commit message:
> ./ffmpeg -i <avif file> output.png
>
> Please let me know if you have more questions. Thank you!

Add informative log msgs in the patchwelcome blocks.

Are there plans to add support for transforms like cropping, rotation?

Regards,
Gyan
Vignesh Venkatasubramanian April 22, 2022, 6:58 p.m. UTC | #6
On Thu, Apr 21, 2022 at 9:18 PM Gyan Doshi <ffmpeg@gyani.pro> wrote:
>
>
>
> On 2022-04-21 09:46 pm, Vignesh Venkatasubramanian wrote:
> > On Thu, Apr 21, 2022 at 2:08 AM Gyan Doshi <ffmpeg@gyani.pro> wrote:
> >>
> >>
> >> On 2022-04-20 09:54 am, Gyan Doshi wrote:
> >>>
> >>> On 2022-04-20 02:49 am, Paul B Mahol wrote:
> >>>> On Tue, Apr 19, 2022 at 10:57 PM Vignesh Venkatasubramanian <
> >>>> vigneshv-at-google.com@ffmpeg.org> wrote:
> >>>>
> >>>>> Add support for parsing AVIF still images. This patches supports
> >>>>> AVIF still images that have exactly 1 item (i.e.) no alpha channel.
> >>>>> Essentially, we will have to parse the "iloc" box and populate
> >>>>> the mov index.
> >>>>>
> >>>>> With this patch, we can decode still AVIF images like so:
> >>>>> ffmpeg -i image.avif image.png
> >>>>>
> >>>>> Partially fixes trac ticket #7621
> >>>>>
> >>>> LGTM
> >>> Will push tomorrow if no one else has.
> >> Can you provide a sample AVIF image and command that this patch allows
> >> decoding of?
> >>
> >> I tried a couple of samples from Netflix[1] and MS[2] and none worked,
> >> even with forcing MOV demuxer ("moov atom not found" or "error reading
> >> header").
> > Thanks for verifying. The test files you tried are invalid/not
> > supported by this patch. Please see the explanation below.
> >
> >> [1]: http://download.opencontent.netflix.com/?prefix=AV1/Chimera/AVIF/
> > These files are not valid AVIF since they don't have the major brand
> > set to "mif1" and not "avif". They are also missing a few other
> > mandatory boxes. libavif (the reference AVIF library) also is not able
> > to parse these files. These files were likely made when the AVIF
> > specification was not yet finalized.
> >
> > $ ./avifdec --info Chimera-AV1-8bit-1280x720-3363kbps-100.avif
> > ERROR: Failed to decode image: BMFF parsing failed
> > Diagnostics:
> >   * [Strict] Item ID 1 of type 'av01' is missing mandatory pixi property
> >
> >> [2]:
> >> https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Microsoft
> >>
> > These files have EXIF metadata and will contain more than one item
> > entry in the iloc box. This patch does not support that (however, i
> > have a follow-up patch to fix this). The files in this directory
> > return AVERROR_PATCHWELCOME as intended.
> >
> > For a set of working AVIF files that are supported by this patch you
> > can try the files under "Link-U" and "Netflix" subdirectories of this repo:
> >
> > https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Link-U
> >
> > https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix/avif
> Ok, these work.
>
> > The command is as mentioned in the commit message:
> > ./ffmpeg -i <avif file> output.png
> >
> > Please let me know if you have more questions. Thank you!
>
> Add informative log msgs in the patchwelcome blocks.
>

Done.

> Are there plans to add support for transforms like cropping, rotation?
>

I have follow-up patches for fixing some of the AVERROR_PATCHWELCOME
cases. I don't have working code for transforms. It is something that
i will look into in the future once the basic AVIF encode/decode
support lands in ffmpeg.

> Regards,
> Gyan
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Vignesh Venkatasubramanian April 24, 2022, 6:43 p.m. UTC | #7
On Thu, Apr 21, 2022 at 9:16 AM Vignesh Venkatasubramanian
<vigneshv@google.com> wrote:
>
> On Thu, Apr 21, 2022 at 2:08 AM Gyan Doshi <ffmpeg@gyani.pro> wrote:
> >
> >
> >
> > On 2022-04-20 09:54 am, Gyan Doshi wrote:
> > >
> > >
> > > On 2022-04-20 02:49 am, Paul B Mahol wrote:
> > >> On Tue, Apr 19, 2022 at 10:57 PM Vignesh Venkatasubramanian <
> > >> vigneshv-at-google.com@ffmpeg.org> wrote:
> > >>
> > >>> Add support for parsing AVIF still images. This patches supports
> > >>> AVIF still images that have exactly 1 item (i.e.) no alpha channel.
> > >>> Essentially, we will have to parse the "iloc" box and populate
> > >>> the mov index.
> > >>>
> > >>> With this patch, we can decode still AVIF images like so:
> > >>> ffmpeg -i image.avif image.png
> > >>>
> > >>> Partially fixes trac ticket #7621
> > >>>
> > >> LGTM
> > >
> > > Will push tomorrow if no one else has.
> >
> > Can you provide a sample AVIF image and command that this patch allows
> > decoding of?
> >
> > I tried a couple of samples from Netflix[1] and MS[2] and none worked,
> > even with forcing MOV demuxer ("moov atom not found" or "error reading
> > header").
>
> Thanks for verifying. The test files you tried are invalid/not
> supported by this patch. Please see the explanation below.
>
> >
> > [1]: http://download.opencontent.netflix.com/?prefix=AV1/Chimera/AVIF/
>
> These files are not valid AVIF since they don't have the major brand
> set to "mif1" and not "avif". They are also missing a few other
> mandatory boxes. libavif (the reference AVIF library) also is not able
> to parse these files. These files were likely made when the AVIF
> specification was not yet finalized.
>
> $ ./avifdec --info Chimera-AV1-8bit-1280x720-3363kbps-100.avif
> ERROR: Failed to decode image: BMFF parsing failed
> Diagnostics:
>  * [Strict] Item ID 1 of type 'av01' is missing mandatory pixi property
>
> > [2]:
> > https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Microsoft
> >
>
> These files have EXIF metadata and will contain more than one item
> entry in the iloc box. This patch does not support that (however, i
> have a follow-up patch to fix this). The files in this directory
> return AVERROR_PATCHWELCOME as intended.
>

The follow-up patch for supporting the files in the "Microsoft"
subdirectory is here:
http://ffmpeg.org/pipermail/ffmpeg-devel/2022-April/295647.html

> For a set of working AVIF files that are supported by this patch you
> can try the files under "Link-U" and "Netflix" subdirectories of this repo:
>
> https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Link-U
>
> https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix/avif
>
> The command is as mentioned in the commit message:
> ./ffmpeg -i <avif file> output.png
>
> Please let me know if you have more questions. Thank you!
>
>
> > Regards,
> > Gyan
> >
> >
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel@ffmpeg.org
> > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> >
> > To unsubscribe, visit link above, or email
> > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
>
>
> --
> Vignesh
diff mbox series

Patch

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 5caf42b15d..02d681e3ae 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -315,6 +315,7 @@  typedef struct MOVContext {
     int have_read_mfra_size;
     uint32_t mfra_size;
     uint32_t max_stts_delta;
+    int is_still_picture_avif;
 } MOVContext;
 
 int ff_mp4_read_descr_len(AVIOContext *pb);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 6c847de164..e925690584 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1136,6 +1136,7 @@  static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         c->isom = 1;
     av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type);
     av_dict_set(&c->fc->metadata, "major_brand", type, 0);
+    c->is_still_picture_avif = !strncmp(type, "avif", 4);
     minor_ver = avio_rb32(pb); /* minor version */
     av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
 
@@ -7430,6 +7431,141 @@  static int mov_read_SAND(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return 0;
 }
 
+static int rb_size(AVIOContext *pb, uint64_t* value, int size)
+{
+    if (size == 0)
+        *value = 0;
+    else if (size == 1)
+        *value = avio_r8(pb);
+    else if (size == 2)
+        *value = avio_rb16(pb);
+    else if (size == 4)
+        *value = avio_rb32(pb);
+    else if (size == 8)
+        *value = avio_rb64(pb);
+    else
+        return -1;
+    return size;
+}
+
+static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    int version, offset_size, length_size, base_offset_size, index_size;
+    int item_count, extent_count;
+    uint64_t base_offset, extent_offset, extent_length;
+    uint8_t value;
+    AVStream *st;
+    MOVStreamContext *sc;
+
+    if (!c->is_still_picture_avif) {
+        // * For non-avif, we simply ignore the iloc box.
+        // * For animated avif, we don't care about the iloc box as all the
+        //   necessary information can be found in the moov box.
+        return 0;
+    }
+
+    if (c->fc->nb_streams) {
+        av_log(c->fc, AV_LOG_INFO, "Duplicate iloc box found\n");
+        return 0;
+    }
+
+    st = avformat_new_stream(c->fc, NULL);
+    if (!st)
+        return AVERROR(ENOMEM);
+    st->id = c->fc->nb_streams;
+    sc = av_mallocz(sizeof(MOVStreamContext));
+    if (!sc)
+        return AVERROR(ENOMEM);
+
+    st->priv_data = sc;
+    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+    st->codecpar->codec_id = AV_CODEC_ID_AV1;
+    sc->ffindex = st->index;
+    c->trak_index = st->index;
+    st->avg_frame_rate.num = st->avg_frame_rate.den = 1;
+    st->time_base.num = st->time_base.den = 1;
+    st->nb_frames = 1;
+    sc->time_scale = 1;
+    sc = st->priv_data;
+    sc->pb = c->fc->pb;
+    sc->pb_is_copied = 1;
+
+    version = avio_r8(pb);
+    avio_rb24(pb);  // flags.
+    
+    value = avio_r8(pb);
+    offset_size = (value >> 4) & 0xF;
+    length_size = value & 0xF;
+    value = avio_r8(pb);
+    base_offset_size = (value >> 4) & 0xF;
+    index_size = !version ? 0 : (value & 0xF);
+    if (index_size)
+        return AVERROR_PATCHWELCOME;
+    item_count = (version < 2) ? avio_rb16(pb) : avio_rb32(pb);
+    if (item_count > 1) {
+        // For still AVIF images, we only support one item. Second item will
+        // generally be found for AVIF images with alpha channel. We don't
+        // support them as of now.
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Populate the necessary fields used by mov_build_index.
+    sc->stsc_count = item_count;
+    sc->stsc_data = av_malloc_array(item_count, sizeof(*sc->stsc_data));
+    if (!sc->stsc_data)
+        return AVERROR(ENOMEM);
+    sc->stsc_data[0].first = 1;
+    sc->stsc_data[0].count = 1;
+    sc->stsc_data[0].id = 1;
+    sc->chunk_count = item_count;
+    sc->chunk_offsets =
+        av_malloc_array(item_count, sizeof(*sc->chunk_offsets));
+    if (!sc->chunk_offsets)
+        return AVERROR(ENOMEM);
+    sc->sample_count = item_count;
+    sc->sample_sizes =
+        av_malloc_array(item_count, sizeof(*sc->sample_sizes));
+    if (!sc->sample_sizes)
+        return AVERROR(ENOMEM);
+    sc->stts_count = item_count;
+    sc->stts_data = av_malloc_array(item_count, sizeof(*sc->stts_data));
+    if (!sc->stts_data)
+        return AVERROR(ENOMEM);
+    sc->stts_data[0].count = 1;
+    // Not used for still images. But needed by mov_build_index.
+    sc->stts_data[0].duration = 0;
+
+    for (int i = 0; i < item_count; i++) {
+        (version < 2) ? avio_rb16(pb) : avio_rb32(pb);  // item_id;
+        if (version > 0)
+            avio_rb16(pb);  // construction_method.
+        avio_rb16(pb);  // data_reference_index.
+        if (rb_size(pb, &base_offset, base_offset_size) < 0)
+            return AVERROR_INVALIDDATA;
+        extent_count = avio_rb16(pb);
+        if (extent_count > 1) {
+            // For still AVIF images, we only support one extent item.
+            return AVERROR_PATCHWELCOME;
+        }
+        for (int j = 0; j < extent_count; j++) {
+            if (rb_size(pb, &extent_offset, offset_size) < 0 ||
+                rb_size(pb, &extent_length, length_size) < 0)
+                return AVERROR_INVALIDDATA;
+            sc->sample_sizes[0] = extent_length;
+            sc->chunk_offsets[0] = base_offset + extent_offset;
+        }
+    }
+
+    mov_build_index(c, st);
+
+    // For still AVIF images, the iloc box contains all the necessary
+    // information that would generally be provided by the moov box. So simply
+    // mark that we have found the moov box so that parsing can continue.
+    c->found_moov = 1;
+
+    return atom.size;
+}
+
 static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('A','C','L','R'), mov_read_aclr },
 { MKTAG('A','P','R','G'), mov_read_avid },
@@ -7532,6 +7668,7 @@  static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('k','i','n','d'), mov_read_kind },
 { MKTAG('S','A','3','D'), mov_read_SA3D }, /* ambisonic audio box */
 { MKTAG('S','A','N','D'), mov_read_SAND }, /* non diegetic audio box */
+{ MKTAG('i','l','o','c'), mov_read_iloc },
 { 0, NULL }
 };