*
* @author James Almer <jamrial@gmail.com>
* Exif metadata
+ * ICC profile
*
* Unimplemented:
* - Animation
- * - ICC profile
* - XMP metadata
*/
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 */
length = offset + get_bits(&s->gb, extra_bits) + 1;
}
prefix_code = huff_reader_get_symbol(&hg[HUFF_IDX_DIST], &s->gb);
- if (prefix_code > 39) {
+ if (prefix_code > 39U) {
av_log(s->avctx, AV_LOG_ERROR,
"distance prefix code too large: %d\n", prefix_code);
return AVERROR_INVALIDDATA;
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);
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)
w = get_bits(&s->gb, 14) + 1;
h = get_bits(&s->gb, 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;
+
+ update_canvas_size(avctx, w, h);
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
if (!s->initialized) {
ff_vp8_decode_init(avctx);
s->initialized = 1;
- if (s->has_alpha)
- avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
}
+ avctx->pix_fmt = s->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
s->lossless = 0;
if (data_size > INT_MAX) {
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);
*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)
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;
bytestream2_skip(&gb, chunk_size);
break;
}
- case MKTAG('I', 'C', 'C', 'P'):
+ 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('X', 'M', 'P', ' '):