From 0697440c1ef55e6def219cdf0e22682b0b71f089 Mon Sep 17 00:00:00 2001 From: Peter Ross Date: Thu, 10 Mar 2011 23:23:25 +1100 Subject: [PATCH] Bitmap Brothers JV video decoder Signed-off-by: Ronald S. Bultje --- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 5 +- libavcodec/jvdec.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 libavcodec/jvdec.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index e116a7d01..21bdbf42d 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -184,6 +184,7 @@ OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o \ mjpegdec.o mjpeg.o OBJS-$(CONFIG_JPEGLS_ENCODER) += jpeglsenc.o jpegls.o +OBJS-$(CONFIG_JV_DECODER) += jvdec.o OBJS-$(CONFIG_KGV1_DECODER) += kgv1dec.o OBJS-$(CONFIG_KMVC_DECODER) += kmvc.o OBJS-$(CONFIG_LAGARITH_DECODER) += lagarith.o lagarithrac.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 108a3ab7c..2ed49a272 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -126,6 +126,7 @@ void avcodec_register_all(void) REGISTER_DECODER (INDEO5, indeo5); REGISTER_DECODER (INTERPLAY_VIDEO, interplay_video); REGISTER_ENCDEC (JPEGLS, jpegls); + REGISTER_DECODER (JV, jv); REGISTER_DECODER (KGV1, kgv1); REGISTER_DECODER (KMVC, kmvc); REGISTER_DECODER (LAGARITH, lagarith); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 12cca6ff9..6491e0745 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -32,8 +32,8 @@ #include "libavutil/cpu.h" #define LIBAVCODEC_VERSION_MAJOR 52 -#define LIBAVCODEC_VERSION_MINOR 113 -#define LIBAVCODEC_VERSION_MICRO 2 +#define LIBAVCODEC_VERSION_MINOR 114 +#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ @@ -261,6 +261,7 @@ enum CodecID { CODEC_ID_MXPEG, CODEC_ID_LAGARITH, CODEC_ID_PRORES, + CODEC_ID_JV, /* various PCM "codecs" */ CODEC_ID_PCM_S16LE= 0x10000, diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c new file mode 100644 index 000000000..61faef6a5 --- /dev/null +++ b/libavcodec/jvdec.c @@ -0,0 +1,215 @@ +/* + * Bitmap Brothers JV video decoder + * Copyright (c) 2011 Peter Ross + * + * This file is part of FFmpeg. + * + * 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. + * + * 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Bitmap Brothers JV video decoder + * @author Peter Ross + */ + +#include "avcodec.h" +#include "dsputil.h" +#include "get_bits.h" +#include "libavutil/intreadwrite.h" + +typedef struct JvContext { + DSPContext dsp; + AVFrame frame; + uint32_t palette[AVPALETTE_COUNT]; + int palette_has_changed; +} JvContext; + +static av_cold int decode_init(AVCodecContext *avctx) +{ + JvContext *s = avctx->priv_data; + avctx->pix_fmt = PIX_FMT_PAL8; + dsputil_init(&s->dsp, avctx); + return 0; +} + +/** + * Decode 2x2 block + */ +static inline void decode2x2(GetBitContext *gb, uint8_t *dst, int linesize) +{ + int i, j, v[2]; + + switch (get_bits(gb, 2)) { + case 1: + v[0] = get_bits(gb, 8); + for (j = 0; j < 2; j++) + memset(dst + j*linesize, v[0], 2); + break; + case 2: + v[0] = get_bits(gb, 8); + v[1] = get_bits(gb, 8); + for (j = 0; j < 2; j++) + for (i = 0; i < 2; i++) + dst[j*linesize + i] = v[get_bits1(gb)]; + break; + case 3: + for (j = 0; j < 2; j++) + for (i = 0; i < 2; i++) + dst[j*linesize + i] = get_bits(gb, 8); + } +} + +/** + * Decode 4x4 block + */ +static inline void decode4x4(GetBitContext *gb, uint8_t *dst, int linesize) +{ + int i, j, v[2]; + + switch (get_bits(gb, 2)) { + case 1: + v[0] = get_bits(gb, 8); + for (j = 0; j < 4; j++) + memset(dst + j*linesize, v[0], 4); + break; + case 2: + v[0] = get_bits(gb, 8); + v[1] = get_bits(gb, 8); + for (j = 2; j >= 0; j -= 2) { + for (i = 0; i < 4; i++) + dst[j*linesize + i] = v[get_bits1(gb)]; + for (i = 0; i < 4; i++) + dst[(j+1)*linesize + i] = v[get_bits1(gb)]; + } + break; + case 3: + for (j = 0; j < 4; j += 2) + for (i = 0; i < 4; i += 2) + decode2x2(gb, dst + j*linesize + i, linesize); + } +} + +/** + * Decode 8x8 block + */ +static inline void decode8x8(GetBitContext *gb, uint8_t *dst, int linesize, DSPContext *dsp) +{ + int i, j, v[2]; + + switch (get_bits(gb, 2)) { + case 1: + v[0] = get_bits(gb, 8); + dsp->fill_block_tab[1](dst, v[0], linesize, 8); + break; + case 2: + v[0] = get_bits(gb, 8); + v[1] = get_bits(gb, 8); + for (j = 7; j >= 0; j--) + for (i = 0; i < 8; i++) + dst[j*linesize + i] = v[get_bits1(gb)]; + break; + case 3: + for (j = 0; j < 8; j += 4) + for (i = 0; i < 8; i += 4) + decode4x4(gb, dst + j*linesize + i, linesize); + } +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + AVPacket *avpkt) +{ + JvContext *s = avctx->priv_data; + int buf_size = avpkt->size; + const uint8_t *buf = avpkt->data; + const uint8_t *buf_end = buf + buf_size; + int video_size, video_type, i, j; + + video_size = AV_RL32(buf); + video_type = buf[4]; + buf += 5; + + if (video_size) { + if (avctx->reget_buffer(avctx, &s->frame) < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + + if (video_type == 0 || video_type == 1) { + GetBitContext gb; + init_get_bits(&gb, buf, FFMIN(video_size, buf_end - buf)); + + for (j = 0; j < avctx->height; j += 8) + for (i = 0; i < avctx->width; i += 8) + decode8x8(&gb, s->frame.data[0] + j*s->frame.linesize[0] + i, + s->frame.linesize[0], &s->dsp); + + buf += video_size; + } else if (video_type == 2) { + if (buf + 1 <= buf_end) { + int v = *buf++; + for (j = 0; j < avctx->height; j++) + memset(s->frame.data[0] + j*s->frame.linesize[0], v, avctx->width); + } + } else { + av_log(avctx, AV_LOG_WARNING, "unsupported frame type %i\n", video_type); + return AVERROR_INVALIDDATA; + } + } + + if (buf < buf_end) { + for (i = 0; i < AVPALETTE_COUNT && buf + 3 <= buf_end; i++) { + s->palette[i] = AV_RB24(buf) << 2; + buf += 3; + } + s->palette_has_changed = 1; + } + + if (video_size) { + s->frame.key_frame = 1; + s->frame.pict_type = FF_I_TYPE; + s->frame.palette_has_changed = s->palette_has_changed; + s->palette_has_changed = 0; + memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = s->frame; + } + + return buf_size; +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + JvContext *s = avctx->priv_data; + + if(s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); + + return 0; +} + +AVCodec ff_jv_decoder = { + .name = "jv", + .long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV video"), + .type = CODEC_TYPE_VIDEO, + .id = CODEC_ID_JV, + .priv_data_size = sizeof(JvContext), + .init = decode_init, + .close = decode_close, + .decode = decode_frame, + .capabilities = CODEC_CAP_DR1, +}; -- 2.11.0