summaryrefslogtreecommitdiffstats
path: root/libavcodec/webp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/webp.c')
-rw-r--r--libavcodec/webp.c277
1 files changed, 190 insertions, 87 deletions
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 0e769c3..077bb06 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2013 Aneesh Dogra <aneesh@sugarlabs.org>
* Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,18 +31,22 @@
* Lossless decoder
* Compressed alpha for lossy
*
+ * @author James Almer <jamrial@gmail.com>
+ * Exif metadata
+ * ICC profile
+ *
* Unimplemented:
* - Animation
- * - ICC profile
- * - Exif and XMP metadata
+ * - XMP metadata
*/
#include "libavutil/imgutils.h"
#define BITSTREAM_READER_LE
#include "avcodec.h"
-#include "bitstream.h"
#include "bytestream.h"
+#include "exif.h"
+#include "get_bits.h"
#include "internal.h"
#include "thread.h"
#include "vp8.h"
@@ -183,7 +187,7 @@ typedef struct ImageContext {
typedef struct WebPContext {
VP8Context v; /* VP8 Context used for lossy decoding */
- BitstreamContext bc; /* bitstream reader for main image chunk */
+ GetBitContext gb; /* bitstream reader for main image chunk */
AVFrame *alpha_frame; /* AVFrame for alpha data decompressed from VP8L */
AVCodecContext *avctx; /* parent AVCodecContext */
int initialized; /* set once the VP8 context is initialized */
@@ -192,6 +196,8 @@ typedef struct WebPContext {
enum AlphaFilter alpha_filter; /* filtering method for alpha chunk */
uint8_t *alpha_data; /* alpha chunk data */
int alpha_data_size; /* alpha chunk data size */
+ int has_exif; /* set after an EXIF chunk has been processed */
+ int has_iccp; /* set after an ICCP chunk has been processed */
int width; /* image width */
int height; /* image height */
int lossless; /* indicates lossless or lossy */
@@ -232,41 +238,47 @@ static void image_ctx_free(ImageContext *img)
* - assumes 8-bit table to make reversal simpler
* - assumes max depth of 2 since the max code length for WebP is 15
*/
-static av_always_inline int webp_get_vlc(BitstreamContext *bc, VLC_TYPE (*table)[2])
+static av_always_inline int webp_get_vlc(GetBitContext *gb, VLC_TYPE (*table)[2])
{
int n, nb_bits;
unsigned int index;
int code;
- index = bitstream_peek(bc, 8);
+ OPEN_READER(re, gb);
+ UPDATE_CACHE(re, gb);
+
+ index = SHOW_UBITS(re, gb, 8);
index = ff_reverse[index];
code = table[index][0];
n = table[index][1];
if (n < 0) {
- bitstream_skip(bc, 8);
+ LAST_SKIP_BITS(re, gb, 8);
+ UPDATE_CACHE(re, gb);
nb_bits = -n;
- index = bitstream_peek(bc, nb_bits);
+ index = SHOW_UBITS(re, gb, nb_bits);
index = (ff_reverse[index] >> (8 - nb_bits)) + code;
code = table[index][0];
n = table[index][1];
}
- bitstream_skip(bc, n);
+ SKIP_BITS(re, gb, n);
+
+ CLOSE_READER(re, gb);
return code;
}
-static int huff_reader_get_symbol(HuffReader *r, BitstreamContext *bc)
+static int huff_reader_get_symbol(HuffReader *r, GetBitContext *gb)
{
if (r->simple) {
if (r->nb_symbols == 1)
return r->simple_symbols[0];
else
- return r->simple_symbols[bitstream_read_bit(bc)];
+ return r->simple_symbols[get_bits1(gb)];
} else
- return webp_get_vlc(bc, r->vlc.table);
+ return webp_get_vlc(gb, r->vlc.table);
}
static int huff_reader_build_canonical(HuffReader *r, int *code_lengths,
@@ -298,7 +310,7 @@ static int huff_reader_build_canonical(HuffReader *r, int *code_lengths,
if (max_code_length == 0 || max_code_length > MAX_HUFFMAN_CODE_LENGTH)
return AVERROR(EINVAL);
- codes = av_malloc(alphabet_size * sizeof(*codes));
+ codes = av_malloc_array(alphabet_size, sizeof(*codes));
if (!codes)
return AVERROR(ENOMEM);
@@ -333,15 +345,15 @@ static int huff_reader_build_canonical(HuffReader *r, int *code_lengths,
static void read_huffman_code_simple(WebPContext *s, HuffReader *hc)
{
- hc->nb_symbols = bitstream_read_bit(&s->bc) + 1;
+ hc->nb_symbols = get_bits1(&s->gb) + 1;
- if (bitstream_read_bit(&s->bc))
- hc->simple_symbols[0] = bitstream_read(&s->bc, 8);
+ if (get_bits1(&s->gb))
+ hc->simple_symbols[0] = get_bits(&s->gb, 8);
else
- hc->simple_symbols[0] = bitstream_read_bit(&s->bc);
+ hc->simple_symbols[0] = get_bits1(&s->gb);
if (hc->nb_symbols == 2)
- hc->simple_symbols[1] = bitstream_read(&s->bc, 8);
+ hc->simple_symbols[1] = get_bits(&s->gb, 8);
hc->simple = 1;
}
@@ -353,13 +365,13 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
int *code_lengths = NULL;
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
int i, symbol, max_symbol, prev_code_len, ret;
- int num_codes = 4 + bitstream_read(&s->bc, 4);
+ int num_codes = 4 + get_bits(&s->gb, 4);
if (num_codes > NUM_CODE_LENGTH_CODES)
return AVERROR_INVALIDDATA;
for (i = 0; i < num_codes; i++)
- code_length_code_lengths[code_length_code_order[i]] = bitstream_read(&s->bc, 3);
+ code_length_code_lengths[code_length_code_order[i]] = get_bits(&s->gb, 3);
ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths,
NUM_CODE_LENGTH_CODES);
@@ -372,9 +384,9 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
goto finish;
}
- if (bitstream_read_bit(&s->bc)) {
- int bits = 2 + 2 * bitstream_read(&s->bc, 3);
- max_symbol = 2 + bitstream_read(&s->bc, bits);
+ if (get_bits1(&s->gb)) {
+ int bits = 2 + 2 * get_bits(&s->gb, 3);
+ max_symbol = 2 + get_bits(&s->gb, bits);
if (max_symbol > alphabet_size) {
av_log(s->avctx, AV_LOG_ERROR, "max symbol %d > alphabet size %d\n",
max_symbol, alphabet_size);
@@ -392,7 +404,7 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
if (!max_symbol--)
break;
- code_len = huff_reader_get_symbol(&code_len_hc, &s->bc);
+ code_len = huff_reader_get_symbol(&code_len_hc, &s->gb);
if (code_len < 16) {
/* Code length code [0..15] indicates literal code lengths. */
code_lengths[symbol++] = code_len;
@@ -405,18 +417,18 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
/* Code 16 repeats the previous non-zero value [3..6] times,
* i.e., 3 + ReadBits(2) times. If code 16 is used before a
* non-zero value has been emitted, a value of 8 is repeated. */
- repeat = 3 + bitstream_read(&s->bc, 2);
+ repeat = 3 + get_bits(&s->gb, 2);
length = prev_code_len;
break;
case 17:
/* Code 17 emits a streak of zeros [3..10], i.e.,
* 3 + ReadBits(3) times. */
- repeat = 3 + bitstream_read(&s->bc, 3);
+ repeat = 3 + get_bits(&s->gb, 3);
break;
case 18:
/* Code 18 emits a streak of zeros of length [11..138], i.e.,
* 11 + ReadBits(7) times. */
- repeat = 11 + bitstream_read(&s->bc, 7);
+ repeat = 11 + get_bits(&s->gb, 7);
break;
}
if (symbol + repeat > alphabet_size) {
@@ -443,7 +455,7 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
int w, int h);
#define PARSE_BLOCK_SIZE(w, h) do { \
- block_bits = bitstream_read(&s->bc, 3) + 2; \
+ block_bits = get_bits(&s->gb, 3) + 2; \
blocks_w = FFALIGN((w), 1 << block_bits) >> block_bits; \
blocks_h = FFALIGN((h), 1 << block_bits) >> block_bits; \
} while (0)
@@ -520,7 +532,7 @@ static int parse_transform_color_indexing(WebPContext *s)
int width_bits, index_size, ret, x;
uint8_t *ct;
- index_size = bitstream_read(&s->bc, 8) + 1;
+ index_size = get_bits(&s->gb, 8) + 1;
if (index_size <= 2)
width_bits = 3;
@@ -600,8 +612,8 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
if (ret < 0)
return ret;
- if (bitstream_read_bit(&s->bc)) {
- img->color_cache_bits = bitstream_read(&s->bc, 4);
+ if (get_bits1(&s->gb)) {
+ img->color_cache_bits = get_bits(&s->gb, 4);
if (img->color_cache_bits < 1 || img->color_cache_bits > 11) {
av_log(s->avctx, AV_LOG_ERROR, "invalid color cache bits: %d\n",
img->color_cache_bits);
@@ -616,7 +628,7 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
}
img->nb_huffman_groups = 1;
- if (role == IMAGE_ROLE_ARGB && bitstream_read_bit(&s->bc)) {
+ if (role == IMAGE_ROLE_ARGB && get_bits1(&s->gb)) {
ret = decode_entropy_image(s);
if (ret < 0)
return ret;
@@ -635,7 +647,7 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
if (!j && img->color_cache_bits > 0)
alphabet_size += 1 << img->color_cache_bits;
- if (bitstream_read_bit(&s->bc)) {
+ if (get_bits1(&s->gb)) {
read_huffman_code_simple(s, &hg[j]);
} else {
ret = read_huffman_code_normal(s, &hg[j], alphabet_size);
@@ -654,14 +666,14 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
int v;
hg = get_huffman_group(s, img, x, y);
- v = huff_reader_get_symbol(&hg[HUFF_IDX_GREEN], &s->bc);
+ v = huff_reader_get_symbol(&hg[HUFF_IDX_GREEN], &s->gb);
if (v < NUM_LITERAL_CODES) {
/* literal pixel values */
uint8_t *p = GET_PIXEL(img->frame, x, y);
p[2] = v;
- p[1] = huff_reader_get_symbol(&hg[HUFF_IDX_RED], &s->bc);
- p[3] = huff_reader_get_symbol(&hg[HUFF_IDX_BLUE], &s->bc);
- p[0] = huff_reader_get_symbol(&hg[HUFF_IDX_ALPHA], &s->bc);
+ p[1] = huff_reader_get_symbol(&hg[HUFF_IDX_RED], &s->gb);
+ p[3] = huff_reader_get_symbol(&hg[HUFF_IDX_BLUE], &s->gb);
+ p[0] = huff_reader_get_symbol(&hg[HUFF_IDX_ALPHA], &s->gb);
if (img->color_cache_bits)
color_cache_put(img, AV_RB32(p));
x++;
@@ -680,10 +692,10 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
} else {
int extra_bits = (prefix_code - 2) >> 1;
int offset = 2 + (prefix_code & 1) << extra_bits;
- length = offset + bitstream_read(&s->bc, extra_bits) + 1;
+ length = offset + get_bits(&s->gb, extra_bits) + 1;
}
- prefix_code = huff_reader_get_symbol(&hg[HUFF_IDX_DIST], &s->bc);
- if (prefix_code > 39) {
+ prefix_code = huff_reader_get_symbol(&hg[HUFF_IDX_DIST], &s->gb);
+ if (prefix_code > 39U) {
av_log(s->avctx, AV_LOG_ERROR,
"distance prefix code too large: %d\n", prefix_code);
return AVERROR_INVALIDDATA;
@@ -693,7 +705,7 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
} else {
int extra_bits = prefix_code - 2 >> 1;
int offset = 2 + (prefix_code & 1) << extra_bits;
- distance = offset + bitstream_read(&s->bc, extra_bits) + 1;
+ distance = offset + get_bits(&s->gb, extra_bits) + 1;
}
/* find reference location */
@@ -1022,32 +1034,32 @@ static int apply_color_indexing_transform(WebPContext *s)
ImageContext *img;
ImageContext *pal;
int i, x, y;
- uint8_t *p, *pi;
+ uint8_t *p;
img = &s->image[IMAGE_ROLE_ARGB];
pal = &s->image[IMAGE_ROLE_COLOR_INDEXING];
if (pal->size_reduction > 0) {
- BitstreamContext bc_g;
+ GetBitContext gb_g;
uint8_t *line;
int pixel_bits = 8 >> pal->size_reduction;
- line = av_malloc(img->frame->linesize[0]);
+ line = av_malloc(img->frame->linesize[0] + AV_INPUT_BUFFER_PADDING_SIZE);
if (!line)
return AVERROR(ENOMEM);
for (y = 0; y < img->frame->height; y++) {
p = GET_PIXEL(img->frame, 0, y);
memcpy(line, p, img->frame->linesize[0]);
- bitstream_init8(&bc_g, line, img->frame->linesize[0]);
- bitstream_skip(&bc_g, 16);
+ init_get_bits(&gb_g, line, img->frame->linesize[0] * 8);
+ skip_bits(&gb_g, 16);
i = 0;
for (x = 0; x < img->frame->width; x++) {
p = GET_PIXEL(img->frame, x, y);
- p[2] = bitstream_read(&bc_g, pixel_bits);
+ p[2] = get_bits(&gb_g, pixel_bits);
i++;
if (i == 1 << pal->size_reduction) {
- bitstream_skip(&bc_g, 24);
+ skip_bits(&gb_g, 24);
i = 0;
}
}
@@ -1055,22 +1067,54 @@ static int apply_color_indexing_transform(WebPContext *s)
av_free(line);
}
- for (y = 0; y < img->frame->height; y++) {
- for (x = 0; x < img->frame->width; x++) {
- p = GET_PIXEL(img->frame, x, y);
- i = p[2];
- if (i >= pal->frame->width) {
- av_log(s->avctx, AV_LOG_ERROR, "invalid palette index %d\n", i);
- return AVERROR_INVALIDDATA;
+ // switch to local palette if it's worth initializing it
+ if (img->frame->height * img->frame->width > 300) {
+ uint8_t palette[256 * 4];
+ const int size = pal->frame->width * 4;
+ av_assert0(size <= 1024U);
+ memcpy(palette, GET_PIXEL(pal->frame, 0, 0), size); // copy palette
+ // set extra entries to transparent black
+ memset(palette + size, 0, 256 * 4 - size);
+ for (y = 0; y < img->frame->height; y++) {
+ for (x = 0; x < img->frame->width; x++) {
+ p = GET_PIXEL(img->frame, x, y);
+ i = p[2];
+ AV_COPY32(p, &palette[i * 4]);
+ }
+ }
+ } else {
+ for (y = 0; y < img->frame->height; y++) {
+ for (x = 0; x < img->frame->width; x++) {
+ p = GET_PIXEL(img->frame, x, y);
+ i = p[2];
+ if (i >= pal->frame->width) {
+ AV_WB32(p, 0x00000000);
+ } else {
+ const uint8_t *pi = GET_PIXEL(pal->frame, i, 0);
+ AV_COPY32(p, pi);
+ }
}
- pi = GET_PIXEL(pal->frame, i, 0);
- AV_COPY32(p, pi);
}
}
return 0;
}
+static void update_canvas_size(AVCodecContext *avctx, int w, int h)
+{
+ WebPContext *s = avctx->priv_data;
+ if (s->width && s->width != w) {
+ av_log(avctx, AV_LOG_WARNING, "Width mismatch. %d != %d\n",
+ s->width, w);
+ }
+ s->width = w;
+ if (s->height && s->height != h) {
+ av_log(avctx, AV_LOG_WARNING, "Height mismatch. %d != %d\n",
+ s->height, h);
+ }
+ s->height = h;
+}
+
static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
int *got_frame, uint8_t *data_start,
unsigned int data_size, int is_alpha_chunk)
@@ -1083,36 +1127,28 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
avctx->pix_fmt = AV_PIX_FMT_ARGB;
}
- ret = bitstream_init8(&s->bc, data_start, data_size);
+ ret = init_get_bits8(&s->gb, data_start, data_size);
if (ret < 0)
return ret;
if (!is_alpha_chunk) {
- if (bitstream_read(&s->bc, 8) != 0x2F) {
+ if (get_bits(&s->gb, 8) != 0x2F) {
av_log(avctx, AV_LOG_ERROR, "Invalid WebP Lossless signature\n");
return AVERROR_INVALIDDATA;
}
- w = bitstream_read(&s->bc, 14) + 1;
- h = bitstream_read(&s->bc, 14) + 1;
- if (s->width && s->width != w) {
- av_log(avctx, AV_LOG_WARNING, "Width mismatch. %d != %d\n",
- s->width, w);
- }
- s->width = w;
- if (s->height && s->height != h) {
- av_log(avctx, AV_LOG_WARNING, "Height mismatch. %d != %d\n",
- s->width, w);
- }
- s->height = h;
+ w = get_bits(&s->gb, 14) + 1;
+ h = get_bits(&s->gb, 14) + 1;
+
+ update_canvas_size(avctx, w, h);
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
return ret;
- s->has_alpha = bitstream_read_bit(&s->bc);
+ s->has_alpha = get_bits1(&s->gb);
- if (bitstream_read(&s->bc, 3) != 0x0) {
+ if (get_bits(&s->gb, 3) != 0x0) {
av_log(avctx, AV_LOG_ERROR, "Invalid WebP Lossless version\n");
return AVERROR_INVALIDDATA;
}
@@ -1127,9 +1163,8 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
s->nb_transforms = 0;
s->reduced_width = 0;
used = 0;
- while (bitstream_read_bit(&s->bc)) {
- enum TransformType transform = bitstream_read(&s->bc, 2);
- s->transforms[s->nb_transforms++] = transform;
+ while (get_bits1(&s->gb)) {
+ enum TransformType transform = get_bits(&s->gb, 2);
if (used & (1 << transform)) {
av_log(avctx, AV_LOG_ERROR, "Transform %d used more than once\n",
transform);
@@ -1137,6 +1172,7 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
goto free_and_return;
}
used |= (1 << transform);
+ s->transforms[s->nb_transforms++] = transform;
switch (transform) {
case PREDICTOR_TRANSFORM:
ret = parse_transform_predictor(s);
@@ -1300,11 +1336,8 @@ static int vp8_lossy_decode_frame(AVCodecContext *avctx, AVFrame *p,
ff_vp8_decode_init(avctx);
s->initialized = 1;
s->v.actually_webp = 1;
- if (s->has_alpha)
- avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
- else
- avctx->pix_fmt = AV_PIX_FMT_YUV420P;
}
+ avctx->pix_fmt = s->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
s->lossless = 0;
if (data_size > INT_MAX) {
@@ -1317,6 +1350,14 @@ static int vp8_lossy_decode_frame(AVCodecContext *avctx, AVFrame *p,
pkt.size = data_size;
ret = ff_vp8_decode_frame(avctx, p, got_frame, &pkt);
+ if (ret < 0)
+ return ret;
+
+ if (!*got_frame)
+ return AVERROR_INVALIDDATA;
+
+ update_canvas_size(avctx, avctx->width, avctx->height);
+
if (s->has_alpha) {
ret = vp8_lossy_decode_alpha(avctx, p, s->alpha_data,
s->alpha_data_size);
@@ -1341,6 +1382,8 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->height = 0;
*got_frame = 0;
s->has_alpha = 0;
+ s->has_exif = 0;
+ s->has_iccp = 0;
bytestream2_init(&gb, avpkt->data, avpkt->size);
if (bytestream2_get_bytes_left(&gb) < 12)
@@ -1390,10 +1433,15 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
chunk_size, 0);
if (ret < 0)
return ret;
+ avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS;
}
bytestream2_skip(&gb, chunk_size);
break;
case MKTAG('V', 'P', '8', 'X'):
+ if (s->width || s->height || *got_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Canvas dimensions are already set\n");
+ return AVERROR_INVALIDDATA;
+ }
vp8x_flags = bytestream2_get_byte(&gb);
bytestream2_skip(&gb, 3);
s->width = bytestream2_get_le24(&gb) + 1;
@@ -1433,13 +1481,68 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
break;
}
- case MKTAG('I', 'C', 'C', 'P'):
+ case MKTAG('E', 'X', 'I', 'F'): {
+ int le, ifd_offset, exif_offset = bytestream2_tell(&gb);
+ AVDictionary *exif_metadata = NULL;
+ GetByteContext exif_gb;
+
+ if (s->has_exif) {
+ av_log(avctx, AV_LOG_VERBOSE, "Ignoring extra EXIF chunk\n");
+ goto exif_end;
+ }
+ if (!(vp8x_flags & VP8X_FLAG_EXIF_METADATA))
+ av_log(avctx, AV_LOG_WARNING,
+ "EXIF chunk present, but Exif bit not set in the "
+ "VP8X header\n");
+
+ s->has_exif = 1;
+ bytestream2_init(&exif_gb, avpkt->data + exif_offset,
+ avpkt->size - exif_offset);
+ if (ff_tdecode_header(&exif_gb, &le, &ifd_offset) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid TIFF header "
+ "in Exif data\n");
+ goto exif_end;
+ }
+
+ bytestream2_seek(&exif_gb, ifd_offset, SEEK_SET);
+ if (ff_exif_decode_ifd(avctx, &exif_gb, le, 0, &exif_metadata) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error decoding Exif data\n");
+ goto exif_end;
+ }
+
+ av_dict_copy(&((AVFrame *) data)->metadata, exif_metadata, 0);
+
+exif_end:
+ av_dict_free(&exif_metadata);
+ bytestream2_skip(&gb, chunk_size);
+ break;
+ }
+ case MKTAG('I', 'C', 'C', 'P'): {
+ AVFrameSideData *sd;
+
+ if (s->has_iccp) {
+ av_log(avctx, AV_LOG_VERBOSE, "Ignoring extra ICCP chunk\n");
+ bytestream2_skip(&gb, chunk_size);
+ break;
+ }
+ if (!(vp8x_flags & VP8X_FLAG_ICC))
+ av_log(avctx, AV_LOG_WARNING,
+ "ICCP chunk present, but ICC Profile bit not set in the "
+ "VP8X header\n");
+
+ s->has_iccp = 1;
+ sd = av_frame_new_side_data(p, AV_FRAME_DATA_ICC_PROFILE, chunk_size);
+ if (!sd)
+ return AVERROR(ENOMEM);
+
+ bytestream2_get_buffer(&gb, sd->data, chunk_size);
+ break;
+ }
case MKTAG('A', 'N', 'I', 'M'):
case MKTAG('A', 'N', 'M', 'F'):
- case MKTAG('E', 'X', 'I', 'F'):
case MKTAG('X', 'M', 'P', ' '):
AV_WL32(chunk_str, chunk_type);
- av_log(avctx, AV_LOG_VERBOSE, "skipping unsupported chunk: %s\n",
+ av_log(avctx, AV_LOG_WARNING, "skipping unsupported chunk: %s\n",
chunk_str);
bytestream2_skip(&gb, chunk_size);
break;
OpenPOWER on IntegriCloud