1/* 2 * LOCO codec 3 * Copyright (c) 2005 Konstantin Shishkov 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 libavcodec/loco.c 24 * LOCO codec. 25 */ 26 27#include "avcodec.h" 28#include "bitstream.h" 29#include "golomb.h" 30#include "mathops.h" 31 32enum LOCO_MODE {LOCO_UNKN=0, LOCO_CYUY2=-1, LOCO_CRGB=-2, LOCO_CRGBA=-3, LOCO_CYV12=-4, 33 LOCO_YUY2=1, LOCO_UYVY=2, LOCO_RGB=3, LOCO_RGBA=4, LOCO_YV12=5}; 34 35typedef struct LOCOContext{ 36 AVCodecContext *avctx; 37 AVFrame pic; 38 int lossy; 39 int mode; 40} LOCOContext; 41 42typedef struct RICEContext{ 43 GetBitContext gb; 44 int save, run, run2; /* internal rice decoder state */ 45 int sum, count; /* sum and count for getting rice parameter */ 46 int lossy; 47}RICEContext; 48 49static int loco_get_rice_param(RICEContext *r) 50{ 51 int cnt = 0; 52 int val = r->count; 53 54 while(r->sum > val && cnt < 9) { 55 val <<= 1; 56 cnt++; 57 } 58 59 return cnt; 60} 61 62static inline void loco_update_rice_param(RICEContext *r, int val) 63{ 64 r->sum += val; 65 r->count++; 66 67 if(r->count == 16) { 68 r->sum >>= 1; 69 r->count >>= 1; 70 } 71} 72 73static inline int loco_get_rice(RICEContext *r) 74{ 75 int v; 76 if (r->run > 0) { /* we have zero run */ 77 r->run--; 78 loco_update_rice_param(r, 0); 79 return 0; 80 } 81 v = get_ur_golomb_jpegls(&r->gb, loco_get_rice_param(r), INT_MAX, 0); 82 loco_update_rice_param(r, (v+1)>>1); 83 if (!v) { 84 if (r->save >= 0) { 85 r->run = get_ur_golomb_jpegls(&r->gb, 2, INT_MAX, 0); 86 if(r->run > 1) 87 r->save += r->run + 1; 88 else 89 r->save -= 3; 90 } 91 else 92 r->run2++; 93 } else { 94 v = ((v>>1) + r->lossy) ^ -(v&1); 95 if (r->run2 > 0) { 96 if (r->run2 > 2) 97 r->save += r->run2; 98 else 99 r->save -= 3; 100 r->run2 = 0; 101 } 102 } 103 104 return v; 105} 106 107/* LOCO main predictor - LOCO-I/JPEG-LS predictor */ 108static inline int loco_predict(uint8_t* data, int stride, int step) 109{ 110 int a, b, c; 111 112 a = data[-stride]; 113 b = data[-step]; 114 c = data[-stride - step]; 115 116 return mid_pred(a, a + b - c, b); 117} 118 119static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int height, 120 int stride, const uint8_t *buf, int buf_size, int step) 121{ 122 RICEContext rc; 123 int val; 124 int i, j; 125 126 init_get_bits(&rc.gb, buf, buf_size*8); 127 rc.save = 0; 128 rc.run = 0; 129 rc.run2 = 0; 130 rc.lossy = l->lossy; 131 132 rc.sum = 8; 133 rc.count = 1; 134 135 /* restore top left pixel */ 136 val = loco_get_rice(&rc); 137 data[0] = 128 + val; 138 /* restore top line */ 139 for (i = 1; i < width; i++) { 140 val = loco_get_rice(&rc); 141 data[i * step] = data[i * step - step] + val; 142 } 143 data += stride; 144 for (j = 1; j < height; j++) { 145 /* restore left column */ 146 val = loco_get_rice(&rc); 147 data[0] = data[-stride] + val; 148 /* restore all other pixels */ 149 for (i = 1; i < width; i++) { 150 val = loco_get_rice(&rc); 151 data[i * step] = loco_predict(&data[i * step], stride, step) + val; 152 } 153 data += stride; 154 } 155 156 return (get_bits_count(&rc.gb) + 7) >> 3; 157} 158 159static int decode_frame(AVCodecContext *avctx, 160 void *data, int *data_size, 161 const uint8_t *buf, int buf_size) 162{ 163 LOCOContext * const l = avctx->priv_data; 164 AVFrame * const p= (AVFrame*)&l->pic; 165 int decoded; 166 167 if(p->data[0]) 168 avctx->release_buffer(avctx, p); 169 170 p->reference = 0; 171 if(avctx->get_buffer(avctx, p) < 0){ 172 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 173 return -1; 174 } 175 p->key_frame = 1; 176 177 switch(l->mode) { 178 case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY: 179 decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, 180 p->linesize[0], buf, buf_size, 1); 181 buf += decoded; buf_size -= decoded; 182 decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height, 183 p->linesize[1], buf, buf_size, 1); 184 buf += decoded; buf_size -= decoded; 185 decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height, 186 p->linesize[2], buf, buf_size, 1); 187 break; 188 case LOCO_CYV12: case LOCO_YV12: 189 decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, 190 p->linesize[0], buf, buf_size, 1); 191 buf += decoded; buf_size -= decoded; 192 decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2, 193 p->linesize[2], buf, buf_size, 1); 194 buf += decoded; buf_size -= decoded; 195 decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2, 196 p->linesize[1], buf, buf_size, 1); 197 break; 198 case LOCO_CRGB: case LOCO_RGB: 199 decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height, 200 -p->linesize[0], buf, buf_size, 3); 201 buf += decoded; buf_size -= decoded; 202 decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height, 203 -p->linesize[0], buf, buf_size, 3); 204 buf += decoded; buf_size -= decoded; 205 decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height, 206 -p->linesize[0], buf, buf_size, 3); 207 break; 208 case LOCO_RGBA: 209 decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, 210 p->linesize[0], buf, buf_size, 4); 211 buf += decoded; buf_size -= decoded; 212 decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height, 213 p->linesize[0], buf, buf_size, 4); 214 buf += decoded; buf_size -= decoded; 215 decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height, 216 p->linesize[0], buf, buf_size, 4); 217 buf += decoded; buf_size -= decoded; 218 decoded = loco_decode_plane(l, p->data[0] + 3, avctx->width, avctx->height, 219 p->linesize[0], buf, buf_size, 4); 220 break; 221 } 222 223 *data_size = sizeof(AVFrame); 224 *(AVFrame*)data = l->pic; 225 226 return buf_size; 227} 228 229static av_cold int decode_init(AVCodecContext *avctx){ 230 LOCOContext * const l = avctx->priv_data; 231 int version; 232 233 l->avctx = avctx; 234 if (avctx->extradata_size < 12) { 235 av_log(avctx, AV_LOG_ERROR, "Extradata size must be >= 12 instead of %i\n", 236 avctx->extradata_size); 237 return -1; 238 } 239 version = AV_RL32(avctx->extradata); 240 switch(version) { 241 case 1: 242 l->lossy = 0; 243 break; 244 case 2: 245 l->lossy = AV_RL32(avctx->extradata + 8); 246 break; 247 default: 248 l->lossy = AV_RL32(avctx->extradata + 8); 249 av_log(avctx, AV_LOG_INFO, "This is LOCO codec version %i, please upload file for study\n", version); 250 } 251 252 l->mode = AV_RL32(avctx->extradata + 4); 253 switch(l->mode) { 254 case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY: 255 avctx->pix_fmt = PIX_FMT_YUV422P; 256 break; 257 case LOCO_CRGB: case LOCO_RGB: 258 avctx->pix_fmt = PIX_FMT_BGR24; 259 break; 260 case LOCO_CYV12: case LOCO_YV12: 261 avctx->pix_fmt = PIX_FMT_YUV420P; 262 break; 263 case LOCO_CRGBA: case LOCO_RGBA: 264 avctx->pix_fmt = PIX_FMT_RGB32; 265 break; 266 default: 267 av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode); 268 return -1; 269 } 270 if(avctx->debug & FF_DEBUG_PICT_INFO) 271 av_log(avctx, AV_LOG_INFO, "lossy:%i, version:%i, mode: %i\n", l->lossy, version, l->mode); 272 273 return 0; 274} 275 276AVCodec loco_decoder = { 277 "loco", 278 CODEC_TYPE_VIDEO, 279 CODEC_ID_LOCO, 280 sizeof(LOCOContext), 281 decode_init, 282 NULL, 283 NULL, 284 decode_frame, 285 CODEC_CAP_DR1, 286 .long_name = NULL_IF_CONFIG_SMALL("LOCO"), 287}; 288