* [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
@ 2022-03-03 23:57 Vignesh Venkatasubramanian
2022-03-15 21:38 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-03 23:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Vignesh Venkatasubramanian
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 | 142 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 143 insertions(+)
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 625dea8421..cc0a8e1ca9 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -306,6 +306,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 68b6d7f075..d260024e47 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1126,6 +1126,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);
@@ -7173,6 +7174,146 @@ cleanup:
return ret;
}
+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;
+ int i, j;
+ 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 != 0) {
+ 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) ? 0 : (value & 0xF);
+ if (index_size != 0) {
+ 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;
+ sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
+
+ for (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 (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 },
@@ -7272,6 +7413,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('d','v','v','C'), mov_read_dvcc_dvvc },
{ MKTAG('d','v','w','C'), mov_read_dvcc_dvvc },
{ MKTAG('k','i','n','d'), mov_read_kind },
+{ MKTAG('i','l','o','c'), mov_read_iloc },
{ 0, NULL }
};
--
2.35.1.616.g0bdcbb4464-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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-03 23:57 [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing Vignesh Venkatasubramanian
@ 2022-03-15 21:38 ` Vignesh Venkatasubramanian
2022-03-16 12:41 ` Lynne
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-15 21:38 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Thu, Mar 3, 2022 at 3:58 PM Vignesh Venkatasubramanian
<vigneshv@google.com> 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
>
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
> libavformat/isom.h | 1 +
> libavformat/mov.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 143 insertions(+)
>
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index 625dea8421..cc0a8e1ca9 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -306,6 +306,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 68b6d7f075..d260024e47 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -1126,6 +1126,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);
>
> @@ -7173,6 +7174,146 @@ cleanup:
> return ret;
> }
>
> +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;
> + int i, j;
> + 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 != 0) {
> + 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) ? 0 : (value & 0xF);
> + if (index_size != 0) {
> + 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;
> + sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
> +
> + for (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 (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 },
> @@ -7272,6 +7413,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
> { MKTAG('d','v','v','C'), mov_read_dvcc_dvvc },
> { MKTAG('d','v','w','C'), mov_read_dvcc_dvvc },
> { MKTAG('k','i','n','d'), mov_read_kind },
> +{ MKTAG('i','l','o','c'), mov_read_iloc },
> { 0, NULL }
> };
>
> --
> 2.35.1.616.g0bdcbb4464-goog
>
Ping on this patch please.
--
Vignesh
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-15 21:38 ` Vignesh Venkatasubramanian
@ 2022-03-16 12:41 ` Lynne
2022-03-16 16:57 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Lynne @ 2022-03-16 12:41 UTC (permalink / raw)
To: FFmpeg development discussions and patches
15 Mar 2022, 22:38 by vigneshv-at-google.com@ffmpeg.org:
> On Thu, Mar 3, 2022 at 3:58 PM Vignesh Venkatasubramanian
> <vigneshv@google.com> 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
>>
>> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
>> ---
>> libavformat/isom.h | 1 +
>> libavformat/mov.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 143 insertions(+)
>>
>> diff --git a/libavformat/isom.h b/libavformat/isom.h
>> index 625dea8421..cc0a8e1ca9 100644
>> --- a/libavformat/isom.h
>> +++ b/libavformat/isom.h
>> @@ -306,6 +306,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 68b6d7f075..d260024e47 100644
>> --- a/libavformat/mov.c
>> +++ b/libavformat/mov.c
>> @@ -1126,6 +1126,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);
>>
>> @@ -7173,6 +7174,146 @@ cleanup:
>> return ret;
>> }
>>
>> +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;
>> + int i, j;
>> + 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 != 0) {
>> + 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) ? 0 : (value & 0xF);
>> + if (index_size != 0) {
>> + 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;
>> + sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
>> +
>> + for (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 (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 },
>> @@ -7272,6 +7413,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
>> { MKTAG('d','v','v','C'), mov_read_dvcc_dvvc },
>> { MKTAG('d','v','w','C'), mov_read_dvcc_dvvc },
>> { MKTAG('k','i','n','d'), mov_read_kind },
>> +{ MKTAG('i','l','o','c'), mov_read_iloc },
>> { 0, NULL }
>> };
>>
>> --
>> 2.35.1.616.g0bdcbb4464-goog
>>
>
> Ping on this patch please.
>
Fix the coding style, please.
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-16 12:41 ` Lynne
@ 2022-03-16 16:57 ` Vignesh Venkatasubramanian
2022-03-16 17:00 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-16 16:57 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Wed, Mar 16, 2022 at 5:41 AM Lynne <dev@lynne.ee> wrote:
>
> 15 Mar 2022, 22:38 by vigneshv-at-google.com@ffmpeg.org:
>
> > On Thu, Mar 3, 2022 at 3:58 PM Vignesh Venkatasubramanian
> > <vigneshv@google.com> 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
> >>
> >> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> >> ---
> >> libavformat/isom.h | 1 +
> >> libavformat/mov.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
> >> 2 files changed, 143 insertions(+)
> >>
> >> diff --git a/libavformat/isom.h b/libavformat/isom.h
> >> index 625dea8421..cc0a8e1ca9 100644
> >> --- a/libavformat/isom.h
> >> +++ b/libavformat/isom.h
> >> @@ -306,6 +306,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 68b6d7f075..d260024e47 100644
> >> --- a/libavformat/mov.c
> >> +++ b/libavformat/mov.c
> >> @@ -1126,6 +1126,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);
> >>
> >> @@ -7173,6 +7174,146 @@ cleanup:
> >> return ret;
> >> }
> >>
> >> +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;
> >> + int i, j;
> >> + 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 != 0) {
> >> + 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) ? 0 : (value & 0xF);
> >> + if (index_size != 0) {
> >> + 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;
> >> + sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
> >> +
> >> + for (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 (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 },
> >> @@ -7272,6 +7413,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
> >> { MKTAG('d','v','v','C'), mov_read_dvcc_dvvc },
> >> { MKTAG('d','v','w','C'), mov_read_dvcc_dvvc },
> >> { MKTAG('k','i','n','d'), mov_read_kind },
> >> +{ MKTAG('i','l','o','c'), mov_read_iloc },
> >> { 0, NULL }
> >> };
> >>
> >> --
> >> 2.35.1.616.g0bdcbb4464-goog
> >>
> >
> > Ping on this patch please.
> >
>
> Fix the coding style, please.
I am sorry, can you please be a bit more specific? I was trying to
follow the code style that is consistent with the rest of the file.
> _______________________________________________
> 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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-16 16:57 ` Vignesh Venkatasubramanian
@ 2022-03-16 17:00 ` Vignesh Venkatasubramanian
2022-03-16 17:02 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-16 17:00 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Vignesh Venkatasubramanian
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 | 142 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 143 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..d598f9b248 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,146 @@ 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;
+ int i, j;
+ 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) ? 0 : (value & 0xF);
+ if (index_size != 0) {
+ 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;
+ sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
+
+ for (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 (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 +7673,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.35.1.723.g4982287a31-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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-16 17:00 ` Vignesh Venkatasubramanian
@ 2022-03-16 17:02 ` Vignesh Venkatasubramanian
2022-03-22 21:56 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-16 17:02 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Vignesh Venkatasubramanian
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 | 142 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 143 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..3af49427b9 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,146 @@ 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;
+ int i, j;
+ 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) ? 0 : (value & 0xF);
+ if (index_size != 0) {
+ 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;
+ sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
+
+ for (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 (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 +7673,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.35.1.723.g4982287a31-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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-16 17:02 ` Vignesh Venkatasubramanian
@ 2022-03-22 21:56 ` Vignesh Venkatasubramanian
2022-03-28 17:07 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-22 21:56 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Wed, Mar 16, 2022 at 10:02 AM Vignesh Venkatasubramanian
<vigneshv@google.com> 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
>
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
> libavformat/isom.h | 1 +
> libavformat/mov.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 143 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..3af49427b9 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,146 @@ 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;
> + int i, j;
> + 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) ? 0 : (value & 0xF);
> + if (index_size != 0) {
> + 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;
> + sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
> +
> + for (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 (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 +7673,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.35.1.723.g4982287a31-goog
>
Another ping on this?
--
Vignesh
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-22 21:56 ` Vignesh Venkatasubramanian
@ 2022-03-28 17:07 ` Vignesh Venkatasubramanian
2022-03-28 17:13 ` Paul B Mahol
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-28 17:07 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Tue, Mar 22, 2022 at 2:56 PM Vignesh Venkatasubramanian
<vigneshv@google.com> wrote:
>
> On Wed, Mar 16, 2022 at 10:02 AM Vignesh Venkatasubramanian
> <vigneshv@google.com> 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
> >
> > Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> > ---
> > libavformat/isom.h | 1 +
> > libavformat/mov.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 143 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..3af49427b9 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,146 @@ 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;
> > + int i, j;
> > + 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) ? 0 : (value & 0xF);
> > + if (index_size != 0) {
> > + 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;
> > + sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
> > +
> > + for (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 (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 +7673,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.35.1.723.g4982287a31-goog
> >
>
> Another ping on this?
>
>
> --
> Vignesh
If there are no more comments, can this be merged please?
--
Vignesh
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-28 17:07 ` Vignesh Venkatasubramanian
@ 2022-03-28 17:13 ` Paul B Mahol
2022-03-28 18:10 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Paul B Mahol @ 2022-03-28 17:13 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Mon, Mar 28, 2022 at 7:07 PM Vignesh Venkatasubramanian <
vigneshv-at-google.com@ffmpeg.org> wrote:
> On Tue, Mar 22, 2022 at 2:56 PM Vignesh Venkatasubramanian
> <vigneshv@google.com> wrote:
> >
> > On Wed, Mar 16, 2022 at 10:02 AM Vignesh Venkatasubramanian
> > <vigneshv@google.com> 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
> > >
> > > Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> > > ---
> > > libavformat/isom.h | 1 +
> > > libavformat/mov.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
> > > 2 files changed, 143 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..3af49427b9 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,146 @@ 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;
> > > + int i, j;
> > > + 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) ? 0 : (value & 0xF);
> > > + if (index_size != 0) {
> > > + 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;
> > > + sc->stts_data[0].duration = 0; // Not used for still images. But
> needed by mov_build_index.
> > > +
> > > + for (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 (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 +7673,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.35.1.723.g4982287a31-goog
> > >
> >
> > Another ping on this?
> >
> >
> > --
> > Vignesh
>
> If there are no more comments, can this be merged please?
>
Nope. fix code style first.
Look at other files for example how style should look.
I stopped counting after seeing ++i instead of i++
> --
> Vignesh
> _______________________________________________
> 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".
>
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-28 17:13 ` Paul B Mahol
@ 2022-03-28 18:10 ` Vignesh Venkatasubramanian
2022-03-28 18:11 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-28 18:10 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Mon, Mar 28, 2022 at 10:11 AM Paul B Mahol <onemda@gmail.com> wrote:
>
> On Mon, Mar 28, 2022 at 7:07 PM Vignesh Venkatasubramanian <
> vigneshv-at-google.com@ffmpeg.org> wrote:
>
> > On Tue, Mar 22, 2022 at 2:56 PM Vignesh Venkatasubramanian
> > <vigneshv@google.com> wrote:
> > >
> > > On Wed, Mar 16, 2022 at 10:02 AM Vignesh Venkatasubramanian
> > > <vigneshv@google.com> 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
> > > >
> > > > Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> > > > ---
> > > > libavformat/isom.h | 1 +
> > > > libavformat/mov.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
> > > > 2 files changed, 143 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..3af49427b9 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,146 @@ 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;
> > > > + int i, j;
> > > > + 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) ? 0 : (value & 0xF);
> > > > + if (index_size != 0) {
> > > > + 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;
> > > > + sc->stts_data[0].duration = 0; // Not used for still images. But
> > needed by mov_build_index.
> > > > +
> > > > + for (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 (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 +7673,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.35.1.723.g4982287a31-goog
> > > >
> > >
> > > Another ping on this?
> > >
> > >
> > > --
> > > Vignesh
> >
> > If there are no more comments, can this be merged please?
> >
>
> Nope. fix code style first.
>
> Look at other files for example how style should look.
>
> I stopped counting after seeing ++i instead of i++
>
There are several instances of ++i in for loops in this file. So i
thought that was okay. I have updated it to i++. I really am not sure
what other style mismatches you are referring to. Can you please
explain and i will fix them? :)
>
> > --
> > Vignesh
> > _______________________________________________
> > 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".
> >
> _______________________________________________
> 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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-28 18:10 ` Vignesh Venkatasubramanian
@ 2022-03-28 18:11 ` Vignesh Venkatasubramanian
2022-03-28 19:11 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-28 18:11 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Vignesh Venkatasubramanian
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 | 142 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 143 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..eb9a529ceb 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,146 @@ 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;
+ int i, j;
+ 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) ? 0 : (value & 0xF);
+ if (index_size != 0) {
+ 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;
+ sc->stts_data[0].duration = 0; // Not used for still images. But needed by mov_build_index.
+
+ for (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 (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 +7673,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.35.1.1021.g381101b075-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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-28 18:11 ` Vignesh Venkatasubramanian
@ 2022-03-28 19:11 ` Vignesh Venkatasubramanian
2022-04-18 22:03 ` Vignesh Venkatasubramanian
2022-04-19 20:21 ` Paul B Mahol
0 siblings, 2 replies; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-03-28 19:11 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Vignesh Venkatasubramanian
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 | 148 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 149 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..fb6d071b95 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,152 @@ 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 +7679,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.35.1.1021.g381101b075-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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-28 19:11 ` Vignesh Venkatasubramanian
@ 2022-04-18 22:03 ` Vignesh Venkatasubramanian
2022-04-19 20:21 ` Paul B Mahol
1 sibling, 0 replies; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-18 22:03 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Mon, Mar 28, 2022 at 12:11 PM Vignesh Venkatasubramanian
<vigneshv@google.com> 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
>
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
> libavformat/isom.h | 1 +
> libavformat/mov.c | 148 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 149 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..fb6d071b95 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,152 @@ 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 +7679,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.35.1.1021.g381101b075-goog
>
Another ping on this one.
--
Vignesh
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-03-28 19:11 ` Vignesh Venkatasubramanian
2022-04-18 22:03 ` Vignesh Venkatasubramanian
@ 2022-04-19 20:21 ` Paul B Mahol
2022-04-19 20:55 ` Vignesh Venkatasubramanian
1 sibling, 1 reply; 26+ messages in thread
From: Paul B Mahol @ 2022-04-19 20:21 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Vignesh Venkatasubramanian
On Mon, Mar 28, 2022 at 9:12 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
>
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
> libavformat/isom.h | 1 +
> libavformat/mov.c | 148 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 149 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..fb6d071b95 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,152 @@ 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);
> + }
>
Here and everywhere else, remove excessive {/}, they are not needed for
one liners.
+ 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 +7679,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.35.1.1021.g381101b075-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".
>
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-19 20:21 ` Paul B Mahol
@ 2022-04-19 20:55 ` Vignesh Venkatasubramanian
2022-04-19 20:57 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-19 20:55 UTC (permalink / raw)
To: Paul B Mahol; +Cc: FFmpeg development discussions and patches
On Tue, Apr 19, 2022 at 1:18 PM Paul B Mahol <onemda@gmail.com> wrote:
>
>
>
> On Mon, Mar 28, 2022 at 9:12 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
>>
>> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
>> ---
>> libavformat/isom.h | 1 +
>> libavformat/mov.c | 148 +++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 149 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..fb6d071b95 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,152 @@ 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);
>> + }
>
>
> Here and everywhere else, remove excessive {/}, they are not needed for one liners.
>
Done.
>> + 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 +7679,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.35.1.1021.g381101b075-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".
--
Vignesh
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-19 20:55 ` Vignesh Venkatasubramanian
@ 2022-04-19 20:57 ` Vignesh Venkatasubramanian
2022-04-19 21:19 ` Paul B Mahol
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-19 20:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Vignesh Venkatasubramanian
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(+)
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-19 20:57 ` Vignesh Venkatasubramanian
@ 2022-04-19 21:19 ` Paul B Mahol
2022-04-20 4:24 ` Gyan Doshi
0 siblings, 1 reply; 26+ messages in thread
From: Paul B Mahol @ 2022-04-19 21:19 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Vignesh Venkatasubramanian
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".
>
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-19 21:19 ` Paul B Mahol
@ 2022-04-20 4:24 ` Gyan Doshi
2022-04-21 9:00 ` Gyan Doshi
0 siblings, 1 reply; 26+ messages in thread
From: Gyan Doshi @ 2022-04-20 4:24 UTC (permalink / raw)
To: ffmpeg-devel
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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-20 4:24 ` Gyan Doshi
@ 2022-04-21 9:00 ` Gyan Doshi
2022-04-21 16:16 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Gyan Doshi @ 2022-04-21 9:00 UTC (permalink / raw)
To: ffmpeg-devel
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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-21 9:00 ` Gyan Doshi
@ 2022-04-21 16:16 ` Vignesh Venkatasubramanian
2022-04-22 4:17 ` Gyan Doshi
2022-04-24 18:43 ` Vignesh Venkatasubramanian
0 siblings, 2 replies; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-21 16:16 UTC (permalink / raw)
To: FFmpeg development discussions and patches
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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-21 16:16 ` Vignesh Venkatasubramanian
@ 2022-04-22 4:17 ` Gyan Doshi
2022-04-22 18:58 ` Vignesh Venkatasubramanian
2022-04-24 18:43 ` Vignesh Venkatasubramanian
1 sibling, 1 reply; 26+ messages in thread
From: Gyan Doshi @ 2022-04-22 4:17 UTC (permalink / raw)
To: ffmpeg-devel
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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-22 4:17 ` Gyan Doshi
@ 2022-04-22 18:58 ` Vignesh Venkatasubramanian
2022-04-22 18:59 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-22 18:58 UTC (permalink / raw)
To: FFmpeg development discussions and patches
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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-22 18:58 ` Vignesh Venkatasubramanian
@ 2022-04-22 18:59 ` Vignesh Venkatasubramanian
2022-04-23 8:13 ` Gyan Doshi
0 siblings, 1 reply; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-22 18:59 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Vignesh Venkatasubramanian
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 | 141 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 142 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..39feb9fba6 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,145 @@ 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) {
+ av_log(c->fc, AV_LOG_ERROR, "iloc: index_size != 0 not supported.\n");
+ 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.
+ av_log(c->fc, AV_LOG_ERROR, "iloc: item_count > 1 not supported.\n");
+ 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.
+ av_log(c->fc, AV_LOG_ERROR, "iloc: extent_count > 1 not supported.\n");
+ 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 +7672,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.rc2.479.g8af0fa9b8e-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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-22 18:59 ` Vignesh Venkatasubramanian
@ 2022-04-23 8:13 ` Gyan Doshi
2022-04-24 18:41 ` Vignesh Venkatasubramanian
0 siblings, 1 reply; 26+ messages in thread
From: Gyan Doshi @ 2022-04-23 8:13 UTC (permalink / raw)
To: ffmpeg-devel
Removed some trailing whitespace, edited commit msg and pushed as
499e245b856733c3bbcd3ba23b406729343ed5fe
Consider adding avif to extensions in the AVInputFormat
Regards,
Gyan
On 2022-04-23 12:29 am, Vignesh Venkatasubramanian 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
>
> Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> ---
> libavformat/isom.h | 1 +
> libavformat/mov.c | 141 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 142 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..39feb9fba6 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,145 @@ 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) {
> + av_log(c->fc, AV_LOG_ERROR, "iloc: index_size != 0 not supported.\n");
> + 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.
> + av_log(c->fc, AV_LOG_ERROR, "iloc: item_count > 1 not supported.\n");
> + 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.
> + av_log(c->fc, AV_LOG_ERROR, "iloc: extent_count > 1 not supported.\n");
> + 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 +7672,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 }
> };
>
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-23 8:13 ` Gyan Doshi
@ 2022-04-24 18:41 ` Vignesh Venkatasubramanian
0 siblings, 0 replies; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-24 18:41 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Sat, Apr 23, 2022 at 1:14 AM Gyan Doshi <ffmpeg@gyani.pro> wrote:
>
> Removed some trailing whitespace, edited commit msg and pushed as
> 499e245b856733c3bbcd3ba23b406729343ed5fe
>
Thanks for merging!
> Consider adding avif to extensions in the AVInputFormat
Sorry this was an oversight. I thought I had already done this. I have
sent another patch to do this:
http://ffmpeg.org/pipermail/ffmpeg-devel/2022-April/295648.html
>
> Regards,
> Gyan
>
> On 2022-04-23 12:29 am, Vignesh Venkatasubramanian 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
> >
> > Signed-off-by: Vignesh Venkatasubramanian <vigneshv@google.com>
> > ---
> > libavformat/isom.h | 1 +
> > libavformat/mov.c | 141 +++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 142 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..39feb9fba6 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,145 @@ 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) {
> > + av_log(c->fc, AV_LOG_ERROR, "iloc: index_size != 0 not supported.\n");
> > + 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.
> > + av_log(c->fc, AV_LOG_ERROR, "iloc: item_count > 1 not supported.\n");
> > + 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.
> > + av_log(c->fc, AV_LOG_ERROR, "iloc: extent_count > 1 not supported.\n");
> > + 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 +7672,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 }
> > };
> >
>
> _______________________________________________
> 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
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing
2022-04-21 16:16 ` Vignesh Venkatasubramanian
2022-04-22 4:17 ` Gyan Doshi
@ 2022-04-24 18:43 ` Vignesh Venkatasubramanian
1 sibling, 0 replies; 26+ messages in thread
From: Vignesh Venkatasubramanian @ 2022-04-24 18:43 UTC (permalink / raw)
To: FFmpeg development discussions and patches
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
--
Vignesh
_______________________________________________
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".
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2022-04-24 18:43 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-03 23:57 [FFmpeg-devel] [PATCH] avformat/mov: Add support for still image AVIF parsing Vignesh Venkatasubramanian
2022-03-15 21:38 ` Vignesh Venkatasubramanian
2022-03-16 12:41 ` Lynne
2022-03-16 16:57 ` Vignesh Venkatasubramanian
2022-03-16 17:00 ` Vignesh Venkatasubramanian
2022-03-16 17:02 ` Vignesh Venkatasubramanian
2022-03-22 21:56 ` Vignesh Venkatasubramanian
2022-03-28 17:07 ` Vignesh Venkatasubramanian
2022-03-28 17:13 ` Paul B Mahol
2022-03-28 18:10 ` Vignesh Venkatasubramanian
2022-03-28 18:11 ` Vignesh Venkatasubramanian
2022-03-28 19:11 ` Vignesh Venkatasubramanian
2022-04-18 22:03 ` Vignesh Venkatasubramanian
2022-04-19 20:21 ` Paul B Mahol
2022-04-19 20:55 ` Vignesh Venkatasubramanian
2022-04-19 20:57 ` Vignesh Venkatasubramanian
2022-04-19 21:19 ` Paul B Mahol
2022-04-20 4:24 ` Gyan Doshi
2022-04-21 9:00 ` Gyan Doshi
2022-04-21 16:16 ` Vignesh Venkatasubramanian
2022-04-22 4:17 ` Gyan Doshi
2022-04-22 18:58 ` Vignesh Venkatasubramanian
2022-04-22 18:59 ` Vignesh Venkatasubramanian
2022-04-23 8:13 ` Gyan Doshi
2022-04-24 18:41 ` Vignesh Venkatasubramanian
2022-04-24 18:43 ` Vignesh Venkatasubramanian
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git