FFmpeg
Loading...
Searching...
No Matches
motionpixels.c
Go to the documentation of this file.
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/mem.h"
23#include "libavutil/thread.h"
24
25#include "config.h"
26
27#include "avcodec.h"
28#include "get_bits.h"
29#include "bswapdsp.h"
30#include "codec_internal.h"
31#include "decode.h"
32
33#define MAX_HUFF_CODES 16
34
36
37typedef struct HuffCode {
38 uint8_t size;
39 uint8_t delta;
40} HuffCode;
41
57
59{
61
62 av_freep(&mp->changes_map);
63 av_freep(&mp->vpt);
64 av_freep(&mp->hpt);
65 av_freep(&mp->bswapbuf);
66 av_frame_free(&mp->frame);
67
68 return 0;
69}
70
72{
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");
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);
91
92 mp->frame = av_frame_alloc();
93 if (!mp->frame)
94 return AVERROR(ENOMEM);
95
96#if !CONFIG_HARDCODED_TABLES
97 static AVOnce init_static_once = AV_ONCE_INIT;
98 ff_thread_once(&init_static_once, motionpixels_tableinit);
99#endif
100
101 return 0;
102}
103
104static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color)
105{
106 uint16_t *pixels;
107 int offset, w, h, color = 0, x, y, i;
108
109 while (count--) {
110 offset = get_bits_long(gb, mp->offset_bits_len);
111 w = get_bits(gb, bits_len) + 1;
112 h = get_bits(gb, bits_len) + 1;
113 if (read_color)
114 color = get_bits(gb, 15);
115 x = offset % mp->avctx->width;
116 y = offset / mp->avctx->width;
117 if (y >= mp->avctx->height)
118 continue;
119 w = FFMIN(w, mp->avctx->width - x);
120 h = FFMIN(h, mp->avctx->height - y);
121 pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
122 while (h--) {
123 mp->changes_map[offset] = w;
124 if (read_color)
125 for (i = 0; i < w; ++i)
126 pixels[i] = color;
127 offset += mp->avctx->width;
128 pixels += mp->frame->linesize[0] / 2;
129 }
130 }
131}
132
134{
135 while (get_bits1(gb)) {
136 ++size;
137 if (size > mp->max_codes_bits) {
138 av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits);
139 return AVERROR_INVALIDDATA;
140 }
141 if (mp_get_code(mp, gb, size) < 0)
142 return AVERROR_INVALIDDATA;
143 }
144 if (mp->current_codes_count >= mp->codes_count) {
145 av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n");
146 return AVERROR_INVALIDDATA;
147 }
148
149 mp->codes[mp->current_codes_count++].size = size;
150 return 0;
151}
152
154{
155 if (mp->codes_count == 1) {
156 mp->codes[0].delta = get_bits(gb, 4);
157 } else {
158 int i;
159 int ret;
160
161 mp->max_codes_bits = get_bits(gb, 4);
162 for (i = 0; i < mp->codes_count; ++i)
163 mp->codes[i].delta = get_bits(gb, 4);
164 mp->current_codes_count = 0;
165 if ((ret = mp_get_code(mp, gb, 0)) < 0)
166 return ret;
167 if (mp->current_codes_count < mp->codes_count) {
168 av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n");
169 return AVERROR_INVALIDDATA;
170 }
171 }
172 return 0;
173}
174
175static av_always_inline int mp_gradient(MotionPixelsContext *mp, int component, int v)
176{
177 int delta;
178
179 delta = (v - 7) * mp->gradient_scale[component];
180 mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1;
181 return delta;
182}
183
185{
186 int color;
187
188 color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
189 return mp_rgb_yuv_table[color & 0x7FFF];
190}
191
192static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p)
193{
194 int color;
195
196 color = mp_yuv_to_rgb(p->y, p->v, p->u, 1);
197 *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color;
198}
199
201{
202 return mp->vlc.table ? get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1)
203 : mp->codes[0].delta;
204}
205
207{
208 YuvPixel p;
209 const int y0 = y * mp->avctx->width;
210 int w, i, x = 0;
211
212 p = mp->vpt[y];
213 if (mp->changes_map[y0 + x] == 0) {
214 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
215 ++x;
216 }
217 while (x < mp->avctx->width) {
218 w = mp->changes_map[y0 + x];
219 if (w != 0) {
220 if ((y & 3) == 0) {
221 if (mp->changes_map[y0 + x + mp->avctx->width] < w ||
222 mp->changes_map[y0 + x + mp->avctx->width * 2] < w ||
223 mp->changes_map[y0 + x + mp->avctx->width * 3] < w) {
224 for (i = (x + 3) & ~3; i < x + w; i += 4) {
225 mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y);
226 }
227 }
228 }
229 x += w;
230 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
231 p = mp_get_yuv_from_rgb(mp, x - 1, y);
232 } else {
233 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
234 p.y = av_clip_uintp2(p.y, 5);
235 if ((x & 3) == 0) {
236 if ((y & 3) == 0) {
237 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
238 p.v = av_clip_intp2(p.v, 5);
239 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
240 p.u = av_clip_intp2(p.u, 5);
241 mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p;
242 } else {
243 p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v;
244 p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u;
245 }
246 }
247 mp_set_rgb_from_yuv(mp, x, y, &p);
248 ++x;
249 }
250 }
251}
252
254{
255 YuvPixel p;
256 int y, y0;
257
258 av_assert1(mp->changes_map[0]);
259
260 for (y = 0; y < mp->avctx->height; ++y) {
261 if (mp->changes_map[y * mp->avctx->width] != 0) {
262 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
263 p = mp_get_yuv_from_rgb(mp, 0, y);
264 } else {
265 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
266 p.y = av_clip_uintp2(p.y, 5);
267 if ((y & 3) == 0) {
268 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
269 p.v = av_clip_intp2(p.v, 5);
270 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
271 p.u = av_clip_intp2(p.u, 5);
272 }
273 mp->vpt[y] = p;
274 mp_set_rgb_from_yuv(mp, 0, y, &p);
275 }
276 }
277 for (y0 = 0; y0 < 2; ++y0)
278 for (y = y0; y < mp->avctx->height; y += 2)
279 mp_decode_line(mp, gb, y);
280}
281
282static int mp_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
283 int *got_frame, AVPacket *avpkt)
284{
285 const uint8_t *buf = avpkt->data;
286 int buf_size = avpkt->size;
288 GetBitContext gb;
289 int i, count1, count2, sz, ret;
290
291 if ((ret = ff_reget_buffer(avctx, mp->frame, 0)) < 0)
292 return ret;
293
294 /* le32 bitstream msb first */
295 av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size);
296 if (!mp->bswapbuf)
297 return AVERROR(ENOMEM);
298 mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf,
299 buf_size / 4);
300 if (buf_size & 3)
301 memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3);
302 init_get_bits(&gb, mp->bswapbuf, buf_size * 8);
303
304 memset(mp->changes_map, 0, avctx->width * avctx->height);
305 for (i = !(avctx->extradata[1] & 2); i < 2; ++i) {
306 count1 = get_bits(&gb, 12);
307 count2 = get_bits(&gb, 12);
308 mp_read_changes_map(mp, &gb, count1, 8, i);
309 mp_read_changes_map(mp, &gb, count2, 4, i);
310 }
311
312 mp->codes_count = get_bits(&gb, 4);
313 if (mp->codes_count == 0)
314 goto end;
315
316 if (mp->changes_map[0] == 0) {
317 *(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15);
318 mp->changes_map[0] = 1;
319 }
320 if (mp_read_codes_table(mp, &gb) < 0)
321 goto end;
322
323 sz = get_bits(&gb, 18);
324 if (avctx->extradata[0] != 5)
325 sz += get_bits(&gb, 18);
326 if (sz == 0)
327 goto end;
328
329 if (mp->codes_count > 1) {
330 /* The entries of the mp->codes array are sorted from right to left
331 * in the Huffman tree, hence -(int)sizeof(HuffCode). */
332 ret = ff_vlc_init_from_lengths(&mp->vlc, mp->max_codes_bits, mp->codes_count,
333 &mp->codes[mp->codes_count - 1].size, -(int)sizeof(HuffCode),
334 &mp->codes[mp->codes_count - 1].delta, -(int)sizeof(HuffCode), 1,
335 0, 0, avctx);
336 if (ret < 0)
337 goto end;
338 }
340 ff_vlc_free(&mp->vlc);
341
342end:
343 if ((ret = av_frame_ref(rframe, mp->frame)) < 0)
344 return ret;
345 *got_frame = 1;
346 return buf_size;
347}
348
350 .p.name = "motionpixels",
351 CODEC_LONG_NAME("Motion Pixels video"),
352 .p.type = AVMEDIA_TYPE_VIDEO,
354 .priv_data_size = sizeof(MotionPixelsContext),
358 .p.capabilities = AV_CODEC_CAP_DR1,
359 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
360};
static double mp(int i, double w0, double r)
Definition af_atilt.c:60
const FFCodec ff_motionpixels_decoder
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition avassert.h:58
Libavcodec external API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define FF_CODEC_DECODE_CB(func)
#define CODEC_LONG_NAME(str)
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
#define av_clip_intp2
Definition common.h:121
#define av_clip_uintp2
Definition common.h:124
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Identical in function to ff_get_buffer(), except it reuses the existing buffer if available.
Definition decode.c:1906
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
bitstream reader API header.
static unsigned int get_bits_long(GetBitContext *s, int n)
Read 0-32 bits.
Definition get_bits.h:424
static av_always_inline int get_vlc2(GetBitContext *s, const VLCElem *table, int bits, int max_depth)
Parse a vlc code.
Definition get_bits.h:645
static unsigned int get_bits1(GetBitContext *s)
Definition get_bits.h:391
static unsigned int get_bits(GetBitContext *s, int n)
Read 1-25 bits.
Definition get_bits.h:337
static int init_get_bits(GetBitContext *s, const uint8_t *buffer, int bit_size)
Initialize GetBitContext.
Definition get_bits.h:517
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
@ AV_CODEC_ID_MOTIONPIXELS
Definition codec_id.h:169
void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size)
Same behaviour av_fast_malloc but the buffer has additional AV_INPUT_BUFFER_PADDING_SIZE at the end w...
Definition utils.c:53
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition frame.c:278
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define av_log2
Definition intmath.h:84
unsigned offset
Definition libaomenc.c:763
av_cold void ff_bswapdsp_init(BswapDSPContext *c)
Definition bswapdsp.c:37
#define u(width, name, range_min, range_max)
Definition cbs_apv.c:68
#define av_always_inline
Definition attributes.h:72
#define av_cold
Definition attributes.h:117
#define AVOnce
Definition thread.h:202
static int ff_thread_once(char *control, void(*routine)(void))
Definition thread.h:205
#define AV_ONCE_INIT
Definition thread.h:203
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
static av_cold int mp_decode_end(AVCodecContext *avctx)
static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb)
static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y)
static int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size)
static int mp_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, AVPacket *avpkt)
static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p)
static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color)
static av_cold int mp_decode_init(AVCodecContext *avctx)
static av_always_inline int mp_gradient(MotionPixelsContext *mp, int component, int v)
#define MAX_HUFF_CODES
static av_always_inline int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb)
static int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb)
static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y)
static av_cold void motionpixels_tableinit(void)
static YuvPixel mp_rgb_yuv_table[1<< 15]
static int mp_yuv_to_rgb(int y, int v, int u, int clip_rgb)
#define AV_PIX_FMT_RGB555
Definition pixfmt.h:533
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
uint8_t * extradata
Out-of-band global headers that may be used by some codecs.
Definition avcodec.h:526
int extradata_size
Definition avcodec.h:527
void * priv_data
Definition avcodec.h:470
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
This structure stores compressed data.
Definition packet.h:580
int size
Definition packet.h:604
uint8_t * data
Definition packet.h:603
uint8_t size
uint8_t delta
HuffCode codes[MAX_HUFF_CODES]
BswapDSPContext bdsp
uint8_t gradient_scale[3]
AVCodecContext * avctx
Definition vlc.h:50
#define av_freep(p)
#define av_log(a,...)
int size
int ff_vlc_init_from_lengths(VLC *vlc, int nb_bits, int nb_codes, const int8_t *lens, int lens_wrap, const void *symbols, int symbols_wrap, int symbols_size, int offset, int flags, void *logctx)
Build VLC decoding tables suitable for use with get_vlc2()
Definition vlc.c:306
void ff_vlc_free(VLC *vlc)
Definition vlc.c:580
float delta