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