Quoting Vittorio Giovara (2015-03-10 02:28:55)
> Signed-off-by: Vittorio Giovara <[email protected]>
> ---
> Addressed all reviews, updated to use a full avcodeccontext rather than
> using mjpeg function directly, simplified init() thanks to the new internal
> capability and fixed test to use simple idct.
>
> Vittorio
>
> Changelog | 1 +
> configure | 2 +
> doc/general.texi | 1 +
> libavcodec/Makefile | 1 +
> libavcodec/allcodecs.c | 1 +
> libavcodec/avcodec.h | 1 +
> libavcodec/codec_desc.c | 7 +
> libavcodec/tdsc.c | 629
> ++++++++++++++++++++++++++++++++++++++++++++++++
> libavcodec/version.h | 2 +-
> libavformat/riff.c | 1 +
> tests/fate/video.mak | 3 +
> tests/ref/fate/tdsc | 42 ++++
> 12 files changed, 690 insertions(+), 1 deletion(-)
> create mode 100644 libavcodec/tdsc.c
> create mode 100644 tests/ref/fate/tdsc
>
> diff --git a/Changelog b/Changelog
> index 31a550d..7dc4d7c 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -22,6 +22,7 @@ version <next>:
> - Canopus HQX decoder
> - RTP depacketization of T.140 text (RFC 4103)
> - VP9 RTP payload format (draft 0) experimental depacketizer
> +- TDSC decoder
>
>
> version 11:
> diff --git a/configure b/configure
> index 9ea946b..8789d13 100755
> --- a/configure
> +++ b/configure
> @@ -1911,6 +1911,8 @@ svq1_encoder_select="aandcttables hpeldsp me_cmp
> mpegvideoenc"
> svq3_decoder_select="h264_decoder hpeldsp tpeldsp"
> svq3_decoder_suggest="zlib"
> tak_decoder_select="audiodsp"
> +tdsc_decoder_deps="zlib"
> +tdsc_decoder_select="mjpeg_decoder"
> theora_decoder_select="vp3_decoder"
> thp_decoder_select="mjpeg_decoder"
> tiff_decoder_suggest="zlib"
> diff --git a/doc/general.texi b/doc/general.texi
> index 21e5fe8..58ce1dc 100644
> --- a/doc/general.texi
> +++ b/doc/general.texi
> @@ -409,6 +409,7 @@ library:
> @item Sony Wave64 (W64) @tab @tab X
> @item SoX native format @tab X @tab X
> @item SUN AU format @tab X @tab X
> +@item TDSC @tab @tab X
> @item Text files @tab @tab X
> @item THP @tab @tab X
> @tab Used on the Nintendo GameCube.
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 1c50f99..b132021 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -377,6 +377,7 @@ OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o svq13.o
> mpegutils.o
> OBJS-$(CONFIG_TAK_DECODER) += takdec.o tak.o
> OBJS-$(CONFIG_TARGA_DECODER) += targa.o
> OBJS-$(CONFIG_TARGA_ENCODER) += targaenc.o rle.o
> +OBJS-$(CONFIG_TDSC_DECODER) += tdsc.o
> OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.o
> OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o faxcompr.o
> OBJS-$(CONFIG_TIFF_ENCODER) += tiffenc.o rle.o lzwenc.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 392a2c9..4cba5fb 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -243,6 +243,7 @@ void avcodec_register_all(void)
> REGISTER_ENCDEC (SVQ1, svq1);
> REGISTER_DECODER(SVQ3, svq3);
> REGISTER_ENCDEC (TARGA, targa);
> + REGISTER_DECODER(TDSC, tdsc);
> REGISTER_DECODER(THEORA, theora);
> REGISTER_DECODER(THP, thp);
> REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo);
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index b9e5375..b264eaa 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -294,6 +294,7 @@ enum AVCodecID {
> AV_CODEC_ID_MVC1,
> AV_CODEC_ID_MVC2,
> AV_CODEC_ID_HQX,
> + AV_CODEC_ID_TDSC,
>
> /* various PCM "codecs" */
> AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the
> start of audio codecs
> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> index 747ebe8..de46704 100644
> --- a/libavcodec/codec_desc.c
> +++ b/libavcodec/codec_desc.c
> @@ -1286,6 +1286,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
> .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
> },
> {
> + .id = AV_CODEC_ID_TDSC,
> + .type = AVMEDIA_TYPE_VIDEO,
> + .name = "tdsc",
> + .long_name = NULL_IF_CONFIG_SMALL("TDSC"),
> + .props = AV_CODEC_PROP_LOSSY,
> + },
> + {
> .id = AV_CODEC_ID_TIFF,
> .type = AVMEDIA_TYPE_VIDEO,
> .name = "tiff",
> diff --git a/libavcodec/tdsc.c b/libavcodec/tdsc.c
> new file mode 100644
> index 0000000..b023c45
> --- /dev/null
> +++ b/libavcodec/tdsc.c
> @@ -0,0 +1,629 @@
> +/*
> + * TDSC decoder
> + * Copyright (C) 2015 Vittorio Giovara <[email protected]>
> + *
> + * This file is part of Libav.
> + *
> + * Libav 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,
> + * 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
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
> USA
> + */
> +
> +/**
> + * @file
> + * TDSC decoder
> + *
> + * Fourcc: TSDC
> + *
> + * TDSC is very simple. It codes picture by tiles, storing them in raw BGR24
> + * format or compressing them in JPEG. Frames can be full pictures or just
> + * updates to the previous frame. Cursor is found in its own frame or at the
> + * bottom of the picture. Every frame is then packed with zlib.
> + *
> + * Supports: BGR24
> + */
> +
> +#include <stdint.h>
> +#include <zlib.h>
> +
> +#include "libavutil/imgutils.h"
> +#include "libavutil/thread.h"
> +
> +#include "avcodec.h"
> +#include "bytestream.h"
> +#include "internal.h"
> +
> +#define BITMAPINFOHEADER_SIZE 0x28
> +#define TDSF_HEADER_SIZE 0x56
> +#define TDSB_HEADER_SIZE 0x08
> +
> +typedef struct TDSCContext {
> + AVCodecContext *jpeg_avctx; // wrapper context for MJPEG
> +
> + int width, height;
> + GetByteContext gbc;
> +
> + AVFrame *refframe; // full decoded frame (without cursor)
> + AVFrame *jpgframe; // decoded JPEG tile
> + uint8_t *tilebuffer; // buffer containing tile data
> +
> + /* zlib interation */
> + uint8_t *deflatebuffer;
> + uLongf deflatelen;
> +
> + /* All that is cursor */
> + uint8_t *cursor;
> + int cursor_stride;
> + int cursor_w, cursor_h, cursor_x, cursor_y;
> + int cursor_hot_x, cursor_hot_y;
> +} TDSCContext;
> +
> +/* 1 byte bits, 1 byte planes, 2 bytes format (probably) */
> +enum TDSCCursorFormat {
> + CUR_FMT_MONO = 0x01010004,
> + CUR_FMT_BGRA = 0x20010004,
> + CUR_FMT_RGBA = 0x20010008,
> +};
> +
> +static av_cold int tdsc_close(AVCodecContext *avctx)
> +{
> + TDSCContext *ctx = avctx->priv_data;
> +
> + av_frame_free(&ctx->refframe);
> + av_frame_free(&ctx->jpgframe);
> + av_freep(&ctx->deflatebuffer);
> + av_freep(&ctx->tilebuffer);
> + av_freep(&ctx->cursor);
> + avcodec_free_context(&ctx->jpeg_avctx);
> +
> + return 0;
> +}
> +
> +static av_cold int tdsc_init(AVCodecContext *avctx)
> +{
> + TDSCContext *ctx = avctx->priv_data;
> + AVCodec *codec;
const
> + int ret;
> +
> + avctx->pix_fmt = AV_PIX_FMT_BGR24;
> +
> + /* These needs to be set to estimate buffer and frame size */
> + if (!(avctx->width && avctx->height)) {
> + av_log(avctx, AV_LOG_ERROR, "Video size not set.\n");
> + return AVERROR_INVALIDDATA;
> + }
> +
> + /* This value should be large enough for a RAW-only frame plus headers */
> + ctx->deflatelen = avctx->width * avctx->height * (3 + 1);
> + ret = av_reallocp(&ctx->deflatebuffer, ctx->deflatelen);
> + if (ret < 0)
> + return ret;
> +
> + /* Allocate reference and JPEG frame */
> + ctx->refframe = av_frame_alloc();
> + ctx->jpgframe = av_frame_alloc();
> + if (!ctx->refframe || !ctx->jpgframe)
> + return AVERROR(ENOMEM);
> +
> + /* Prepare everything needed for JPEG decoding */
> + codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
> + if (!codec)
> + return AVERROR_DECODER_NOT_FOUND;
> + ctx->jpeg_avctx = avcodec_alloc_context3(codec);
> + if (!ctx->jpeg_avctx)
> + return AVERROR(ENOMEM);
> + ctx->jpeg_avctx->flags = avctx->flags;
> + ctx->jpeg_avctx->flags2 = avctx->flags2;
> + ctx->jpeg_avctx->dct_algo = avctx->dct_algo;
> + ctx->jpeg_avctx->idct_algo = avctx->idct_algo;;
> + ret = avcodec_open2(ctx->jpeg_avctx, codec, NULL);
> + if (ret < 0)
> + return ret;
> +
> + /* Finally set the output pixel format */
nit: drop 'finally', it carries no information and will probably become
wrong in the future
> + ctx->refframe->format = avctx->pix_fmt;
> +
> + return 0;
> +}
> +
> +#define APPLY_ALPHA(src, new, alpha) \
> + src = (src * (256 - alpha) + new * alpha) >> 8
> +
> +/* Paint a region over a buffer, without drawing out of its bounds. */
> +static void tdsc_paint_cursor(AVCodecContext *avctx, uint8_t *dst, int
> stride)
> +{
> + TDSCContext *ctx = avctx->priv_data;
> + const uint8_t *cursor = ctx->cursor;
> + int x = ctx->cursor_x - ctx->cursor_hot_x;
> + int y = ctx->cursor_y - ctx->cursor_hot_y;
> + int w = ctx->cursor_w;
> + int h = ctx->cursor_h;
> + int i, j;
> +
> + if (!ctx->cursor)
> + return;
> +
> + if (x + w > ctx->width)
> + w = ctx->width - x;
> + if (y + h > ctx->height)
> + h = ctx->height - y;
> + if (x < 0) {
> + w += x;
> + cursor += -x * 4;
> + } else {
> + dst += x * 3;
> + }
> + if (y < 0) {
> + h += y;
> + cursor += -y * ctx->cursor_stride;
> + } else {
> + dst += y * stride;
> + }
> + if (w < 0 || h < 0)
> + return;
> +
> + for (j = 0; j < h; j++) {
> + for (i = 0; i < w; i++) {
> + uint8_t alpha = cursor[i * 4];
> + APPLY_ALPHA(dst[i * 3 + 0], cursor[i * 4 + 1], alpha);
> + APPLY_ALPHA(dst[i * 3 + 1], cursor[i * 4 + 2], alpha);
> + APPLY_ALPHA(dst[i * 3 + 2], cursor[i * 4 + 3], alpha);
> + }
> + dst += stride;
> + cursor += ctx->cursor_stride;
> + }
> +}
> +
> +/* Load cursor data and store it in ABGR mode. */
> +static int tdsc_load_cursor(AVCodecContext *avctx, int action)
> +{
> + TDSCContext *ctx = avctx->priv_data;
> +
> + ctx->cursor_x = bytestream2_get_le32(&ctx->gbc);
> + ctx->cursor_y = bytestream2_get_le32(&ctx->gbc);
> +
> + if (action == 3) {
> + int i, j, k, ret, bits, cursor_fmt;
> + uint8_t *dst;
> +
> + ctx->cursor_hot_x = bytestream2_get_le16(&ctx->gbc);
> + ctx->cursor_hot_y = bytestream2_get_le16(&ctx->gbc);
> + ctx->cursor_w = bytestream2_get_le16(&ctx->gbc);
> + ctx->cursor_h = bytestream2_get_le16(&ctx->gbc);
> +
> + ctx->cursor_stride = FFALIGN(ctx->cursor_w, 32) * 4;
> + cursor_fmt = bytestream2_get_le32(&ctx->gbc);
> +
> + if (ctx->cursor_x >= avctx->width || ctx->cursor_y >= avctx->height)
> {
> + av_log(avctx, AV_LOG_ERROR,
> + "Invalid cursor position (%d.%d outside %dx%d).\n",
> + ctx->cursor_x, ctx->cursor_y, avctx->width,
> avctx->height);
> + return AVERROR_INVALIDDATA;
> + }
> + if (ctx->cursor_w < 1 || ctx->cursor_w > 256 ||
> + ctx->cursor_h < 1 || ctx->cursor_h > 256) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Invalid cursor dimensions %dx%d.\n",
> + ctx->cursor_w, ctx->cursor_h);
> + return AVERROR_INVALIDDATA;
> + }
> + if (ctx->cursor_hot_x > ctx->cursor_w ||
> + ctx->cursor_hot_y > ctx->cursor_h) {
> + av_log(avctx, AV_LOG_WARNING, "Invalid hotspot position
> %d.%d.\n",
> + ctx->cursor_hot_x, ctx->cursor_hot_y);
> + ctx->cursor_hot_x = FFMIN(ctx->cursor_hot_x, ctx->cursor_w - 1);
> + ctx->cursor_hot_y = FFMIN(ctx->cursor_hot_y, ctx->cursor_h - 1);
> + }
> +
> + ret = av_reallocp(&ctx->cursor, ctx->cursor_stride * ctx->cursor_h);
> + if (ret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Cannot allocate cursor buffer.\n");
> + return ret;
> + }
> +
> + dst = ctx->cursor;
> + /* here data is packed in BE */
> + switch (cursor_fmt) {
> + case CUR_FMT_MONO:
> + for (j = 0; j < ctx->cursor_h; j++) {
> + for (i = 0; i < ctx->cursor_w; i += 32) {
> + bits = bytestream2_get_be32(&ctx->gbc);
> + for (k = 0; k < 32; k++) {
> + dst[0] = !!(bits & 0x80000000);
> + dst += 4;
> + bits <<= 1;
> + }
> + }
> + dst += ctx->cursor_stride - ctx->cursor_w * 4;
> + }
> +
> + dst = ctx->cursor;
> + for (j = 0; j < ctx->cursor_h; j++) {
> + for (i = 0; i < ctx->cursor_w; i += 32) {
> + bits = bytestream2_get_be32(&ctx->gbc);
> + for (k = 0; k < 32; k++) {
> + int mask_bit = !!(bits & 0x80000000);
> + switch (dst[0] * 2 + mask_bit) {
> + case 0:
> + dst[0] = 0xFF;
> + dst[1] = 0x00;
> + dst[2] = 0x00;
> + dst[3] = 0x00;
> + break;
> + case 1:
> + dst[0] = 0xFF;
> + dst[1] = 0xFF;
> + dst[2] = 0xFF;
> + dst[3] = 0xFF;
> + break;
> + default:
> + dst[0] = 0x00;
> + dst[1] = 0x00;
> + dst[2] = 0x00;
> + dst[3] = 0x00;
> + }
> + dst += 4;
> + bits <<= 1;
> + }
> + }
> + dst += ctx->cursor_stride - ctx->cursor_w * 4;
> + }
> + break;
> + case CUR_FMT_BGRA:
> + case CUR_FMT_RGBA:
> + /* Skip monochrome version of the cursor */
> + bytestream2_skip(&ctx->gbc,
> + ctx->cursor_h * (FFALIGN(ctx->cursor_w, 32) >>
> 3));
> + if (cursor_fmt & 8) { // RGBA -> ABGR
> + for (j = 0; j < ctx->cursor_h; j++) {
> + for (i = 0; i < ctx->cursor_w; i++) {
> + int val = bytestream2_get_be32(&ctx->gbc);
> + *dst++ = val >> 24;
> + *dst++ = val >> 16;
> + *dst++ = val >> 8;
> + *dst++ = val >> 0;
> + }
> + dst += ctx->cursor_stride - ctx->cursor_w * 4;
> + }
> + } else { // BGRA -> ABGR
> + for (j = 0; j < ctx->cursor_h; j++) {
> + for (i = 0; i < ctx->cursor_w; i++) {
> + int val = bytestream2_get_be32(&ctx->gbc);
> + *dst++ = val >> 0;
> + *dst++ = val >> 24;
> + *dst++ = val >> 16;
> + *dst++ = val >> 8;
> + }
> + dst += ctx->cursor_stride - ctx->cursor_w * 4;
> + }
> + }
> + break;
> + default:
> + avpriv_request_sample(avctx, "Cursor format %08x", cursor_fmt);
> + return AVERROR_PATCHWELCOME;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* Convert a single YUV pixel to RGB. */
> +static inline void tdsc_yuv2rgb(uint8_t *out, int Y, int U, int V)
> +{
> + out[0] = av_clip_uint8(Y + ( 91881 * V + 32768 >> 16));
> + out[1] = av_clip_uint8(Y + (-22554 * U - 46802 * V + 32768 >> 16));
> + out[2] = av_clip_uint8(Y + (116130 * U + 32768 >> 16));
> +}
> +
> +/* Convert a YUV420 buffer to a RGB buffer. */
> +static av_always_inline void tdsc_blit(uint8_t *dst, int dst_stride,
> + const uint8_t *srcy, int srcy_stride,
> + const uint8_t *srcu, const uint8_t
> *srcv,
> + int srcuv_stride, int width, int
> height)
> +{
> + int col, line;
> + for (line = 0; line < height; line++) {
> + for (col = 0; col < width; col++)
> + tdsc_yuv2rgb(dst + col * 3, srcy[col],
> + srcu[col >> 1] - 128, srcv[col >> 1] - 128);
> +
> + dst += dst_stride;
> + srcy += srcy_stride;
> + srcu += srcuv_stride * (line & 1);
> + srcv += srcuv_stride * (line & 1);
> + }
> +}
> +
> +/* Invoke the MJPEG decoder to decode the tile. */
> +static int tdsc_decode_jpeg_tile(AVCodecContext *avctx, int tile_size,
> + int x, int y, int w, int h)
> +{
> + TDSCContext *ctx = avctx->priv_data;
> + AVPacket jpkt;
> + int got_frame = 0;
> + int ret;
> +
> + /* Prepare a packet and send to the MJPEG decoder */
> + av_init_packet(&jpkt);
> + jpkt.data = ctx->tilebuffer;
> + jpkt.size = tile_size;
> +
> + ret = avcodec_decode_video2(ctx->jpeg_avctx, ctx->jpgframe,
> + &got_frame, &jpkt);
> + if (ret < 0 || !got_frame || ctx->jpgframe->format !=
> AV_PIX_FMT_YUVJ420P) {
> + av_log(avctx, AV_LOG_ERROR,
> + "JPEG decoding error (%d) for (%d) frame.\n",
> + ret, got_frame);
> +
> + /* Normally skip, error if explode */
> + if (avctx->err_recognition & AV_EF_EXPLODE)
> + return AVERROR_INVALIDDATA;
> + else
> + return 0;
> + }
> +
> + /* Let's paint ont the buffer */
> + tdsc_blit(ctx->refframe->data[0] + x * 3 + ctx->refframe->linesize[0] *
> y,
> + ctx->refframe->linesize[0],
> + ctx->jpgframe->data[0], ctx->jpgframe->linesize[0],
> + ctx->jpgframe->data[1], ctx->jpgframe->data[2],
> + ctx->jpgframe->linesize[1], w, h);
> +
> + av_frame_unref(ctx->jpgframe);
> +
> + return 0;
> +}
> +
> +/* Parse frame and either copy data or decode JPEG. */
> +static int tdsc_decode_tiles(AVCodecContext *avctx, int number_tiles)
> +{
> + TDSCContext *ctx = avctx->priv_data;
> + int i, width, height;
> +
> + /* Keep track of the correct context size */
Is this still relevant?
> + width = avctx->width;
> + height = avctx->height;
> +
> + /* Iterate over the number of tiles */
> + for (i = 0; i < number_tiles; i++) {
> + int tile_size;
> + int tile_mode;
> + int x, y, w, h;
> + int ret;
> +
> + if (bytestream2_get_bytes_left(&ctx->gbc) < 4 ||
> + bytestream2_get_le32(&ctx->gbc) != MKTAG('T','D','S','B') ||
> + bytestream2_get_bytes_left(&ctx->gbc) < TDSB_HEADER_SIZE - 4) {
> + av_log(avctx, AV_LOG_ERROR, "TDSB tag is too small.\n");
> + return AVERROR_INVALIDDATA;
> + }
> +
> + tile_size = bytestream2_get_le32(&ctx->gbc);
> + if (bytestream2_get_bytes_left(&ctx->gbc) < tile_size)
> + return AVERROR_INVALIDDATA;
> +
> + tile_mode = bytestream2_get_le32(&ctx->gbc);
> + bytestream2_skip(&ctx->gbc, 4); // unknown
> + x = bytestream2_get_le32(&ctx->gbc);
> + y = bytestream2_get_le32(&ctx->gbc);
> + w = bytestream2_get_le32(&ctx->gbc) - x;
> + h = bytestream2_get_le32(&ctx->gbc) - y;
> +
> + if (x >= width || y >= height) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Invalid tile position (%d.%d outside %dx%d).\n",
> + x, y, width, height);
> + return AVERROR_INVALIDDATA;
> + }
> + if (x + w > width || y + h > height) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Invalid tile size %dx%d\n", w, h);
> + return AVERROR_INVALIDDATA;
> + }
> +
> + ret = av_reallocp(&ctx->tilebuffer, tile_size);
> + if (!ctx->tilebuffer)
> + return ret;
> +
> + bytestream2_get_buffer(&ctx->gbc, ctx->tilebuffer, tile_size);
> +
> + if (tile_mode == MKTAG('G','E','P','J')) {
> + /* Decode JPEG tile and copy it in the reference frame */
> + ret = tdsc_decode_jpeg_tile(avctx, tile_size, x, y, w, h);
> + if (ret < 0)
> + return ret;
> + } else if (tile_mode == MKTAG(' ','W','A','R')) {
> + /* Just copy the buffer to output */
> + av_image_copy_plane(ctx->refframe->data[0] + x * 3 +
> + ctx->refframe->linesize[0] * y,
> + ctx->refframe->linesize[0], ctx->tilebuffer,
> + w * 3, w * 3, h);
> + } else {
> + av_log(avctx, AV_LOG_ERROR, "Unknown tile type %08x.\n",
> tile_mode);
> + return AVERROR_INVALIDDATA;
> + }
> + av_log(avctx, AV_LOG_DEBUG, "Tile %d, %dx%d (%d.%d)\n", i, w, h, x,
> y);
> + }
> +
> + return 0;
> +}
> +
> +static int tdsc_parse_tdsf(AVCodecContext *avctx, int number_tiles)
> +{
> + TDSCContext *ctx = avctx->priv_data;
> + int ret, init_refframe = !ctx->refframe->data[0];
> + int orig_w = avctx->width;
> + int orig_h = avctx->height;
> +
> + /* BITMAPINFOHEADER
> + * http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx
> */
> + if (bytestream2_get_le32(&ctx->gbc) != BITMAPINFOHEADER_SIZE)
> + return AVERROR_INVALIDDATA;
> +
> + ctx->refframe->width = ctx->width = bytestream2_get_le32(&ctx->gbc);
> + ctx->refframe->height = ctx->height = -bytestream2_get_le32(&ctx->gbc);
> +
> + if (bytestream2_get_le16(&ctx->gbc) != 1 || // 1 plane
> + bytestream2_get_le16(&ctx->gbc) != 24) // BGR24
> + return AVERROR_INVALIDDATA;
I think if you error out here and the size changed just above, this will
leave the context in an inconsistent state and might crash.
Best not to write the new dimensions anywhere until context reinit is
finished.
--
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel