1/* 2 * Bitmap Brothers JV video decoder 3 * Copyright (c) 2011 Peter Ross <pross@xvid.org> 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * Bitmap Brothers JV video decoder 25 * @author Peter Ross <pross@xvid.org> 26 */ 27 28#include "libavutil/intreadwrite.h" 29 30#include "avcodec.h" 31#include "blockdsp.h" 32#include "codec_internal.h" 33#include "get_bits.h" 34#include "internal.h" 35 36typedef struct JvContext { 37 BlockDSPContext bdsp; 38 AVFrame *frame; 39 uint32_t palette[AVPALETTE_COUNT]; 40 int palette_has_changed; 41} JvContext; 42 43static av_cold int decode_init(AVCodecContext *avctx) 44{ 45 JvContext *s = avctx->priv_data; 46 47 if (!avctx->width || !avctx->height || 48 (avctx->width & 7) || (avctx->height & 7)) { 49 av_log(avctx, AV_LOG_ERROR, "Invalid video dimensions: %dx%d\n", 50 avctx->width, avctx->height); 51 return AVERROR(EINVAL); 52 } 53 54 s->frame = av_frame_alloc(); 55 if (!s->frame) 56 return AVERROR(ENOMEM); 57 58 avctx->pix_fmt = AV_PIX_FMT_PAL8; 59 ff_blockdsp_init(&s->bdsp, avctx); 60 return 0; 61} 62 63/** 64 * Decode 2x2 block 65 */ 66static inline void decode2x2(GetBitContext *gb, uint8_t *dst, int linesize) 67{ 68 int i, j, v[2]; 69 70 switch (get_bits(gb, 2)) { 71 case 1: 72 v[0] = get_bits(gb, 8); 73 for (j = 0; j < 2; j++) 74 memset(dst + j * linesize, v[0], 2); 75 break; 76 case 2: 77 v[0] = get_bits(gb, 8); 78 v[1] = get_bits(gb, 8); 79 for (j = 0; j < 2; j++) 80 for (i = 0; i < 2; i++) 81 dst[j * linesize + i] = v[get_bits1(gb)]; 82 break; 83 case 3: 84 for (j = 0; j < 2; j++) 85 for (i = 0; i < 2; i++) 86 dst[j * linesize + i] = get_bits(gb, 8); 87 } 88} 89 90/** 91 * Decode 4x4 block 92 */ 93static inline void decode4x4(GetBitContext *gb, uint8_t *dst, int linesize) 94{ 95 int i, j, v[2]; 96 97 switch (get_bits(gb, 2)) { 98 case 1: 99 v[0] = get_bits(gb, 8); 100 for (j = 0; j < 4; j++) 101 memset(dst + j * linesize, v[0], 4); 102 break; 103 case 2: 104 v[0] = get_bits(gb, 8); 105 v[1] = get_bits(gb, 8); 106 for (j = 2; j >= 0; j -= 2) { 107 for (i = 0; i < 4; i++) 108 dst[j * linesize + i] = v[get_bits1(gb)]; 109 for (i = 0; i < 4; i++) 110 dst[(j + 1) * linesize + i] = v[get_bits1(gb)]; 111 } 112 break; 113 case 3: 114 for (j = 0; j < 4; j += 2) 115 for (i = 0; i < 4; i += 2) 116 decode2x2(gb, dst + j * linesize + i, linesize); 117 } 118} 119 120/** 121 * Decode 8x8 block 122 */ 123static inline void decode8x8(GetBitContext *gb, uint8_t *dst, int linesize, 124 BlockDSPContext *bdsp) 125{ 126 int i, j, v[2]; 127 128 switch (get_bits(gb, 2)) { 129 case 1: 130 v[0] = get_bits(gb, 8); 131 bdsp->fill_block_tab[1](dst, v[0], linesize, 8); 132 break; 133 case 2: 134 v[0] = get_bits(gb, 8); 135 v[1] = get_bits(gb, 8); 136 for (j = 7; j >= 0; j--) 137 for (i = 0; i < 8; i++) 138 dst[j * linesize + i] = v[get_bits1(gb)]; 139 break; 140 case 3: 141 for (j = 0; j < 8; j += 4) 142 for (i = 0; i < 8; i += 4) 143 decode4x4(gb, dst + j * linesize + i, linesize); 144 } 145} 146 147static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, 148 int *got_frame, AVPacket *avpkt) 149{ 150 JvContext *s = avctx->priv_data; 151 const uint8_t *buf = avpkt->data; 152 const uint8_t *buf_end = buf + avpkt->size; 153 int video_size, video_type, i, j, ret; 154 155 if (avpkt->size < 6) 156 return AVERROR_INVALIDDATA; 157 158 video_size = AV_RL32(buf); 159 video_type = buf[4]; 160 buf += 5; 161 162 if (video_size) { 163 if (video_size < 0 || video_size > avpkt->size - 5) { 164 av_log(avctx, AV_LOG_ERROR, "video size %d invalid\n", video_size); 165 return AVERROR_INVALIDDATA; 166 } 167 168 if (video_type == 0 || video_type == 1) { 169 GetBitContext gb; 170 init_get_bits(&gb, buf, 8 * video_size); 171 172 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 173 return ret; 174 175 if (avctx->height/8 * (avctx->width/8) > 4 * video_size) { 176 av_log(avctx, AV_LOG_ERROR, "Insufficient input data for dimensions\n"); 177 return AVERROR_INVALIDDATA; 178 } 179 180 for (j = 0; j < avctx->height; j += 8) 181 for (i = 0; i < avctx->width; i += 8) 182 decode8x8(&gb, 183 s->frame->data[0] + j * s->frame->linesize[0] + i, 184 s->frame->linesize[0], &s->bdsp); 185 186 buf += video_size; 187 } else if (video_type == 2) { 188 int v = *buf++; 189 190 av_frame_unref(s->frame); 191 if ((ret = ff_get_buffer(avctx, s->frame, AV_GET_BUFFER_FLAG_REF)) < 0) 192 return ret; 193 194 for (j = 0; j < avctx->height; j++) 195 memset(s->frame->data[0] + j * s->frame->linesize[0], 196 v, avctx->width); 197 } else { 198 av_log(avctx, AV_LOG_WARNING, 199 "unsupported frame type %i\n", video_type); 200 return AVERROR_INVALIDDATA; 201 } 202 } 203 204 if (buf_end - buf >= AVPALETTE_COUNT * 3) { 205 for (i = 0; i < AVPALETTE_COUNT; i++) { 206 uint32_t pal = AV_RB24(buf); 207 s->palette[i] = 0xFFU << 24 | pal << 2 | ((pal >> 4) & 0x30303); 208 buf += 3; 209 } 210 s->palette_has_changed = 1; 211 } 212 213 if (video_size) { 214 s->frame->key_frame = 1; 215 s->frame->pict_type = AV_PICTURE_TYPE_I; 216 s->frame->palette_has_changed = s->palette_has_changed; 217 s->palette_has_changed = 0; 218 memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); 219 220 if ((ret = av_frame_ref(rframe, s->frame)) < 0) 221 return ret; 222 *got_frame = 1; 223 } 224 225 return avpkt->size; 226} 227 228static av_cold int decode_close(AVCodecContext *avctx) 229{ 230 JvContext *s = avctx->priv_data; 231 232 av_frame_free(&s->frame); 233 234 return 0; 235} 236 237const FFCodec ff_jv_decoder = { 238 .p.name = "jv", 239 .p.long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV video"), 240 .p.type = AVMEDIA_TYPE_VIDEO, 241 .p.id = AV_CODEC_ID_JV, 242 .priv_data_size = sizeof(JvContext), 243 .init = decode_init, 244 .close = decode_close, 245 FF_CODEC_DECODE_CB(decode_frame), 246 .p.capabilities = AV_CODEC_CAP_DR1, 247 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 248}; 249