1/* 2 * VBLE Decoder 3 * Copyright (c) 2011 Derek Buitenhuis 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 * VBLE Decoder 25 */ 26 27#include "libavutil/imgutils.h" 28 29#define BITSTREAM_READER_LE 30#include "avcodec.h" 31#include "codec_internal.h" 32#include "get_bits.h" 33#include "lossless_videodsp.h" 34#include "mathops.h" 35#include "thread.h" 36 37typedef struct VBLEContext { 38 AVCodecContext *avctx; 39 LLVidDSPContext llviddsp; 40 41 int size; 42 uint8_t *val; ///< This array first holds the lengths of vlc symbols and then their value. 43} VBLEContext; 44 45static int vble_unpack(VBLEContext *ctx, GetBitContext *gb) 46{ 47 int i; 48 int allbits = 0; 49 static const uint8_t LUT[256] = { 50 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 51 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 52 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 53 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 54 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 55 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 56 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 57 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 58 }; 59 60 /* Read all the lengths in first */ 61 for (i = 0; i < ctx->size; i++) { 62 /* At most we need to read 9 bits total to get indices up to 8 */ 63 int val = show_bits(gb, 8); 64 65 // read reverse unary 66 if (val) { 67 val = LUT[val]; 68 skip_bits(gb, val + 1); 69 ctx->val[i] = val; 70 } else { 71 skip_bits(gb, 8); 72 if (!get_bits1(gb)) 73 return -1; 74 ctx->val[i] = 8; 75 } 76 allbits += ctx->val[i]; 77 } 78 79 /* Check we have enough bits left */ 80 if (get_bits_left(gb) < allbits) 81 return -1; 82 return 0; 83} 84 85static void vble_restore_plane(VBLEContext *ctx, AVFrame *pic, 86 GetBitContext *gb, int plane, 87 int offset, int width, int height) 88{ 89 uint8_t *dst = pic->data[plane]; 90 uint8_t *val = ctx->val + offset; 91 int stride = pic->linesize[plane]; 92 int i, j, left, left_top; 93 94 for (i = 0; i < height; i++) { 95 for (j = 0; j < width; j++) { 96 /* get_bits can't take a length of 0 */ 97 if (val[j]) { 98 int v = (1 << val[j]) + get_bits(gb, val[j]) - 1; 99 val[j] = (v >> 1) ^ -(v & 1); 100 } 101 } 102 if (i) { 103 left = 0; 104 left_top = dst[-stride]; 105 ctx->llviddsp.add_median_pred(dst, dst - stride, val, 106 width, &left, &left_top); 107 } else { 108 dst[0] = val[0]; 109 for (j = 1; j < width; j++) 110 dst[j] = val[j] + dst[j - 1]; 111 } 112 dst += stride; 113 val += width; 114 } 115} 116 117static int vble_decode_frame(AVCodecContext *avctx, AVFrame *pic, 118 int *got_frame, AVPacket *avpkt) 119{ 120 VBLEContext *ctx = avctx->priv_data; 121 GetBitContext gb; 122 const uint8_t *src = avpkt->data; 123 int version; 124 int offset = 0; 125 int width_uv = avctx->width / 2, height_uv = avctx->height / 2; 126 int ret; 127 128 if (avpkt->size < 4 || avpkt->size - 4 > INT_MAX/8) { 129 av_log(avctx, AV_LOG_ERROR, "Invalid packet size\n"); 130 return AVERROR_INVALIDDATA; 131 } 132 133 /* Allocate buffer */ 134 if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0) 135 return ret; 136 137 /* Set flags */ 138 pic->key_frame = 1; 139 pic->pict_type = AV_PICTURE_TYPE_I; 140 141 /* Version should always be 1 */ 142 version = AV_RL32(src); 143 144 if (version != 1) 145 av_log(avctx, AV_LOG_WARNING, "Unsupported VBLE Version: %d\n", version); 146 147 init_get_bits(&gb, src + 4, (avpkt->size - 4) * 8); 148 149 /* Unpack */ 150 if (vble_unpack(ctx, &gb) < 0) { 151 av_log(avctx, AV_LOG_ERROR, "Invalid Code\n"); 152 return AVERROR_INVALIDDATA; 153 } 154 155 /* Restore planes. Should be almost identical to Huffyuv's. */ 156 vble_restore_plane(ctx, pic, &gb, 0, offset, avctx->width, avctx->height); 157 158 /* Chroma */ 159 if (!(ctx->avctx->flags & AV_CODEC_FLAG_GRAY)) { 160 offset += avctx->width * avctx->height; 161 vble_restore_plane(ctx, pic, &gb, 1, offset, width_uv, height_uv); 162 163 offset += width_uv * height_uv; 164 vble_restore_plane(ctx, pic, &gb, 2, offset, width_uv, height_uv); 165 } 166 167 *got_frame = 1; 168 169 return avpkt->size; 170} 171 172static av_cold int vble_decode_close(AVCodecContext *avctx) 173{ 174 VBLEContext *ctx = avctx->priv_data; 175 av_freep(&ctx->val); 176 177 return 0; 178} 179 180static av_cold int vble_decode_init(AVCodecContext *avctx) 181{ 182 VBLEContext *ctx = avctx->priv_data; 183 184 /* Stash for later use */ 185 ctx->avctx = avctx; 186 ff_llviddsp_init(&ctx->llviddsp); 187 188 avctx->pix_fmt = AV_PIX_FMT_YUV420P; 189 avctx->bits_per_raw_sample = 8; 190 191 ctx->size = av_image_get_buffer_size(avctx->pix_fmt, 192 avctx->width, avctx->height, 1); 193 194 ctx->val = av_malloc_array(ctx->size, sizeof(*ctx->val)); 195 196 if (!ctx->val) { 197 av_log(avctx, AV_LOG_ERROR, "Could not allocate values buffer.\n"); 198 return AVERROR(ENOMEM); 199 } 200 201 return 0; 202} 203 204const FFCodec ff_vble_decoder = { 205 .p.name = "vble", 206 .p.long_name = NULL_IF_CONFIG_SMALL("VBLE Lossless Codec"), 207 .p.type = AVMEDIA_TYPE_VIDEO, 208 .p.id = AV_CODEC_ID_VBLE, 209 .priv_data_size = sizeof(VBLEContext), 210 .init = vble_decode_init, 211 .close = vble_decode_close, 212 FF_CODEC_DECODE_CB(vble_decode_frame), 213 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, 214 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 215}; 216