LCOV - code coverage report
Current view: top level - libavcodec - motionpixels.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 166 192 86.5 %
Date: 2017-12-17 04:34:43 Functions: 12 12 100.0 %

          Line data    Source code
       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             : 
      31             : typedef struct HuffCode {
      32             :     int code;
      33             :     uint8_t size;
      34             :     uint8_t delta;
      35             : } HuffCode;
      36             : 
      37             : typedef 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             : 
      53           2 : static av_cold int mp_decode_end(AVCodecContext *avctx)
      54             : {
      55           2 :     MotionPixelsContext *mp = avctx->priv_data;
      56             : 
      57           2 :     av_freep(&mp->changes_map);
      58           2 :     av_freep(&mp->vpt);
      59           2 :     av_freep(&mp->hpt);
      60           2 :     av_freep(&mp->bswapbuf);
      61           2 :     av_frame_free(&mp->frame);
      62             : 
      63           2 :     return 0;
      64             : }
      65             : 
      66           2 : static av_cold int mp_decode_init(AVCodecContext *avctx)
      67             : {
      68           2 :     MotionPixelsContext *mp = avctx->priv_data;
      69           2 :     int w4 = (avctx->width  + 3) & ~3;
      70           2 :     int h4 = (avctx->height + 3) & ~3;
      71             : 
      72           2 :     if(avctx->extradata_size < 2){
      73           0 :         av_log(avctx, AV_LOG_ERROR, "extradata too small\n");
      74           0 :         return AVERROR_INVALIDDATA;
      75             :     }
      76             : 
      77           2 :     motionpixels_tableinit();
      78           2 :     mp->avctx = avctx;
      79           2 :     ff_bswapdsp_init(&mp->bdsp);
      80           2 :     mp->changes_map = av_mallocz_array(avctx->width, h4);
      81           2 :     mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1;
      82           2 :     mp->vpt = av_mallocz_array(avctx->height, sizeof(YuvPixel));
      83           2 :     mp->hpt = av_mallocz_array(h4 / 4, w4 / 4 * sizeof(YuvPixel));
      84           2 :     if (!mp->changes_map || !mp->vpt || !mp->hpt) {
      85           0 :         av_freep(&mp->changes_map);
      86           0 :         av_freep(&mp->vpt);
      87           0 :         av_freep(&mp->hpt);
      88           0 :         return AVERROR(ENOMEM);
      89             :     }
      90           2 :     avctx->pix_fmt = AV_PIX_FMT_RGB555;
      91             : 
      92           2 :     mp->frame = av_frame_alloc();
      93           2 :     if (!mp->frame) {
      94           0 :         mp_decode_end(avctx);
      95           0 :         return AVERROR(ENOMEM);
      96             :     }
      97             : 
      98           2 :     return 0;
      99             : }
     100             : 
     101         444 : static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color)
     102             : {
     103             :     uint16_t *pixels;
     104         444 :     int offset, w, h, color = 0, x, y, i;
     105             : 
     106       27863 :     while (count--) {
     107       26975 :         offset = get_bits_long(gb, mp->offset_bits_len);
     108       26975 :         w      = get_bits(gb, bits_len) + 1;
     109       26975 :         h      = get_bits(gb, bits_len) + 1;
     110       26975 :         if (read_color)
     111       16095 :             color = get_bits(gb, 15);
     112       26975 :         x = offset % mp->avctx->width;
     113       26975 :         y = offset / mp->avctx->width;
     114       26975 :         if (y >= mp->avctx->height)
     115           0 :             continue;
     116       26975 :         w = FFMIN(w, mp->avctx->width  - x);
     117       26975 :         h = FFMIN(h, mp->avctx->height - y);
     118       26975 :         pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
     119      352236 :         while (h--) {
     120      298286 :             mp->changes_map[offset] = w;
     121      298286 :             if (read_color)
     122     1832851 :                 for (i = 0; i < w; ++i)
     123     1646821 :                     pixels[i] = color;
     124      298286 :             offset += mp->avctx->width;
     125      298286 :             pixels += mp->frame->linesize[0] / 2;
     126             :         }
     127             :     }
     128         444 : }
     129             : 
     130        1651 : static int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size, int code)
     131             : {
     132        4842 :     while (get_bits1(gb)) {
     133        1540 :         ++size;
     134        1540 :         if (size > mp->max_codes_bits) {
     135           0 :             av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits);
     136           0 :             return AVERROR_INVALIDDATA;
     137             :         }
     138        1540 :         code <<= 1;
     139        1540 :         if (mp_get_code(mp, gb, size, code + 1) < 0)
     140           0 :             return AVERROR_INVALIDDATA;
     141             :     }
     142        1651 :     if (mp->current_codes_count >= MAX_HUFF_CODES) {
     143           0 :         av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n");
     144           0 :         return AVERROR_INVALIDDATA;
     145             :     }
     146             : 
     147        1651 :     mp->codes[mp->current_codes_count  ].code = code;
     148        1651 :     mp->codes[mp->current_codes_count++].size = size;
     149        1651 :     return 0;
     150             : }
     151             : 
     152         111 : static int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb)
     153             : {
     154         111 :     if (mp->codes_count == 1) {
     155           0 :         mp->codes[0].delta = get_bits(gb, 4);
     156             :     } else {
     157             :         int i;
     158             :         int ret;
     159             : 
     160         111 :         mp->max_codes_bits = get_bits(gb, 4);
     161        1762 :         for (i = 0; i < mp->codes_count; ++i)
     162        1651 :             mp->codes[i].delta = get_bits(gb, 4);
     163         111 :         mp->current_codes_count = 0;
     164         111 :         if ((ret = mp_get_code(mp, gb, 0, 0)) < 0)
     165           0 :             return ret;
     166         111 :         if (mp->current_codes_count < mp->codes_count) {
     167           0 :             av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n");
     168           0 :             return AVERROR_INVALIDDATA;
     169             :         }
     170             :    }
     171         111 :    return 0;
     172             : }
     173             : 
     174     6395631 : static int mp_gradient(MotionPixelsContext *mp, int component, int v)
     175             : {
     176             :     int delta;
     177             : 
     178     6395631 :     delta = (v - 7) * mp->gradient_scale[component];
     179     6395631 :     mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1;
     180     6395631 :     return delta;
     181             : }
     182             : 
     183      340991 : static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y)
     184             : {
     185             :     int color;
     186             : 
     187      340991 :     color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
     188      340991 :     return mp_rgb_yuv_table[color];
     189             : }
     190             : 
     191     5666143 : static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p)
     192             : {
     193             :     int color;
     194             : 
     195     5666143 :     color = mp_yuv_to_rgb(p->y, p->v, p->u, 1);
     196     5666143 :     *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color;
     197     5666143 : }
     198             : 
     199     6395631 : static int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb)
     200             : {
     201             :     int i;
     202             : 
     203     6395631 :     i = (mp->codes_count == 1) ? 0 : get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1);
     204     6395631 :     return mp->codes[i].delta;
     205             : }
     206             : 
     207       26640 : static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y)
     208             : {
     209             :     YuvPixel p;
     210       26640 :     const int y0 = y * mp->avctx->width;
     211       26640 :     int w, i, x = 0;
     212             : 
     213       26640 :     p = mp->vpt[y];
     214       26640 :     if (mp->changes_map[y0 + x] == 0) {
     215       18532 :         memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
     216       18532 :         ++x;
     217             :     }
     218     5999277 :     while (x < mp->avctx->width) {
     219     5945997 :         w = mp->changes_map[y0 + x];
     220     5945997 :         if (w != 0) {
     221      298386 :             if ((y & 3) == 0) {
     222      142614 :                 if (mp->changes_map[y0 + x + mp->avctx->width] < w ||
     223      134529 :                     mp->changes_map[y0 + x + mp->avctx->width * 2] < w ||
     224       65081 :                     mp->changes_map[y0 + x + mp->avctx->width * 3] < w) {
     225       47814 :                     for (i = (x + 3) & ~3; i < x + w; i += 4) {
     226       34497 :                         mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y);
     227             :                     }
     228             :                 }
     229             :             }
     230      298386 :             x += w;
     231      298386 :             memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
     232      298386 :             p = mp_get_yuv_from_rgb(mp, x - 1, y);
     233             :         } else {
     234     5647611 :             p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
     235     5647611 :             p.y = av_clip_uintp2(p.y, 5);
     236     5647611 :             if ((x & 3) == 0) {
     237     1417461 :                 if ((y & 3) == 0) {
     238      360154 :                     p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
     239      360154 :                     p.v = av_clip_intp2(p.v, 5);
     240      360154 :                     p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
     241      360154 :                     p.u = av_clip_intp2(p.u, 5);
     242      360154 :                     mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p;
     243             :                 } else {
     244     1057307 :                     p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v;
     245     1057307 :                     p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u;
     246             :                 }
     247             :             }
     248     5647611 :             mp_set_rgb_from_yuv(mp, x, y, &p);
     249     5647611 :             ++x;
     250             :         }
     251             :     }
     252       26640 : }
     253             : 
     254         111 : static 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       26751 :     for (y = 0; y < mp->avctx->height; ++y) {
     262       26640 :         if (mp->changes_map[y * mp->avctx->width] != 0) {
     263        8108 :             memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
     264        8108 :             p = mp_get_yuv_from_rgb(mp, 0, y);
     265             :         } else {
     266       18532 :             p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
     267       18532 :             p.y = av_clip_uintp2(p.y, 5);
     268       18532 :             if ((y & 3) == 0) {
     269        4590 :                 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
     270        4590 :                 p.v = av_clip_intp2(p.v, 5);
     271        4590 :                 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
     272        4590 :                 p.u = av_clip_intp2(p.u, 5);
     273             :             }
     274       18532 :             mp->vpt[y] = p;
     275       18532 :             mp_set_rgb_from_yuv(mp, 0, y, &p);
     276             :         }
     277             :     }
     278         333 :     for (y0 = 0; y0 < 2; ++y0)
     279       26862 :         for (y = y0; y < mp->avctx->height; y += 2)
     280       26640 :             mp_decode_line(mp, gb, y);
     281         111 : }
     282             : 
     283         111 : static int mp_decode_frame(AVCodecContext *avctx,
     284             :                                  void *data, int *got_frame,
     285             :                                  AVPacket *avpkt)
     286             : {
     287         111 :     const uint8_t *buf = avpkt->data;
     288         111 :     int buf_size = avpkt->size;
     289         111 :     MotionPixelsContext *mp = avctx->priv_data;
     290             :     GetBitContext gb;
     291             :     int i, count1, count2, sz, ret;
     292             : 
     293         111 :     if ((ret = ff_reget_buffer(avctx, mp->frame)) < 0)
     294           0 :         return ret;
     295             : 
     296             :     /* le32 bitstream msb first */
     297         111 :     av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size);
     298         111 :     if (!mp->bswapbuf)
     299           0 :         return AVERROR(ENOMEM);
     300         111 :     mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf,
     301             :                        buf_size / 4);
     302         111 :     if (buf_size & 3)
     303          87 :         memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3);
     304         111 :     init_get_bits(&gb, mp->bswapbuf, buf_size * 8);
     305             : 
     306         111 :     memset(mp->changes_map, 0, avctx->width * avctx->height);
     307         333 :     for (i = !(avctx->extradata[1] & 2); i < 2; ++i) {
     308         222 :         count1 = get_bits(&gb, 12);
     309         222 :         count2 = get_bits(&gb, 12);
     310         222 :         mp_read_changes_map(mp, &gb, count1, 8, i);
     311         222 :         mp_read_changes_map(mp, &gb, count2, 4, i);
     312             :     }
     313             : 
     314         111 :     mp->codes_count = get_bits(&gb, 4);
     315         111 :     if (mp->codes_count == 0)
     316           0 :         goto end;
     317             : 
     318         111 :     if (mp->changes_map[0] == 0) {
     319         100 :         *(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15);
     320         100 :         mp->changes_map[0] = 1;
     321             :     }
     322         111 :     if (mp_read_codes_table(mp, &gb) < 0)
     323           0 :         goto end;
     324             : 
     325         111 :     sz = get_bits(&gb, 18);
     326         111 :     if (avctx->extradata[0] != 5)
     327         111 :         sz += get_bits(&gb, 18);
     328         111 :     if (sz == 0)
     329           0 :         goto end;
     330             : 
     331         111 :     if (mp->max_codes_bits <= 0)
     332           0 :         goto end;
     333         111 :     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           0 :         goto end;
     335         111 :     mp_decode_frame_helper(mp, &gb);
     336         111 :     ff_free_vlc(&mp->vlc);
     337             : 
     338         111 : end:
     339         111 :     if ((ret = av_frame_ref(data, mp->frame)) < 0)
     340           0 :         return ret;
     341         111 :     *got_frame       = 1;
     342         111 :     return buf_size;
     343             : }
     344             : 
     345             : AVCodec 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   = AV_CODEC_CAP_DR1,
     355             : };

Generated by: LCOV version 1.13