diff mbox series

[FFmpeg-devel,v3] avformat/mov: Add support for demuxing still HEIC images

Message ID 20231004164019.1428483-1-vigneshv@google.com
State New
Headers show
Series [FFmpeg-devel,v3] avformat/mov: Add support for demuxing still HEIC images | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 fail Make fate failed

Commit Message

Vignesh Venkat Oct. 4, 2023, 4:40 p.m. UTC
They are similar to AVIF images (both use the HEIF container).
The only additional work needed is to parse the hvcC box and put
it in the extradata.

With this patch applied, ffmpeg (when built with an HEVC decoder)
is able to decode the files in
https://github.com/nokiatech/heif/tree/gh-pages/content/images

Also add a couple of fate tests with samples from
https://github.com/nokiatech/heif_conformance/tree/master/conformance_files

Partially fixes trac ticket #6521.

Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
---
 libavformat/isom.h                            |  2 +
 libavformat/mov.c                             | 41 ++++++++++++++++++-
 tests/fate/mov.mak                            |  6 +++
 .../fate/mov-heic-demux-still-image-1-item    | 11 +++++
 .../mov-heic-demux-still-image-multiple-items | 11 +++++
 5 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100644 tests/ref/fate/mov-heic-demux-still-image-1-item
 create mode 100644 tests/ref/fate/mov-heic-demux-still-image-multiple-items

Comments

Vittorio Giovara Oct. 5, 2023, 5:36 p.m. UTC | #1
On Wed, Oct 4, 2023 at 12:40 PM Vignesh Venkatasubramanian via ffmpeg-devel
<ffmpeg-devel@ffmpeg.org> wrote:

> They are similar to AVIF images (both use the HEIF container).
> The only additional work needed is to parse the hvcC box and put
> it in the extradata.
>
> With this patch applied, ffmpeg (when built with an HEVC decoder)
> is able to decode the files in
> https://github.com/nokiatech/heif/tree/gh-pages/content/images
>
> Also add a couple of fate tests with samples from
> https://github.com/nokiatech/heif_conformance/tree/master/conformance_files
>
> Partially fixes trac ticket #6521.
>
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
>  libavformat/isom.h                            |  2 +
>  libavformat/mov.c                             | 41 ++++++++++++++++++-
>  tests/fate/mov.mak                            |  6 +++
>  .../fate/mov-heic-demux-still-image-1-item    | 11 +++++
>  .../mov-heic-demux-still-image-multiple-items | 11 +++++
>  5 files changed, 70 insertions(+), 1 deletion(-)
>  create mode 100644 tests/ref/fate/mov-heic-demux-still-image-1-item
>  create mode 100644
> tests/ref/fate/mov-heic-demux-still-image-multiple-items
>
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index 3d375d7a46..b30b9da65e 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -327,6 +327,8 @@ typedef struct MOVContext {
>          int64_t extent_offset;
>      } *avif_info;
>      int avif_info_size;
> +    int64_t hvcC_offset;
> +    int hvcC_size;
>      int interleaved_read;
>  } MOVContext;
>
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 294c864fbd..d3747022bd 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -1218,7 +1218,8 @@ 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);
> +    c->is_still_picture_avif = !strncmp(type, "avif", 4) ||
> +                               !strncmp(type, "mif1", 4);
>      minor_ver = avio_rb32(pb); /* minor version */
>      av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
>
> @@ -4911,6 +4912,19 @@ static int avif_add_stream(MOVContext *c, int
> item_id)
>      st->priv_data = sc;
>      st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>      st->codecpar->codec_id = AV_CODEC_ID_AV1;
> +    if (c->hvcC_offset >= 0) {
> +        int ret;
> +        int64_t pos = avio_tell(c->fc->pb);
> +        st->codecpar->codec_id = AV_CODEC_ID_HEVC;
> +        if (avio_seek(c->fc->pb, c->hvcC_offset, SEEK_SET) !=
> c->hvcC_offset) {
> +            av_log(c->fc, AV_LOG_ERROR, "Failed to seek to hvcC data.\n");
> +            return AVERROR_UNKNOWN;
> +        }
> +        ret = ff_get_extradata(c->fc, st->codecpar, c->fc->pb,
> c->hvcC_size);
> +        if (ret < 0)
> +            return ret;
> +        avio_seek(c->fc->pb, pos, SEEK_SET);
> +    }
>      sc->ffindex = st->index;
>      c->trak_index = st->index;
>      st->avg_frame_rate.num = st->avg_frame_rate.den = 1;
> @@ -4953,6 +4967,8 @@ static int avif_add_stream(MOVContext *c, int
> item_id)
>
>  static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>  {
> +    c->hvcC_offset = -1;
> +    c->hvcC_size = 0;
>      while (atom.size > 8) {
>          uint32_t tag;
>          if (avio_feof(pb))
> @@ -7827,6 +7843,28 @@ static int mov_read_iloc(MOVContext *c, AVIOContext
> *pb, MOVAtom atom)
>      return atom.size;
>  }
>
> +static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
> +{
> +    int size = avio_rb32(pb);
> +    if (avio_rl32(pb) != MKTAG('i','p','c','o'))
> +        return AVERROR_INVALIDDATA;
> +    size -= 8;
> +    while (size > 0) {
> +        int sub_size, sub_type;
> +        sub_size = avio_rb32(pb);
> +        sub_type = avio_rl32(pb);
> +        sub_size -= 8;
> +        size -= sub_size + 8;
> +        if (sub_type == MKTAG('h','v','c','C')) {
> +            c->hvcC_offset = avio_tell(pb);
> +            c->hvcC_size = sub_size;
> +            break;
> +        }
> +        avio_skip(pb, sub_size);
> +    }
> +    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 },
> @@ -7934,6 +7972,7 @@ static const MOVParseTableEntry
> mov_default_parse_table[] = {
>  { MKTAG('p','c','m','C'), mov_read_pcmc }, /* PCM configuration box */
>  { MKTAG('p','i','t','m'), mov_read_pitm },
>  { MKTAG('e','v','c','C'), mov_read_glbl },
> +{ MKTAG('i','p','r','p'), mov_read_iprp },
>  { 0, NULL }
>  };
>
> diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
> index 6cb493ceab..a2d3cc8013 100644
> --- a/tests/fate/mov.mak
> +++ b/tests/fate/mov.mak
> @@ -18,6 +18,8 @@ FATE_MOV = fate-mov-3elist \
>             fate-mov-neg-firstpts-discard-frames \
>             fate-mov-stream-shorter-than-movie \
>             fate-mov-pcm-remux \
> +           fate-mov-heic-demux-still-image-1-item \
> +           fate-mov-heic-demux-still-image-multiple-items \
>  # FIXME: Uncomment these two lines once the test files are uploaded to
> the fate
>  # server.
>  #           fate-mov-avif-demux-still-image-1-item \
> @@ -152,6 +154,10 @@ fate-mov-mp4-ttml-dfxp: CMD = transcode srt
> $(TARGET_SAMPLES)/sub/SubRip_capabil
>  # parsed.
>  #fate-mov-avif-demux-still-image-multiple-items: CMD = framemd5 -i
> $(TARGET_SAMPLES)/avif/still_image_exif.avif -c:v copy
>
> +fate-mov-heic-demux-still-image-1-item: CMD = framemd5 -i
> $(TARGET_SAMPLES)/heif-conformance/C002.heic -c:v copy
> +
> +fate-mov-heic-demux-still-image-multiple-items: CMD = framemd5 -i
> $(TARGET_SAMPLES)/heif-conformance/C003.heic -c:v copy
> +
>  # Resulting remux should have:
>  # 1. first audio stream with AV_DISPOSITION_HEARING_IMPAIRED
>  # 2. second audio stream with AV_DISPOSITION_VISUAL_IMPAIRED |
> DESCRIPTIONS
> diff --git a/tests/ref/fate/mov-heic-demux-still-image-1-item
> b/tests/ref/fate/mov-heic-demux-still-image-1-item
> new file mode 100644
> index 0000000000..c850c1ff9c
> --- /dev/null
> +++ b/tests/ref/fate/mov-heic-demux-still-image-1-item
> @@ -0,0 +1,11 @@
> +#format: frame checksums
> +#version: 2
> +#hash: MD5
> +#extradata 0,                             100,
> 5444bf01e03182c73ae957179d560f4d
> +#tb 0: 1/1
> +#media_type 0: video
> +#codec_id 0: hevc
> +#dimensions 0: 1280x720
> +#sar 0: 0/1
> +#stream#, dts,        pts, duration,     size, hash
> +0,          0,          0,        1,   111554,
> 03ceabfab39afd2e2e796b9362111f32
> diff --git a/tests/ref/fate/mov-heic-demux-still-image-multiple-items
> b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
> new file mode 100644
> index 0000000000..c850c1ff9c
> --- /dev/null
> +++ b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
> @@ -0,0 +1,11 @@
> +#format: frame checksums
> +#version: 2
> +#hash: MD5
> +#extradata 0,                             100,
> 5444bf01e03182c73ae957179d560f4d
> +#tb 0: 1/1
> +#media_type 0: video
> +#codec_id 0: hevc
> +#dimensions 0: 1280x720
> +#sar 0: 0/1
> +#stream#, dts,        pts, duration,     size, hash
> +0,          0,          0,        1,   111554,
> 03ceabfab39afd2e2e796b9362111f32
> --


patch lgtm. I dont have access to fate, can you send the samples to
https://ffmpeg.org/fate.html#Uploading-new-samples-to-the-fate-suite?
As soon as they are up, I'll merge this.
Thanks
Vignesh Venkat Oct. 5, 2023, 10:40 p.m. UTC | #2
On Thu, Oct 5, 2023 at 10:36 AM Vittorio Giovara <vittorio.giovara@gmail.com>
wrote:

>
>
> On Wed, Oct 4, 2023 at 12:40 PM Vignesh Venkatasubramanian via
> ffmpeg-devel <ffmpeg-devel@ffmpeg.org> wrote:
>
>> They are similar to AVIF images (both use the HEIF container).
>> The only additional work needed is to parse the hvcC box and put
>> it in the extradata.
>>
>> With this patch applied, ffmpeg (when built with an HEVC decoder)
>> is able to decode the files in
>> https://github.com/nokiatech/heif/tree/gh-pages/content/images
>>
>> Also add a couple of fate tests with samples from
>>
>> https://github.com/nokiatech/heif_conformance/tree/master/conformance_files
>>
>> Partially fixes trac ticket #6521.
>>
>> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
>> ---
>>  libavformat/isom.h                            |  2 +
>>  libavformat/mov.c                             | 41 ++++++++++++++++++-
>>  tests/fate/mov.mak                            |  6 +++
>>  .../fate/mov-heic-demux-still-image-1-item    | 11 +++++
>>  .../mov-heic-demux-still-image-multiple-items | 11 +++++
>>  5 files changed, 70 insertions(+), 1 deletion(-)
>>  create mode 100644 tests/ref/fate/mov-heic-demux-still-image-1-item
>>  create mode 100644
>> tests/ref/fate/mov-heic-demux-still-image-multiple-items
>>
>> diff --git a/libavformat/isom.h b/libavformat/isom.h
>> index 3d375d7a46..b30b9da65e 100644
>> --- a/libavformat/isom.h
>> +++ b/libavformat/isom.h
>> @@ -327,6 +327,8 @@ typedef struct MOVContext {
>>          int64_t extent_offset;
>>      } *avif_info;
>>      int avif_info_size;
>> +    int64_t hvcC_offset;
>> +    int hvcC_size;
>>      int interleaved_read;
>>  } MOVContext;
>>
>> diff --git a/libavformat/mov.c b/libavformat/mov.c
>> index 294c864fbd..d3747022bd 100644
>> --- a/libavformat/mov.c
>> +++ b/libavformat/mov.c
>> @@ -1218,7 +1218,8 @@ 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);
>> +    c->is_still_picture_avif = !strncmp(type, "avif", 4) ||
>> +                               !strncmp(type, "mif1", 4);
>>      minor_ver = avio_rb32(pb); /* minor version */
>>      av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
>>
>> @@ -4911,6 +4912,19 @@ static int avif_add_stream(MOVContext *c, int
>> item_id)
>>      st->priv_data = sc;
>>      st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>>      st->codecpar->codec_id = AV_CODEC_ID_AV1;
>> +    if (c->hvcC_offset >= 0) {
>> +        int ret;
>> +        int64_t pos = avio_tell(c->fc->pb);
>> +        st->codecpar->codec_id = AV_CODEC_ID_HEVC;
>> +        if (avio_seek(c->fc->pb, c->hvcC_offset, SEEK_SET) !=
>> c->hvcC_offset) {
>> +            av_log(c->fc, AV_LOG_ERROR, "Failed to seek to hvcC
>> data.\n");
>> +            return AVERROR_UNKNOWN;
>> +        }
>> +        ret = ff_get_extradata(c->fc, st->codecpar, c->fc->pb,
>> c->hvcC_size);
>> +        if (ret < 0)
>> +            return ret;
>> +        avio_seek(c->fc->pb, pos, SEEK_SET);
>> +    }
>>      sc->ffindex = st->index;
>>      c->trak_index = st->index;
>>      st->avg_frame_rate.num = st->avg_frame_rate.den = 1;
>> @@ -4953,6 +4967,8 @@ static int avif_add_stream(MOVContext *c, int
>> item_id)
>>
>>  static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>>  {
>> +    c->hvcC_offset = -1;
>> +    c->hvcC_size = 0;
>>      while (atom.size > 8) {
>>          uint32_t tag;
>>          if (avio_feof(pb))
>> @@ -7827,6 +7843,28 @@ static int mov_read_iloc(MOVContext *c,
>> AVIOContext *pb, MOVAtom atom)
>>      return atom.size;
>>  }
>>
>> +static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>> +{
>> +    int size = avio_rb32(pb);
>> +    if (avio_rl32(pb) != MKTAG('i','p','c','o'))
>> +        return AVERROR_INVALIDDATA;
>> +    size -= 8;
>> +    while (size > 0) {
>> +        int sub_size, sub_type;
>> +        sub_size = avio_rb32(pb);
>> +        sub_type = avio_rl32(pb);
>> +        sub_size -= 8;
>> +        size -= sub_size + 8;
>> +        if (sub_type == MKTAG('h','v','c','C')) {
>> +            c->hvcC_offset = avio_tell(pb);
>> +            c->hvcC_size = sub_size;
>> +            break;
>> +        }
>> +        avio_skip(pb, sub_size);
>> +    }
>> +    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 },
>> @@ -7934,6 +7972,7 @@ static const MOVParseTableEntry
>> mov_default_parse_table[] = {
>>  { MKTAG('p','c','m','C'), mov_read_pcmc }, /* PCM configuration box */
>>  { MKTAG('p','i','t','m'), mov_read_pitm },
>>  { MKTAG('e','v','c','C'), mov_read_glbl },
>> +{ MKTAG('i','p','r','p'), mov_read_iprp },
>>  { 0, NULL }
>>  };
>>
>> diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
>> index 6cb493ceab..a2d3cc8013 100644
>> --- a/tests/fate/mov.mak
>> +++ b/tests/fate/mov.mak
>> @@ -18,6 +18,8 @@ FATE_MOV = fate-mov-3elist \
>>             fate-mov-neg-firstpts-discard-frames \
>>             fate-mov-stream-shorter-than-movie \
>>             fate-mov-pcm-remux \
>> +           fate-mov-heic-demux-still-image-1-item \
>> +           fate-mov-heic-demux-still-image-multiple-items \
>>  # FIXME: Uncomment these two lines once the test files are uploaded to
>> the fate
>>  # server.
>>  #           fate-mov-avif-demux-still-image-1-item \
>> @@ -152,6 +154,10 @@ fate-mov-mp4-ttml-dfxp: CMD = transcode srt
>> $(TARGET_SAMPLES)/sub/SubRip_capabil
>>  # parsed.
>>  #fate-mov-avif-demux-still-image-multiple-items: CMD = framemd5 -i
>> $(TARGET_SAMPLES)/avif/still_image_exif.avif -c:v copy
>>
>> +fate-mov-heic-demux-still-image-1-item: CMD = framemd5 -i
>> $(TARGET_SAMPLES)/heif-conformance/C002.heic -c:v copy
>> +
>> +fate-mov-heic-demux-still-image-multiple-items: CMD = framemd5 -i
>> $(TARGET_SAMPLES)/heif-conformance/C003.heic -c:v copy
>> +
>>  # Resulting remux should have:
>>  # 1. first audio stream with AV_DISPOSITION_HEARING_IMPAIRED
>>  # 2. second audio stream with AV_DISPOSITION_VISUAL_IMPAIRED |
>> DESCRIPTIONS
>> diff --git a/tests/ref/fate/mov-heic-demux-still-image-1-item
>> b/tests/ref/fate/mov-heic-demux-still-image-1-item
>> new file mode 100644
>> index 0000000000..c850c1ff9c
>> --- /dev/null
>> +++ b/tests/ref/fate/mov-heic-demux-still-image-1-item
>> @@ -0,0 +1,11 @@
>> +#format: frame checksums
>> +#version: 2
>> +#hash: MD5
>> +#extradata 0,                             100,
>> 5444bf01e03182c73ae957179d560f4d
>> +#tb 0: 1/1
>> +#media_type 0: video
>> +#codec_id 0: hevc
>> +#dimensions 0: 1280x720
>> +#sar 0: 0/1
>> +#stream#, dts,        pts, duration,     size, hash
>> +0,          0,          0,        1,   111554,
>> 03ceabfab39afd2e2e796b9362111f32
>> diff --git a/tests/ref/fate/mov-heic-demux-still-image-multiple-items
>> b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
>> new file mode 100644
>> index 0000000000..c850c1ff9c
>> --- /dev/null
>> +++ b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
>> @@ -0,0 +1,11 @@
>> +#format: frame checksums
>> +#version: 2
>> +#hash: MD5
>> +#extradata 0,                             100,
>> 5444bf01e03182c73ae957179d560f4d
>> +#tb 0: 1/1
>> +#media_type 0: video
>> +#codec_id 0: hevc
>> +#dimensions 0: 1280x720
>> +#sar 0: 0/1
>> +#stream#, dts,        pts, duration,     size, hash
>> +0,          0,          0,        1,   111554,
>> 03ceabfab39afd2e2e796b9362111f32
>> --
>
>
> patch lgtm. I dont have access to fate, can you send the samples to
> https://ffmpeg.org/fate.html#Uploading-new-samples-to-the-fate-suite?
> As soon as they are up, I'll merge this.
> Thanks
>

Thank you. I have emailed the samples to samples-request@ffmpeg.org. I will
ping this thread once they are uploaded.


> --
> Vittorio
>
Vignesh Venkat Oct. 9, 2023, 6:52 p.m. UTC | #3
On Thu, Oct 5, 2023 at 3:40 PM Vignesh Venkat <vigneshv@google.com> wrote:
>
>
>
> On Thu, Oct 5, 2023 at 10:36 AM Vittorio Giovara <vittorio.giovara@gmail.com> wrote:
>>
>>
>>
>> On Wed, Oct 4, 2023 at 12:40 PM Vignesh Venkatasubramanian via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> wrote:
>>>
>>> They are similar to AVIF images (both use the HEIF container).
>>> The only additional work needed is to parse the hvcC box and put
>>> it in the extradata.
>>>
>>> With this patch applied, ffmpeg (when built with an HEVC decoder)
>>> is able to decode the files in
>>> https://github.com/nokiatech/heif/tree/gh-pages/content/images
>>>
>>> Also add a couple of fate tests with samples from
>>> https://github.com/nokiatech/heif_conformance/tree/master/conformance_files
>>>
>>> Partially fixes trac ticket #6521.
>>>
>>> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
>>> ---
>>>  libavformat/isom.h                            |  2 +
>>>  libavformat/mov.c                             | 41 ++++++++++++++++++-
>>>  tests/fate/mov.mak                            |  6 +++
>>>  .../fate/mov-heic-demux-still-image-1-item    | 11 +++++
>>>  .../mov-heic-demux-still-image-multiple-items | 11 +++++
>>>  5 files changed, 70 insertions(+), 1 deletion(-)
>>>  create mode 100644 tests/ref/fate/mov-heic-demux-still-image-1-item
>>>  create mode 100644 tests/ref/fate/mov-heic-demux-still-image-multiple-items
>>>
>>> diff --git a/libavformat/isom.h b/libavformat/isom.h
>>> index 3d375d7a46..b30b9da65e 100644
>>> --- a/libavformat/isom.h
>>> +++ b/libavformat/isom.h
>>> @@ -327,6 +327,8 @@ typedef struct MOVContext {
>>>          int64_t extent_offset;
>>>      } *avif_info;
>>>      int avif_info_size;
>>> +    int64_t hvcC_offset;
>>> +    int hvcC_size;
>>>      int interleaved_read;
>>>  } MOVContext;
>>>
>>> diff --git a/libavformat/mov.c b/libavformat/mov.c
>>> index 294c864fbd..d3747022bd 100644
>>> --- a/libavformat/mov.c
>>> +++ b/libavformat/mov.c
>>> @@ -1218,7 +1218,8 @@ 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);
>>> +    c->is_still_picture_avif = !strncmp(type, "avif", 4) ||
>>> +                               !strncmp(type, "mif1", 4);
>>>      minor_ver = avio_rb32(pb); /* minor version */
>>>      av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
>>>
>>> @@ -4911,6 +4912,19 @@ static int avif_add_stream(MOVContext *c, int item_id)
>>>      st->priv_data = sc;
>>>      st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
>>>      st->codecpar->codec_id = AV_CODEC_ID_AV1;
>>> +    if (c->hvcC_offset >= 0) {
>>> +        int ret;
>>> +        int64_t pos = avio_tell(c->fc->pb);
>>> +        st->codecpar->codec_id = AV_CODEC_ID_HEVC;
>>> +        if (avio_seek(c->fc->pb, c->hvcC_offset, SEEK_SET) != c->hvcC_offset) {
>>> +            av_log(c->fc, AV_LOG_ERROR, "Failed to seek to hvcC data.\n");
>>> +            return AVERROR_UNKNOWN;
>>> +        }
>>> +        ret = ff_get_extradata(c->fc, st->codecpar, c->fc->pb, c->hvcC_size);
>>> +        if (ret < 0)
>>> +            return ret;
>>> +        avio_seek(c->fc->pb, pos, SEEK_SET);
>>> +    }
>>>      sc->ffindex = st->index;
>>>      c->trak_index = st->index;
>>>      st->avg_frame_rate.num = st->avg_frame_rate.den = 1;
>>> @@ -4953,6 +4967,8 @@ static int avif_add_stream(MOVContext *c, int item_id)
>>>
>>>  static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>>>  {
>>> +    c->hvcC_offset = -1;
>>> +    c->hvcC_size = 0;
>>>      while (atom.size > 8) {
>>>          uint32_t tag;
>>>          if (avio_feof(pb))
>>> @@ -7827,6 +7843,28 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>>>      return atom.size;
>>>  }
>>>
>>> +static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>>> +{
>>> +    int size = avio_rb32(pb);
>>> +    if (avio_rl32(pb) != MKTAG('i','p','c','o'))
>>> +        return AVERROR_INVALIDDATA;
>>> +    size -= 8;
>>> +    while (size > 0) {
>>> +        int sub_size, sub_type;
>>> +        sub_size = avio_rb32(pb);
>>> +        sub_type = avio_rl32(pb);
>>> +        sub_size -= 8;
>>> +        size -= sub_size + 8;
>>> +        if (sub_type == MKTAG('h','v','c','C')) {
>>> +            c->hvcC_offset = avio_tell(pb);
>>> +            c->hvcC_size = sub_size;
>>> +            break;
>>> +        }
>>> +        avio_skip(pb, sub_size);
>>> +    }
>>> +    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 },
>>> @@ -7934,6 +7972,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
>>>  { MKTAG('p','c','m','C'), mov_read_pcmc }, /* PCM configuration box */
>>>  { MKTAG('p','i','t','m'), mov_read_pitm },
>>>  { MKTAG('e','v','c','C'), mov_read_glbl },
>>> +{ MKTAG('i','p','r','p'), mov_read_iprp },
>>>  { 0, NULL }
>>>  };
>>>
>>> diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
>>> index 6cb493ceab..a2d3cc8013 100644
>>> --- a/tests/fate/mov.mak
>>> +++ b/tests/fate/mov.mak
>>> @@ -18,6 +18,8 @@ FATE_MOV = fate-mov-3elist \
>>>             fate-mov-neg-firstpts-discard-frames \
>>>             fate-mov-stream-shorter-than-movie \
>>>             fate-mov-pcm-remux \
>>> +           fate-mov-heic-demux-still-image-1-item \
>>> +           fate-mov-heic-demux-still-image-multiple-items \
>>>  # FIXME: Uncomment these two lines once the test files are uploaded to the fate
>>>  # server.
>>>  #           fate-mov-avif-demux-still-image-1-item \
>>> @@ -152,6 +154,10 @@ fate-mov-mp4-ttml-dfxp: CMD = transcode srt $(TARGET_SAMPLES)/sub/SubRip_capabil
>>>  # parsed.
>>>  #fate-mov-avif-demux-still-image-multiple-items: CMD = framemd5 -i $(TARGET_SAMPLES)/avif/still_image_exif.avif -c:v copy
>>>
>>> +fate-mov-heic-demux-still-image-1-item: CMD = framemd5 -i $(TARGET_SAMPLES)/heif-conformance/C002.heic -c:v copy
>>> +
>>> +fate-mov-heic-demux-still-image-multiple-items: CMD = framemd5 -i $(TARGET_SAMPLES)/heif-conformance/C003.heic -c:v copy
>>> +
>>>  # Resulting remux should have:
>>>  # 1. first audio stream with AV_DISPOSITION_HEARING_IMPAIRED
>>>  # 2. second audio stream with AV_DISPOSITION_VISUAL_IMPAIRED | DESCRIPTIONS
>>> diff --git a/tests/ref/fate/mov-heic-demux-still-image-1-item b/tests/ref/fate/mov-heic-demux-still-image-1-item
>>> new file mode 100644
>>> index 0000000000..c850c1ff9c
>>> --- /dev/null
>>> +++ b/tests/ref/fate/mov-heic-demux-still-image-1-item
>>> @@ -0,0 +1,11 @@
>>> +#format: frame checksums
>>> +#version: 2
>>> +#hash: MD5
>>> +#extradata 0,                             100, 5444bf01e03182c73ae957179d560f4d
>>> +#tb 0: 1/1
>>> +#media_type 0: video
>>> +#codec_id 0: hevc
>>> +#dimensions 0: 1280x720
>>> +#sar 0: 0/1
>>> +#stream#, dts,        pts, duration,     size, hash
>>> +0,          0,          0,        1,   111554, 03ceabfab39afd2e2e796b9362111f32
>>> diff --git a/tests/ref/fate/mov-heic-demux-still-image-multiple-items b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
>>> new file mode 100644
>>> index 0000000000..c850c1ff9c
>>> --- /dev/null
>>> +++ b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
>>> @@ -0,0 +1,11 @@
>>> +#format: frame checksums
>>> +#version: 2
>>> +#hash: MD5
>>> +#extradata 0,                             100, 5444bf01e03182c73ae957179d560f4d
>>> +#tb 0: 1/1
>>> +#media_type 0: video
>>> +#codec_id 0: hevc
>>> +#dimensions 0: 1280x720
>>> +#sar 0: 0/1
>>> +#stream#, dts,        pts, duration,     size, hash
>>> +0,          0,          0,        1,   111554, 03ceabfab39afd2e2e796b9362111f32
>>> --
>>
>>
>> patch lgtm. I dont have access to fate, can you send the samples to https://ffmpeg.org/fate.html#Uploading-new-samples-to-the-fate-suite?
>> As soon as they are up, I'll merge this.
>> Thanks
>
>
> Thank you. I have emailed the samples to samples-request@ffmpeg.org. I will ping this thread once they are uploaded.
>


Could somebody please help upload the sample files sent to
samples-request@ffmpeg.org so that this patch can be merged? Thank
you!

>>
>> --
>> Vittorio
>
>
>
> --
> Vignesh
Thilo Borgmann Oct. 27, 2023, 4:52 p.m. UTC | #4
>> Thank you. I have emailed the samples to samples-request@ffmpeg.org. I will ping this thread once they are uploaded.
>>
> 
> 
> Could somebody please help upload the sample files sent to
> samples-request@ffmpeg.org so that this patch can be merged? Thank
> you!

Done, sorry for delay.

Same for the avif samples.

-Thilo
James Almer Jan. 9, 2024, 12:39 p.m. UTC | #5
On 10/4/2023 1:40 PM, Vignesh Venkatasubramanian via ffmpeg-devel wrote:
> They are similar to AVIF images (both use the HEIF container).
> The only additional work needed is to parse the hvcC box and put
> it in the extradata.
> 
> With this patch applied, ffmpeg (when built with an HEVC decoder)
> is able to decode the files in
> https://github.com/nokiatech/heif/tree/gh-pages/content/images
> 
> Also add a couple of fate tests with samples from
> https://github.com/nokiatech/heif_conformance/tree/master/conformance_files
> 
> Partially fixes trac ticket #6521.
> 
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
>   libavformat/isom.h                            |  2 +
>   libavformat/mov.c                             | 41 ++++++++++++++++++-
>   tests/fate/mov.mak                            |  6 +++
>   .../fate/mov-heic-demux-still-image-1-item    | 11 +++++
>   .../mov-heic-demux-still-image-multiple-items | 11 +++++
>   5 files changed, 70 insertions(+), 1 deletion(-)
>   create mode 100644 tests/ref/fate/mov-heic-demux-still-image-1-item
>   create mode 100644 tests/ref/fate/mov-heic-demux-still-image-multiple-items

This seems to have been forgotten, so I'll apply it soon.
Vignesh Venkat Jan. 10, 2024, 9:05 p.m. UTC | #6
On Tue, Jan 9, 2024 at 4:39 AM James Almer <jamrial@gmail.com> wrote:
>
> On 10/4/2023 1:40 PM, Vignesh Venkatasubramanian via ffmpeg-devel wrote:
> > They are similar to AVIF images (both use the HEIF container).
> > The only additional work needed is to parse the hvcC box and put
> > it in the extradata.
> >
> > With this patch applied, ffmpeg (when built with an HEVC decoder)
> > is able to decode the files in
> > https://github.com/nokiatech/heif/tree/gh-pages/content/images
> >
> > Also add a couple of fate tests with samples from
> > https://github.com/nokiatech/heif_conformance/tree/master/conformance_files
> >
> > Partially fixes trac ticket #6521.
> >
> > Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> > ---
> >   libavformat/isom.h                            |  2 +
> >   libavformat/mov.c                             | 41 ++++++++++++++++++-
> >   tests/fate/mov.mak                            |  6 +++
> >   .../fate/mov-heic-demux-still-image-1-item    | 11 +++++
> >   .../mov-heic-demux-still-image-multiple-items | 11 +++++
> >   5 files changed, 70 insertions(+), 1 deletion(-)
> >   create mode 100644 tests/ref/fate/mov-heic-demux-still-image-1-item
> >   create mode 100644 tests/ref/fate/mov-heic-demux-still-image-multiple-items
>
> This seems to have been forgotten, so I'll apply it soon.

Sorry that was my bad. Thanks for applying.

> _______________________________________________
> 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".
diff mbox series

Patch

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 3d375d7a46..b30b9da65e 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -327,6 +327,8 @@  typedef struct MOVContext {
         int64_t extent_offset;
     } *avif_info;
     int avif_info_size;
+    int64_t hvcC_offset;
+    int hvcC_size;
     int interleaved_read;
 } MOVContext;
 
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 294c864fbd..d3747022bd 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1218,7 +1218,8 @@  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);
+    c->is_still_picture_avif = !strncmp(type, "avif", 4) ||
+                               !strncmp(type, "mif1", 4);
     minor_ver = avio_rb32(pb); /* minor version */
     av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
 
@@ -4911,6 +4912,19 @@  static int avif_add_stream(MOVContext *c, int item_id)
     st->priv_data = sc;
     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     st->codecpar->codec_id = AV_CODEC_ID_AV1;
+    if (c->hvcC_offset >= 0) {
+        int ret;
+        int64_t pos = avio_tell(c->fc->pb);
+        st->codecpar->codec_id = AV_CODEC_ID_HEVC;
+        if (avio_seek(c->fc->pb, c->hvcC_offset, SEEK_SET) != c->hvcC_offset) {
+            av_log(c->fc, AV_LOG_ERROR, "Failed to seek to hvcC data.\n");
+            return AVERROR_UNKNOWN;
+        }
+        ret = ff_get_extradata(c->fc, st->codecpar, c->fc->pb, c->hvcC_size);
+        if (ret < 0)
+            return ret;
+        avio_seek(c->fc->pb, pos, SEEK_SET);
+    }
     sc->ffindex = st->index;
     c->trak_index = st->index;
     st->avg_frame_rate.num = st->avg_frame_rate.den = 1;
@@ -4953,6 +4967,8 @@  static int avif_add_stream(MOVContext *c, int item_id)
 
 static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
+    c->hvcC_offset = -1;
+    c->hvcC_size = 0;
     while (atom.size > 8) {
         uint32_t tag;
         if (avio_feof(pb))
@@ -7827,6 +7843,28 @@  static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return atom.size;
 }
 
+static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    int size = avio_rb32(pb);
+    if (avio_rl32(pb) != MKTAG('i','p','c','o'))
+        return AVERROR_INVALIDDATA;
+    size -= 8;
+    while (size > 0) {
+        int sub_size, sub_type;
+        sub_size = avio_rb32(pb);
+        sub_type = avio_rl32(pb);
+        sub_size -= 8;
+        size -= sub_size + 8;
+        if (sub_type == MKTAG('h','v','c','C')) {
+            c->hvcC_offset = avio_tell(pb);
+            c->hvcC_size = sub_size;
+            break;
+        }
+        avio_skip(pb, sub_size);
+    }
+    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 },
@@ -7934,6 +7972,7 @@  static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('p','c','m','C'), mov_read_pcmc }, /* PCM configuration box */
 { MKTAG('p','i','t','m'), mov_read_pitm },
 { MKTAG('e','v','c','C'), mov_read_glbl },
+{ MKTAG('i','p','r','p'), mov_read_iprp },
 { 0, NULL }
 };
 
diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
index 6cb493ceab..a2d3cc8013 100644
--- a/tests/fate/mov.mak
+++ b/tests/fate/mov.mak
@@ -18,6 +18,8 @@  FATE_MOV = fate-mov-3elist \
            fate-mov-neg-firstpts-discard-frames \
            fate-mov-stream-shorter-than-movie \
            fate-mov-pcm-remux \
+           fate-mov-heic-demux-still-image-1-item \
+           fate-mov-heic-demux-still-image-multiple-items \
 # FIXME: Uncomment these two lines once the test files are uploaded to the fate
 # server.
 #           fate-mov-avif-demux-still-image-1-item \
@@ -152,6 +154,10 @@  fate-mov-mp4-ttml-dfxp: CMD = transcode srt $(TARGET_SAMPLES)/sub/SubRip_capabil
 # parsed.
 #fate-mov-avif-demux-still-image-multiple-items: CMD = framemd5 -i $(TARGET_SAMPLES)/avif/still_image_exif.avif -c:v copy
 
+fate-mov-heic-demux-still-image-1-item: CMD = framemd5 -i $(TARGET_SAMPLES)/heif-conformance/C002.heic -c:v copy
+
+fate-mov-heic-demux-still-image-multiple-items: CMD = framemd5 -i $(TARGET_SAMPLES)/heif-conformance/C003.heic -c:v copy
+
 # Resulting remux should have:
 # 1. first audio stream with AV_DISPOSITION_HEARING_IMPAIRED
 # 2. second audio stream with AV_DISPOSITION_VISUAL_IMPAIRED | DESCRIPTIONS
diff --git a/tests/ref/fate/mov-heic-demux-still-image-1-item b/tests/ref/fate/mov-heic-demux-still-image-1-item
new file mode 100644
index 0000000000..c850c1ff9c
--- /dev/null
+++ b/tests/ref/fate/mov-heic-demux-still-image-1-item
@@ -0,0 +1,11 @@ 
+#format: frame checksums
+#version: 2
+#hash: MD5
+#extradata 0,                             100, 5444bf01e03182c73ae957179d560f4d
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: hevc
+#dimensions 0: 1280x720
+#sar 0: 0/1
+#stream#, dts,        pts, duration,     size, hash
+0,          0,          0,        1,   111554, 03ceabfab39afd2e2e796b9362111f32
diff --git a/tests/ref/fate/mov-heic-demux-still-image-multiple-items b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
new file mode 100644
index 0000000000..c850c1ff9c
--- /dev/null
+++ b/tests/ref/fate/mov-heic-demux-still-image-multiple-items
@@ -0,0 +1,11 @@ 
+#format: frame checksums
+#version: 2
+#hash: MD5
+#extradata 0,                             100, 5444bf01e03182c73ae957179d560f4d
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: hevc
+#dimensions 0: 1280x720
+#sar 0: 0/1
+#stream#, dts,        pts, duration,     size, hash
+0,          0,          0,        1,   111554, 03ceabfab39afd2e2e796b9362111f32