1/* 2 * Motion Pixels Video Decoder 3 * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net) 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#include "avcodec.h" 23#include "get_bits.h" 24#include "bswapdsp.h" 25#include "internal.h" 26 27#define MAX_HUFF_CODES 16 28 29#include "motionpixels_tablegen.h" 30 31typedef struct HuffCode { 32 int code; 33 uint8_t size; 34 uint8_t delta; 35} HuffCode; 36 37typedef struct MotionPixelsContext { 38 AVCodecContext *avctx; 39 AVFrame *frame; 40 BswapDSPContext bdsp; 41 uint8_t *changes_map; 42 int offset_bits_len; 43 int codes_count, current_codes_count; 44 int max_codes_bits; 45 HuffCode codes[MAX_HUFF_CODES]; 46 VLC vlc; 47 YuvPixel *vpt, *hpt; 48 uint8_t gradient_scale[3]; 49 uint8_t *bswapbuf; 50 int bswapbuf_size; 51} MotionPixelsContext; 52 53static av_cold int mp_decode_end(AVCodecContext *avctx) 54{ 55 MotionPixelsContext *mp = avctx->priv_data; 56 57 av_freep(&mp->changes_map); 58 av_freep(&mp->vpt); 59 av_freep(&mp->hpt); 60 av_freep(&mp->bswapbuf); 61 av_frame_free(&mp->frame); 62 63 return 0; 64} 65 66static av_cold int mp_decode_init(AVCodecContext *avctx) 67{ 68 MotionPixelsContext *mp = avctx->priv_data; 69 int w4 = (avctx->width + 3) & ~3; 70 int h4 = (avctx->height + 3) & ~3; 71 72 if(avctx->extradata_size < 2){ 73 av_log(avctx, AV_LOG_ERROR, "extradata too small\n"); 74 return AVERROR_INVALIDDATA; 75 } 76 77 motionpixels_tableinit(); 78 mp->avctx = avctx; 79 ff_bswapdsp_init(&mp->bdsp); 80 mp->changes_map = av_mallocz_array(avctx->width, h4); 81 mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1; 82 mp->vpt = av_mallocz_array(avctx->height, sizeof(YuvPixel)); 83 mp->hpt = av_mallocz_array(h4 / 4, w4 / 4 * sizeof(YuvPixel)); 84 if (!mp->changes_map || !mp->vpt || !mp->hpt) { 85 av_freep(&mp->changes_map); 86 av_freep(&mp->vpt); 87 av_freep(&mp->hpt); 88 return AVERROR(ENOMEM); 89 } 90 avctx->pix_fmt = AV_PIX_FMT_RGB555; 91 92 mp->frame = av_frame_alloc(); 93 if (!mp->frame) { 94 mp_decode_end(avctx); 95 return AVERROR(ENOMEM); 96 } 97 98 return 0; 99} 100 101static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color) 102{ 103 uint16_t *pixels; 104 int offset, w, h, color = 0, x, y, i; 105 106 while (count--) { 107 offset = get_bits_long(gb, mp->offset_bits_len); 108 w = get_bits(gb, bits_len) + 1; 109 h = get_bits(gb, bits_len) + 1; 110 if (read_color) 111 color = get_bits(gb, 15); 112 x = offset % mp->avctx->width; 113 y = offset / mp->avctx->width; 114 if (y >= mp->avctx->height) 115 continue; 116 w = FFMIN(w, mp->avctx->width - x); 117 h = FFMIN(h, mp->avctx->height - y); 118 pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2]; 119 while (h--) { 120 mp->changes_map[offset] = w; 121 if (read_color) 122 for (i = 0; i < w; ++i) 123 pixels[i] = color; 124 offset += mp->avctx->width; 125 pixels += mp->frame->linesize[0] / 2; 126 } 127 } 128} 129 130static int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size, int code) 131{ 132 while (get_bits1(gb)) { 133 ++size; 134 if (size > mp->max_codes_bits) { 135 av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits); 136 return AVERROR_INVALIDDATA; 137 } 138 code <<= 1; 139 if (mp_get_code(mp, gb, size, code + 1) < 0) 140 return AVERROR_INVALIDDATA; 141 } 142 if (mp->current_codes_count >= MAX_HUFF_CODES) { 143 av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n"); 144 return AVERROR_INVALIDDATA; 145 } 146 147 mp->codes[mp->current_codes_count ].code = code; 148 mp->codes[mp->current_codes_count++].size = size; 149 return 0; 150} 151 152static int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb) 153{ 154 if (mp->codes_count == 1) { 155 mp->codes[0].delta = get_bits(gb, 4); 156 } else { 157 int i; 158 int ret; 159 160 mp->max_codes_bits = get_bits(gb, 4); 161 for (i = 0; i < mp->codes_count; ++i) 162 mp->codes[i].delta = get_bits(gb, 4); 163 mp->current_codes_count = 0; 164 if ((ret = mp_get_code(mp, gb, 0, 0)) < 0) 165 return ret; 166 if (mp->current_codes_count < mp->codes_count) { 167 av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n"); 168 return AVERROR_INVALIDDATA; 169 } 170 } 171 return 0; 172} 173 174static int mp_gradient(MotionPixelsContext *mp, int component, int v) 175{ 176 int delta; 177 178 delta = (v - 7) * mp->gradient_scale[component]; 179 mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1; 180 return delta; 181} 182 183static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y) 184{ 185 int color; 186 187 color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2]; 188 return mp_rgb_yuv_table[color]; 189} 190 191static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p) 192{ 193 int color; 194 195 color = mp_yuv_to_rgb(p->y, p->v, p->u, 1); 196 *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color; 197} 198 199static int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb) 200{ 201 int i; 202 203 i = (mp->codes_count == 1) ? 0 : get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1); 204 return mp->codes[i].delta; 205} 206 207static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y) 208{ 209 YuvPixel p; 210 const int y0 = y * mp->avctx->width; 211 int w, i, x = 0; 212 213 p = mp->vpt[y]; 214 if (mp->changes_map[y0 + x] == 0) { 215 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); 216 ++x; 217 } 218 while (x < mp->avctx->width) { 219 w = mp->changes_map[y0 + x]; 220 if (w != 0) { 221 if ((y & 3) == 0) { 222 if (mp->changes_map[y0 + x + mp->avctx->width] < w || 223 mp->changes_map[y0 + x + mp->avctx->width * 2] < w || 224 mp->changes_map[y0 + x + mp->avctx->width * 3] < w) { 225 for (i = (x + 3) & ~3; i < x + w; i += 4) { 226 mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y); 227 } 228 } 229 } 230 x += w; 231 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); 232 p = mp_get_yuv_from_rgb(mp, x - 1, y); 233 } else { 234 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); 235 p.y = av_clip(p.y, 0, 31); 236 if ((x & 3) == 0) { 237 if ((y & 3) == 0) { 238 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); 239 p.v = av_clip(p.v, -32, 31); 240 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); 241 p.u = av_clip(p.u, -32, 31); 242 mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p; 243 } else { 244 p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v; 245 p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u; 246 } 247 } 248 mp_set_rgb_from_yuv(mp, x, y, &p); 249 ++x; 250 } 251 } 252} 253 254static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb) 255{ 256 YuvPixel p; 257 int y, y0; 258 259 av_assert1(mp->changes_map[0]); 260 261 for (y = 0; y < mp->avctx->height; ++y) { 262 if (mp->changes_map[y * mp->avctx->width] != 0) { 263 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); 264 p = mp_get_yuv_from_rgb(mp, 0, y); 265 } else { 266 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); 267 p.y = av_clip(p.y, 0, 31); 268 if ((y & 3) == 0) { 269 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); 270 p.v = av_clip(p.v, -32, 31); 271 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); 272 p.u = av_clip(p.u, -32, 31); 273 } 274 mp->vpt[y] = p; 275 mp_set_rgb_from_yuv(mp, 0, y, &p); 276 } 277 } 278 for (y0 = 0; y0 < 2; ++y0) 279 for (y = y0; y < mp->avctx->height; y += 2) 280 mp_decode_line(mp, gb, y); 281} 282 283static int mp_decode_frame(AVCodecContext *avctx, 284 void *data, int *got_frame, 285 AVPacket *avpkt) 286{ 287 const uint8_t *buf = avpkt->data; 288 int buf_size = avpkt->size; 289 MotionPixelsContext *mp = avctx->priv_data; 290 GetBitContext gb; 291 int i, count1, count2, sz, ret; 292 293 if ((ret = ff_reget_buffer(avctx, mp->frame)) < 0) 294 return ret; 295 296 /* le32 bitstream msb first */ 297 av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size); 298 if (!mp->bswapbuf) 299 return AVERROR(ENOMEM); 300 mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf, 301 buf_size / 4); 302 if (buf_size & 3) 303 memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3); 304 init_get_bits(&gb, mp->bswapbuf, buf_size * 8); 305 306 memset(mp->changes_map, 0, avctx->width * avctx->height); 307 for (i = !(avctx->extradata[1] & 2); i < 2; ++i) { 308 count1 = get_bits(&gb, 12); 309 count2 = get_bits(&gb, 12); 310 mp_read_changes_map(mp, &gb, count1, 8, i); 311 mp_read_changes_map(mp, &gb, count2, 4, i); 312 } 313 314 mp->codes_count = get_bits(&gb, 4); 315 if (mp->codes_count == 0) 316 goto end; 317 318 if (mp->changes_map[0] == 0) { 319 *(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15); 320 mp->changes_map[0] = 1; 321 } 322 if (mp_read_codes_table(mp, &gb) < 0) 323 goto end; 324 325 sz = get_bits(&gb, 18); 326 if (avctx->extradata[0] != 5) 327 sz += get_bits(&gb, 18); 328 if (sz == 0) 329 goto end; 330 331 if (mp->max_codes_bits <= 0) 332 goto end; 333 if (init_vlc(&mp->vlc, mp->max_codes_bits, mp->codes_count, &mp->codes[0].size, sizeof(HuffCode), 1, &mp->codes[0].code, sizeof(HuffCode), 4, 0)) 334 goto end; 335 mp_decode_frame_helper(mp, &gb); 336 ff_free_vlc(&mp->vlc); 337 338end: 339 if ((ret = av_frame_ref(data, mp->frame)) < 0) 340 return ret; 341 *got_frame = 1; 342 return buf_size; 343} 344 345AVCodec ff_motionpixels_decoder = { 346 .name = "motionpixels", 347 .long_name = NULL_IF_CONFIG_SMALL("Motion Pixels video"), 348 .type = AVMEDIA_TYPE_VIDEO, 349 .id = AV_CODEC_ID_MOTIONPIXELS, 350 .priv_data_size = sizeof(MotionPixelsContext), 351 .init = mp_decode_init, 352 .close = mp_decode_end, 353 .decode = mp_decode_frame, 354 .capabilities = CODEC_CAP_DR1, 355}; 356