Mercurial > libavcodec.hg
annotate motionpixels.c @ 10061:09f2db2d7c90 libavcodec
Fix bug caused by difference in stride and picture width.
When a frame is allocated using libschroedinger routines, the frame data size
does not match the actual frame size if the width is not a multiple of 16. So
we cannot do a straightforward memcpy of the frame returned by libschroedinger
into the FFmpeg picture as the stride differs from the width.
Fix this bug by allocating for the libschroedinger frame with the dimensions
in AVCodecContext within libavcodec and passing the frame to libschroedinger.
patch by Anuradha Suraparaju, anuradha rd.bbc.co uk
| author | diego |
|---|---|
| date | Sat, 15 Aug 2009 11:59:53 +0000 |
| parents | 26ccdc910898 |
| children | 2e01212efb32 |
| rev | line source |
|---|---|
| 7231 | 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" | |
| 9428 | 23 #include "get_bits.h" |
| 7231 | 24 #include "dsputil.h" |
| 25 | |
| 26 #define MAX_HUFF_CODES 16 | |
| 27 | |
| 28 typedef struct YuvPixel { | |
| 29 int8_t y, v, u; | |
| 30 } YuvPixel; | |
| 31 | |
| 32 typedef struct HuffCode { | |
| 33 int code; | |
| 34 uint8_t size; | |
| 35 uint8_t delta; | |
| 36 } HuffCode; | |
| 37 | |
| 38 typedef struct MotionPixelsContext { | |
| 39 AVCodecContext *avctx; | |
| 40 AVFrame frame; | |
| 41 DSPContext dsp; | |
| 42 uint8_t *changes_map; | |
| 43 int offset_bits_len; | |
| 44 int codes_count, current_codes_count; | |
| 45 int max_codes_bits; | |
| 46 HuffCode codes[MAX_HUFF_CODES]; | |
| 47 VLC vlc; | |
| 48 YuvPixel *vpt, *hpt; | |
| 49 uint8_t gradient_scale[3]; | |
| 50 uint8_t *bswapbuf; | |
| 51 int bswapbuf_size; | |
| 52 } MotionPixelsContext; | |
| 53 | |
| 54 static YuvPixel mp_rgb_yuv_table[1 << 15]; | |
| 55 | |
| 56 static int mp_yuv_to_rgb(int y, int v, int u, int clip_rgb) { | |
| 57 static const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; | |
| 58 int r, g, b; | |
| 59 | |
| 60 r = (1000 * y + 701 * v) / 1000; | |
| 61 g = (1000 * y - 357 * v - 172 * u) / 1000; | |
| 62 b = (1000 * y + 886 * u) / 1000; | |
| 63 if (clip_rgb) | |
| 64 return ((cm[r * 8] & 0xF8) << 7) | ((cm[g * 8] & 0xF8) << 2) | (cm[b * 8] >> 3); | |
| 65 if ((unsigned)r < 32 && (unsigned)g < 32 && (unsigned)b < 32) | |
| 66 return (r << 10) | (g << 5) | b; | |
| 67 return 1 << 15; | |
| 68 } | |
| 69 | |
| 70 static void mp_set_zero_yuv(YuvPixel *p) | |
| 71 { | |
| 72 int i, j; | |
| 73 | |
| 74 for (i = 0; i < 31; ++i) { | |
| 75 for (j = 31; j > i; --j) | |
| 76 if (!(p[j].u | p[j].v | p[j].y)) | |
| 77 p[j] = p[j - 1]; | |
| 78 for (j = 0; j < 31 - i; ++j) | |
| 79 if (!(p[j].u | p[j].v | p[j].y)) | |
| 80 p[j] = p[j + 1]; | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 static void mp_build_rgb_yuv_table(YuvPixel *p) | |
| 85 { | |
| 86 int y, v, u, i; | |
| 87 | |
| 88 for (y = 0; y <= 31; ++y) | |
| 89 for (v = -31; v <= 31; ++v) | |
| 90 for (u = -31; u <= 31; ++u) { | |
| 91 i = mp_yuv_to_rgb(y, v, u, 0); | |
| 92 if (i < (1 << 15) && !(p[i].u | p[i].v | p[i].y)) { | |
| 93 p[i].y = y; | |
| 94 p[i].v = v; | |
| 95 p[i].u = u; | |
| 96 } | |
| 97 } | |
| 98 for (i = 0; i < 1024; ++i) | |
| 99 mp_set_zero_yuv(p + i * 32); | |
| 100 } | |
| 101 | |
| 102 static av_cold int mp_decode_init(AVCodecContext *avctx) | |
| 103 { | |
| 104 MotionPixelsContext *mp = avctx->priv_data; | |
| 105 | |
| 106 if (!mp_rgb_yuv_table[0].u) { | |
| 107 mp_build_rgb_yuv_table(mp_rgb_yuv_table); | |
| 108 } | |
| 109 mp->avctx = avctx; | |
| 110 dsputil_init(&mp->dsp, avctx); | |
| 111 mp->changes_map = av_mallocz(avctx->width * avctx->height); | |
| 112 mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1; | |
| 113 mp->vpt = av_mallocz(avctx->height * sizeof(YuvPixel)); | |
| 114 mp->hpt = av_mallocz(avctx->height * avctx->width / 16 * sizeof(YuvPixel)); | |
| 115 return 0; | |
| 116 } | |
| 117 | |
| 118 static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color) | |
| 119 { | |
| 120 uint16_t *pixels; | |
| 121 int offset, w, h, color = 0, x, y, i; | |
| 122 | |
| 123 while (count--) { | |
| 124 offset = get_bits_long(gb, mp->offset_bits_len); | |
| 125 w = get_bits(gb, bits_len) + 1; | |
| 126 h = get_bits(gb, bits_len) + 1; | |
| 127 if (read_color) | |
| 128 color = get_bits(gb, 15); | |
| 129 x = offset % mp->avctx->width; | |
| 130 y = offset / mp->avctx->width; | |
| 131 if (y >= mp->avctx->height) | |
| 132 continue; | |
| 133 w = FFMIN(w, mp->avctx->width - x); | |
| 134 h = FFMIN(h, mp->avctx->height - y); | |
| 135 pixels = (uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2]; | |
| 136 while (h--) { | |
| 137 mp->changes_map[offset] = w; | |
| 138 if (read_color) | |
| 139 for (i = 0; i < w; ++i) | |
| 140 pixels[i] = color; | |
| 141 offset += mp->avctx->width; | |
| 142 pixels += mp->frame.linesize[0] / 2; | |
| 143 } | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 static void mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size, int code) | |
| 148 { | |
| 149 while (get_bits1(gb)) { | |
| 150 ++size; | |
| 151 if (size > mp->max_codes_bits) { | |
| 152 av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits); | |
| 153 return; | |
| 154 } | |
| 155 code <<= 1; | |
| 156 mp_get_code(mp, gb, size, code + 1); | |
| 157 } | |
| 158 if (mp->current_codes_count >= MAX_HUFF_CODES) { | |
| 159 av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n"); | |
| 160 return; | |
| 161 } | |
| 162 mp->codes[mp->current_codes_count ].code = code; | |
| 163 mp->codes[mp->current_codes_count++].size = size; | |
| 164 } | |
| 165 | |
| 166 static void mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb) | |
| 167 { | |
| 168 if (mp->codes_count == 1) { | |
| 169 mp->codes[0].delta = get_bits(gb, 4); | |
| 170 } else { | |
| 171 int i; | |
| 172 | |
| 173 mp->max_codes_bits = get_bits(gb, 4); | |
| 174 for (i = 0; i < mp->codes_count; ++i) | |
| 175 mp->codes[i].delta = get_bits(gb, 4); | |
| 176 mp->current_codes_count = 0; | |
| 177 mp_get_code(mp, gb, 0, 0); | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 static int mp_gradient(MotionPixelsContext *mp, int component, int v) | |
| 182 { | |
| 183 int delta; | |
| 184 | |
| 185 delta = (v - 7) * mp->gradient_scale[component]; | |
| 186 mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1; | |
| 187 return delta; | |
| 188 } | |
| 189 | |
| 190 static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y) | |
| 191 { | |
| 192 int color; | |
| 193 | |
| 194 color = *(uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2]; | |
| 195 return mp_rgb_yuv_table[color]; | |
| 196 } | |
| 197 | |
| 198 static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p) | |
| 199 { | |
| 200 int color; | |
| 201 | |
| 202 color = mp_yuv_to_rgb(p->y, p->v, p->u, 1); | |
| 203 *(uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2] = color; | |
| 204 } | |
| 205 | |
| 206 static int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb) | |
| 207 { | |
| 208 int i; | |
| 209 | |
| 210 i = (mp->codes_count == 1) ? 0 : get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1); | |
| 211 return mp->codes[i].delta; | |
| 212 } | |
| 213 | |
| 214 static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y) | |
| 215 { | |
| 216 YuvPixel p; | |
| 217 const int y0 = y * mp->avctx->width; | |
| 218 int w, i, x = 0; | |
| 219 | |
| 220 p = mp->vpt[y]; | |
| 221 if (mp->changes_map[y0 + x] == 0) { | |
| 222 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); | |
| 223 ++x; | |
| 224 } | |
| 225 while (x < mp->avctx->width) { | |
| 226 w = mp->changes_map[y0 + x]; | |
| 227 if (w != 0) { | |
| 228 if ((y & 3) == 0) { | |
| 229 if (mp->changes_map[y0 + x + mp->avctx->width] < w || | |
| 230 mp->changes_map[y0 + x + mp->avctx->width * 2] < w || | |
| 231 mp->changes_map[y0 + x + mp->avctx->width * 3] < w) { | |
| 232 for (i = (x + 3) & ~3; i < x + w; i += 4) { | |
| 233 mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y); | |
| 234 } | |
| 235 } | |
| 236 } | |
| 237 x += w; | |
| 238 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); | |
| 239 p = mp_get_yuv_from_rgb(mp, x - 1, y); | |
| 240 } else { | |
| 241 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); | |
| 242 if ((x & 3) == 0) { | |
| 243 if ((y & 3) == 0) { | |
| 244 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); | |
| 245 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); | |
| 246 mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p; | |
| 247 } else { | |
| 248 p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v; | |
| 249 p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u; | |
| 250 } | |
| 251 } | |
| 252 mp_set_rgb_from_yuv(mp, x, y, &p); | |
| 253 ++x; | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb) | |
| 259 { | |
| 260 YuvPixel p; | |
| 261 int y, y0; | |
| 262 | |
| 263 for (y = 0; y < mp->avctx->height; ++y) { | |
| 264 if (mp->changes_map[y * mp->avctx->width] != 0) { | |
| 265 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); | |
| 266 p = mp_get_yuv_from_rgb(mp, 0, y); | |
| 267 } else { | |
| 268 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); | |
| 269 if ((y & 3) == 0) { | |
| 270 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); | |
| 271 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); | |
| 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 | |
| 282 static int mp_decode_frame(AVCodecContext *avctx, | |
| 283 void *data, int *data_size, | |
|
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
284 AVPacket *avpkt) |
| 7231 | 285 { |
|
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
286 const uint8_t *buf = avpkt->data; |
|
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
287 int buf_size = avpkt->size; |
| 7231 | 288 MotionPixelsContext *mp = avctx->priv_data; |
| 289 GetBitContext gb; | |
| 290 int i, count1, count2, sz; | |
| 291 | |
| 292 mp->frame.reference = 1; | |
| 293 mp->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; | |
| 294 if (avctx->reget_buffer(avctx, &mp->frame)) { | |
| 295 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); | |
| 296 return -1; | |
| 297 } | |
| 298 | |
| 299 /* le32 bitstream msb first */ | |
|
9415
141badec76fc
Add a av_fast_malloc function and replace several uses of av_fast_realloc,
reimar
parents:
9355
diff
changeset
|
300 av_fast_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE); |
|
141badec76fc
Add a av_fast_malloc function and replace several uses of av_fast_realloc,
reimar
parents:
9355
diff
changeset
|
301 if (!mp->bswapbuf) |
|
9583
26ccdc910898
Add missing return statement to out-of-memory condition. Fixes the warning:
diego
parents:
9428
diff
changeset
|
302 return AVERROR(ENOMEM); |
| 7231 | 303 mp->dsp.bswap_buf((uint32_t *)mp->bswapbuf, (const uint32_t *)buf, buf_size / 4); |
| 304 if (buf_size & 3) | |
| 305 memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3); | |
| 306 init_get_bits(&gb, mp->bswapbuf, buf_size * 8); | |
| 307 | |
| 308 memset(mp->changes_map, 0, avctx->width * avctx->height); | |
| 309 for (i = !(avctx->extradata[1] & 2); i < 2; ++i) { | |
| 310 count1 = get_bits(&gb, 12); | |
| 311 count2 = get_bits(&gb, 12); | |
| 312 mp_read_changes_map(mp, &gb, count1, 8, i); | |
| 313 mp_read_changes_map(mp, &gb, count2, 4, i); | |
| 314 } | |
| 315 | |
| 316 mp->codes_count = get_bits(&gb, 4); | |
| 317 if (mp->codes_count == 0) | |
| 318 goto end; | |
| 319 | |
| 320 if (mp->changes_map[0] == 0) { | |
| 321 *(uint16_t *)mp->frame.data[0] = get_bits(&gb, 15); | |
| 322 mp->changes_map[0] = 1; | |
| 323 } | |
| 324 mp_read_codes_table(mp, &gb); | |
| 325 | |
| 326 sz = get_bits(&gb, 18); | |
| 327 if (avctx->extradata[0] != 5) | |
| 328 sz += get_bits(&gb, 18); | |
| 329 if (sz == 0) | |
| 330 goto end; | |
| 331 | |
| 332 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); | |
| 333 mp_decode_frame_helper(mp, &gb); | |
| 334 free_vlc(&mp->vlc); | |
| 335 | |
| 336 end: | |
| 337 *data_size = sizeof(AVFrame); | |
| 338 *(AVFrame *)data = mp->frame; | |
| 339 return buf_size; | |
| 340 } | |
| 341 | |
| 342 static av_cold int mp_decode_end(AVCodecContext *avctx) | |
| 343 { | |
| 344 MotionPixelsContext *mp = avctx->priv_data; | |
| 345 | |
| 346 av_freep(&mp->changes_map); | |
| 347 av_freep(&mp->vpt); | |
| 348 av_freep(&mp->hpt); | |
| 349 av_freep(&mp->bswapbuf); | |
| 350 if (mp->frame.data[0]) | |
| 351 avctx->release_buffer(avctx, &mp->frame); | |
| 352 | |
| 353 return 0; | |
| 354 } | |
| 355 | |
| 356 AVCodec motionpixels_decoder = { | |
| 357 "motionpixels", | |
| 358 CODEC_TYPE_VIDEO, | |
| 359 CODEC_ID_MOTIONPIXELS, | |
| 360 sizeof(MotionPixelsContext), | |
| 361 mp_decode_init, | |
| 362 NULL, | |
| 363 mp_decode_end, | |
| 364 mp_decode_frame, | |
| 365 CODEC_CAP_DR1, | |
|
9083
bf274494b66e
Change a bunch of codec long_names to be more consistent and descriptive.
diego
parents:
7231
diff
changeset
|
366 .long_name = NULL_IF_CONFIG_SMALL("Motion Pixels video"), |
| 7231 | 367 }; |
