1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Motion Pixels Video Decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net) 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/thread.h" 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "config.h" 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_ci#include "avcodec.h" 27cabdff1aSopenharmony_ci#include "get_bits.h" 28cabdff1aSopenharmony_ci#include "bswapdsp.h" 29cabdff1aSopenharmony_ci#include "codec_internal.h" 30cabdff1aSopenharmony_ci#include "internal.h" 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_ci#define MAX_HUFF_CODES 16 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci#include "motionpixels_tablegen.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_citypedef struct HuffCode { 37cabdff1aSopenharmony_ci uint8_t size; 38cabdff1aSopenharmony_ci uint8_t delta; 39cabdff1aSopenharmony_ci} HuffCode; 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_citypedef struct MotionPixelsContext { 42cabdff1aSopenharmony_ci AVCodecContext *avctx; 43cabdff1aSopenharmony_ci AVFrame *frame; 44cabdff1aSopenharmony_ci BswapDSPContext bdsp; 45cabdff1aSopenharmony_ci uint8_t *changes_map; 46cabdff1aSopenharmony_ci int offset_bits_len; 47cabdff1aSopenharmony_ci int codes_count, current_codes_count; 48cabdff1aSopenharmony_ci int max_codes_bits; 49cabdff1aSopenharmony_ci HuffCode codes[MAX_HUFF_CODES]; 50cabdff1aSopenharmony_ci VLC vlc; 51cabdff1aSopenharmony_ci YuvPixel *vpt, *hpt; 52cabdff1aSopenharmony_ci uint8_t gradient_scale[3]; 53cabdff1aSopenharmony_ci uint8_t *bswapbuf; 54cabdff1aSopenharmony_ci int bswapbuf_size; 55cabdff1aSopenharmony_ci} MotionPixelsContext; 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_cistatic av_cold int mp_decode_end(AVCodecContext *avctx) 58cabdff1aSopenharmony_ci{ 59cabdff1aSopenharmony_ci MotionPixelsContext *mp = avctx->priv_data; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci av_freep(&mp->changes_map); 62cabdff1aSopenharmony_ci av_freep(&mp->vpt); 63cabdff1aSopenharmony_ci av_freep(&mp->hpt); 64cabdff1aSopenharmony_ci av_freep(&mp->bswapbuf); 65cabdff1aSopenharmony_ci av_frame_free(&mp->frame); 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci return 0; 68cabdff1aSopenharmony_ci} 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic av_cold int mp_decode_init(AVCodecContext *avctx) 71cabdff1aSopenharmony_ci{ 72cabdff1aSopenharmony_ci av_unused static AVOnce init_static_once = AV_ONCE_INIT; 73cabdff1aSopenharmony_ci MotionPixelsContext *mp = avctx->priv_data; 74cabdff1aSopenharmony_ci int w4 = (avctx->width + 3) & ~3; 75cabdff1aSopenharmony_ci int h4 = (avctx->height + 3) & ~3; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci if(avctx->extradata_size < 2){ 78cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "extradata too small\n"); 79cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 80cabdff1aSopenharmony_ci } 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci mp->avctx = avctx; 83cabdff1aSopenharmony_ci ff_bswapdsp_init(&mp->bdsp); 84cabdff1aSopenharmony_ci mp->changes_map = av_calloc(avctx->width, h4); 85cabdff1aSopenharmony_ci mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1; 86cabdff1aSopenharmony_ci mp->vpt = av_calloc(avctx->height, sizeof(*mp->vpt)); 87cabdff1aSopenharmony_ci mp->hpt = av_calloc(h4 / 4, w4 / 4 * sizeof(*mp->hpt)); 88cabdff1aSopenharmony_ci if (!mp->changes_map || !mp->vpt || !mp->hpt) 89cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 90cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_RGB555; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci mp->frame = av_frame_alloc(); 93cabdff1aSopenharmony_ci if (!mp->frame) 94cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci#if !CONFIG_HARDCODED_TABLES 97cabdff1aSopenharmony_ci ff_thread_once(&init_static_once, motionpixels_tableinit); 98cabdff1aSopenharmony_ci#endif 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci return 0; 101cabdff1aSopenharmony_ci} 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_cistatic void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color) 104cabdff1aSopenharmony_ci{ 105cabdff1aSopenharmony_ci uint16_t *pixels; 106cabdff1aSopenharmony_ci int offset, w, h, color = 0, x, y, i; 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci while (count--) { 109cabdff1aSopenharmony_ci offset = get_bits_long(gb, mp->offset_bits_len); 110cabdff1aSopenharmony_ci w = get_bits(gb, bits_len) + 1; 111cabdff1aSopenharmony_ci h = get_bits(gb, bits_len) + 1; 112cabdff1aSopenharmony_ci if (read_color) 113cabdff1aSopenharmony_ci color = get_bits(gb, 15); 114cabdff1aSopenharmony_ci x = offset % mp->avctx->width; 115cabdff1aSopenharmony_ci y = offset / mp->avctx->width; 116cabdff1aSopenharmony_ci if (y >= mp->avctx->height) 117cabdff1aSopenharmony_ci continue; 118cabdff1aSopenharmony_ci w = FFMIN(w, mp->avctx->width - x); 119cabdff1aSopenharmony_ci h = FFMIN(h, mp->avctx->height - y); 120cabdff1aSopenharmony_ci pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2]; 121cabdff1aSopenharmony_ci while (h--) { 122cabdff1aSopenharmony_ci mp->changes_map[offset] = w; 123cabdff1aSopenharmony_ci if (read_color) 124cabdff1aSopenharmony_ci for (i = 0; i < w; ++i) 125cabdff1aSopenharmony_ci pixels[i] = color; 126cabdff1aSopenharmony_ci offset += mp->avctx->width; 127cabdff1aSopenharmony_ci pixels += mp->frame->linesize[0] / 2; 128cabdff1aSopenharmony_ci } 129cabdff1aSopenharmony_ci } 130cabdff1aSopenharmony_ci} 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_cistatic int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size) 133cabdff1aSopenharmony_ci{ 134cabdff1aSopenharmony_ci while (get_bits1(gb)) { 135cabdff1aSopenharmony_ci ++size; 136cabdff1aSopenharmony_ci if (size > mp->max_codes_bits) { 137cabdff1aSopenharmony_ci av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits); 138cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 139cabdff1aSopenharmony_ci } 140cabdff1aSopenharmony_ci if (mp_get_code(mp, gb, size) < 0) 141cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 142cabdff1aSopenharmony_ci } 143cabdff1aSopenharmony_ci if (mp->current_codes_count >= mp->codes_count) { 144cabdff1aSopenharmony_ci av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n"); 145cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci mp->codes[mp->current_codes_count++].size = size; 149cabdff1aSopenharmony_ci return 0; 150cabdff1aSopenharmony_ci} 151cabdff1aSopenharmony_ci 152cabdff1aSopenharmony_cistatic int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb) 153cabdff1aSopenharmony_ci{ 154cabdff1aSopenharmony_ci if (mp->codes_count == 1) { 155cabdff1aSopenharmony_ci mp->codes[0].delta = get_bits(gb, 4); 156cabdff1aSopenharmony_ci } else { 157cabdff1aSopenharmony_ci int i; 158cabdff1aSopenharmony_ci int ret; 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci mp->max_codes_bits = get_bits(gb, 4); 161cabdff1aSopenharmony_ci for (i = 0; i < mp->codes_count; ++i) 162cabdff1aSopenharmony_ci mp->codes[i].delta = get_bits(gb, 4); 163cabdff1aSopenharmony_ci mp->current_codes_count = 0; 164cabdff1aSopenharmony_ci if ((ret = mp_get_code(mp, gb, 0)) < 0) 165cabdff1aSopenharmony_ci return ret; 166cabdff1aSopenharmony_ci if (mp->current_codes_count < mp->codes_count) { 167cabdff1aSopenharmony_ci av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n"); 168cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 169cabdff1aSopenharmony_ci } 170cabdff1aSopenharmony_ci } 171cabdff1aSopenharmony_ci return 0; 172cabdff1aSopenharmony_ci} 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_cistatic av_always_inline int mp_gradient(MotionPixelsContext *mp, int component, int v) 175cabdff1aSopenharmony_ci{ 176cabdff1aSopenharmony_ci int delta; 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci delta = (v - 7) * mp->gradient_scale[component]; 179cabdff1aSopenharmony_ci mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1; 180cabdff1aSopenharmony_ci return delta; 181cabdff1aSopenharmony_ci} 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_cistatic YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y) 184cabdff1aSopenharmony_ci{ 185cabdff1aSopenharmony_ci int color; 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2]; 188cabdff1aSopenharmony_ci return mp_rgb_yuv_table[color & 0x7FFF]; 189cabdff1aSopenharmony_ci} 190cabdff1aSopenharmony_ci 191cabdff1aSopenharmony_cistatic void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p) 192cabdff1aSopenharmony_ci{ 193cabdff1aSopenharmony_ci int color; 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_ci color = mp_yuv_to_rgb(p->y, p->v, p->u, 1); 196cabdff1aSopenharmony_ci *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color; 197cabdff1aSopenharmony_ci} 198cabdff1aSopenharmony_ci 199cabdff1aSopenharmony_cistatic av_always_inline int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb) 200cabdff1aSopenharmony_ci{ 201cabdff1aSopenharmony_ci return mp->vlc.table ? get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1) 202cabdff1aSopenharmony_ci : mp->codes[0].delta; 203cabdff1aSopenharmony_ci} 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_cistatic void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y) 206cabdff1aSopenharmony_ci{ 207cabdff1aSopenharmony_ci YuvPixel p; 208cabdff1aSopenharmony_ci const int y0 = y * mp->avctx->width; 209cabdff1aSopenharmony_ci int w, i, x = 0; 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci p = mp->vpt[y]; 212cabdff1aSopenharmony_ci if (mp->changes_map[y0 + x] == 0) { 213cabdff1aSopenharmony_ci memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); 214cabdff1aSopenharmony_ci ++x; 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci while (x < mp->avctx->width) { 217cabdff1aSopenharmony_ci w = mp->changes_map[y0 + x]; 218cabdff1aSopenharmony_ci if (w != 0) { 219cabdff1aSopenharmony_ci if ((y & 3) == 0) { 220cabdff1aSopenharmony_ci if (mp->changes_map[y0 + x + mp->avctx->width] < w || 221cabdff1aSopenharmony_ci mp->changes_map[y0 + x + mp->avctx->width * 2] < w || 222cabdff1aSopenharmony_ci mp->changes_map[y0 + x + mp->avctx->width * 3] < w) { 223cabdff1aSopenharmony_ci for (i = (x + 3) & ~3; i < x + w; i += 4) { 224cabdff1aSopenharmony_ci mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y); 225cabdff1aSopenharmony_ci } 226cabdff1aSopenharmony_ci } 227cabdff1aSopenharmony_ci } 228cabdff1aSopenharmony_ci x += w; 229cabdff1aSopenharmony_ci memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); 230cabdff1aSopenharmony_ci p = mp_get_yuv_from_rgb(mp, x - 1, y); 231cabdff1aSopenharmony_ci } else { 232cabdff1aSopenharmony_ci p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); 233cabdff1aSopenharmony_ci p.y = av_clip_uintp2(p.y, 5); 234cabdff1aSopenharmony_ci if ((x & 3) == 0) { 235cabdff1aSopenharmony_ci if ((y & 3) == 0) { 236cabdff1aSopenharmony_ci p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); 237cabdff1aSopenharmony_ci p.v = av_clip_intp2(p.v, 5); 238cabdff1aSopenharmony_ci p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); 239cabdff1aSopenharmony_ci p.u = av_clip_intp2(p.u, 5); 240cabdff1aSopenharmony_ci mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p; 241cabdff1aSopenharmony_ci } else { 242cabdff1aSopenharmony_ci p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v; 243cabdff1aSopenharmony_ci p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u; 244cabdff1aSopenharmony_ci } 245cabdff1aSopenharmony_ci } 246cabdff1aSopenharmony_ci mp_set_rgb_from_yuv(mp, x, y, &p); 247cabdff1aSopenharmony_ci ++x; 248cabdff1aSopenharmony_ci } 249cabdff1aSopenharmony_ci } 250cabdff1aSopenharmony_ci} 251cabdff1aSopenharmony_ci 252cabdff1aSopenharmony_cistatic void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb) 253cabdff1aSopenharmony_ci{ 254cabdff1aSopenharmony_ci YuvPixel p; 255cabdff1aSopenharmony_ci int y, y0; 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci av_assert1(mp->changes_map[0]); 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci for (y = 0; y < mp->avctx->height; ++y) { 260cabdff1aSopenharmony_ci if (mp->changes_map[y * mp->avctx->width] != 0) { 261cabdff1aSopenharmony_ci memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); 262cabdff1aSopenharmony_ci p = mp_get_yuv_from_rgb(mp, 0, y); 263cabdff1aSopenharmony_ci } else { 264cabdff1aSopenharmony_ci p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); 265cabdff1aSopenharmony_ci p.y = av_clip_uintp2(p.y, 5); 266cabdff1aSopenharmony_ci if ((y & 3) == 0) { 267cabdff1aSopenharmony_ci p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); 268cabdff1aSopenharmony_ci p.v = av_clip_intp2(p.v, 5); 269cabdff1aSopenharmony_ci p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); 270cabdff1aSopenharmony_ci p.u = av_clip_intp2(p.u, 5); 271cabdff1aSopenharmony_ci } 272cabdff1aSopenharmony_ci mp->vpt[y] = p; 273cabdff1aSopenharmony_ci mp_set_rgb_from_yuv(mp, 0, y, &p); 274cabdff1aSopenharmony_ci } 275cabdff1aSopenharmony_ci } 276cabdff1aSopenharmony_ci for (y0 = 0; y0 < 2; ++y0) 277cabdff1aSopenharmony_ci for (y = y0; y < mp->avctx->height; y += 2) 278cabdff1aSopenharmony_ci mp_decode_line(mp, gb, y); 279cabdff1aSopenharmony_ci} 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_cistatic int mp_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 282cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 283cabdff1aSopenharmony_ci{ 284cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 285cabdff1aSopenharmony_ci int buf_size = avpkt->size; 286cabdff1aSopenharmony_ci MotionPixelsContext *mp = avctx->priv_data; 287cabdff1aSopenharmony_ci GetBitContext gb; 288cabdff1aSopenharmony_ci int i, count1, count2, sz, ret; 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci if ((ret = ff_reget_buffer(avctx, mp->frame, 0)) < 0) 291cabdff1aSopenharmony_ci return ret; 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci /* le32 bitstream msb first */ 294cabdff1aSopenharmony_ci av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size); 295cabdff1aSopenharmony_ci if (!mp->bswapbuf) 296cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 297cabdff1aSopenharmony_ci mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf, 298cabdff1aSopenharmony_ci buf_size / 4); 299cabdff1aSopenharmony_ci if (buf_size & 3) 300cabdff1aSopenharmony_ci memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3); 301cabdff1aSopenharmony_ci init_get_bits(&gb, mp->bswapbuf, buf_size * 8); 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci memset(mp->changes_map, 0, avctx->width * avctx->height); 304cabdff1aSopenharmony_ci for (i = !(avctx->extradata[1] & 2); i < 2; ++i) { 305cabdff1aSopenharmony_ci count1 = get_bits(&gb, 12); 306cabdff1aSopenharmony_ci count2 = get_bits(&gb, 12); 307cabdff1aSopenharmony_ci mp_read_changes_map(mp, &gb, count1, 8, i); 308cabdff1aSopenharmony_ci mp_read_changes_map(mp, &gb, count2, 4, i); 309cabdff1aSopenharmony_ci } 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci mp->codes_count = get_bits(&gb, 4); 312cabdff1aSopenharmony_ci if (mp->codes_count == 0) 313cabdff1aSopenharmony_ci goto end; 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci if (mp->changes_map[0] == 0) { 316cabdff1aSopenharmony_ci *(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15); 317cabdff1aSopenharmony_ci mp->changes_map[0] = 1; 318cabdff1aSopenharmony_ci } 319cabdff1aSopenharmony_ci if (mp_read_codes_table(mp, &gb) < 0) 320cabdff1aSopenharmony_ci goto end; 321cabdff1aSopenharmony_ci 322cabdff1aSopenharmony_ci sz = get_bits(&gb, 18); 323cabdff1aSopenharmony_ci if (avctx->extradata[0] != 5) 324cabdff1aSopenharmony_ci sz += get_bits(&gb, 18); 325cabdff1aSopenharmony_ci if (sz == 0) 326cabdff1aSopenharmony_ci goto end; 327cabdff1aSopenharmony_ci 328cabdff1aSopenharmony_ci if (mp->codes_count > 1) { 329cabdff1aSopenharmony_ci /* The entries of the mp->codes array are sorted from right to left 330cabdff1aSopenharmony_ci * in the Huffman tree, hence -(int)sizeof(HuffCode). */ 331cabdff1aSopenharmony_ci ret = ff_init_vlc_from_lengths(&mp->vlc, mp->max_codes_bits, mp->codes_count, 332cabdff1aSopenharmony_ci &mp->codes[mp->codes_count - 1].size, -(int)sizeof(HuffCode), 333cabdff1aSopenharmony_ci &mp->codes[mp->codes_count - 1].delta, -(int)sizeof(HuffCode), 1, 334cabdff1aSopenharmony_ci 0, 0, avctx); 335cabdff1aSopenharmony_ci if (ret < 0) 336cabdff1aSopenharmony_ci goto end; 337cabdff1aSopenharmony_ci } 338cabdff1aSopenharmony_ci mp_decode_frame_helper(mp, &gb); 339cabdff1aSopenharmony_ci ff_free_vlc(&mp->vlc); 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ciend: 342cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, mp->frame)) < 0) 343cabdff1aSopenharmony_ci return ret; 344cabdff1aSopenharmony_ci *got_frame = 1; 345cabdff1aSopenharmony_ci return buf_size; 346cabdff1aSopenharmony_ci} 347cabdff1aSopenharmony_ci 348cabdff1aSopenharmony_ciconst FFCodec ff_motionpixels_decoder = { 349cabdff1aSopenharmony_ci .p.name = "motionpixels", 350cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Motion Pixels video"), 351cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 352cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_MOTIONPIXELS, 353cabdff1aSopenharmony_ci .priv_data_size = sizeof(MotionPixelsContext), 354cabdff1aSopenharmony_ci .init = mp_decode_init, 355cabdff1aSopenharmony_ci .close = mp_decode_end, 356cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(mp_decode_frame), 357cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 358cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE, 359cabdff1aSopenharmony_ci}; 360