Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Psygnosis YOP decoder
  3.  *
  4.  * Copyright (C) 2010 Mohamed Naufal Basheer <naufal11@gmail.com>
  5.  * derived from the code by
  6.  * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com>
  7.  *
  8.  * This file is part of FFmpeg.
  9.  *
  10.  * FFmpeg is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU Lesser General Public
  12.  * License as published by the Free Software Foundation; either
  13.  * version 2.1 of the License, or (at your option) any later version.
  14.  *
  15.  * FFmpeg is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18.  * Lesser General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU Lesser General Public
  21.  * License along with FFmpeg; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23.  */
  24.  
  25. #include "libavutil/intreadwrite.h"
  26. #include "libavutil/imgutils.h"
  27.  
  28. #include "avcodec.h"
  29. #include "get_bits.h"
  30. #include "internal.h"
  31.  
  32. typedef struct YopDecContext {
  33.     AVCodecContext *avctx;
  34.     AVFrame *frame;
  35.  
  36.     int num_pal_colors;
  37.     int first_color[2];
  38.     int frame_data_length;
  39.  
  40.     uint8_t *low_nibble;
  41.     uint8_t *srcptr;
  42.     uint8_t *src_end;
  43.     uint8_t *dstptr;
  44.     uint8_t *dstbuf;
  45. } YopDecContext;
  46.  
  47. // These tables are taken directly from:
  48. // http://wiki.multimedia.cx/index.php?title=Psygnosis_YOP
  49.  
  50. /**
  51.  * Lookup table for painting macroblocks. Bytes 0-2 of each entry contain
  52.  * the macroblock positions to be painted (taken as (0, B0, B1, B2)).
  53.  * Byte 3 contains the number of bytes consumed on the input,
  54.  * equal to max(bytes 0-2) + 1.
  55.  */
  56. static const uint8_t paint_lut[15][4] =
  57.     {{1, 2, 3, 4}, {1, 2, 0, 3},
  58.      {1, 2, 1, 3}, {1, 2, 2, 3},
  59.      {1, 0, 2, 3}, {1, 0, 0, 2},
  60.      {1, 0, 1, 2}, {1, 1, 2, 3},
  61.      {0, 1, 2, 3}, {0, 1, 0, 2},
  62.      {1, 1, 0, 2}, {0, 1, 1, 2},
  63.      {0, 0, 1, 2}, {0, 0, 0, 1},
  64.      {1, 1, 1, 2},
  65.     };
  66.  
  67. /**
  68.  * Lookup table for copying macroblocks. Each entry contains the respective
  69.  * x and y pixel offset for the copy source.
  70.  */
  71. static const int8_t motion_vector[16][2] =
  72.     {{-4, -4}, {-2, -4},
  73.      { 0, -4}, { 2, -4},
  74.      {-4, -2}, {-4,  0},
  75.      {-3, -3}, {-1, -3},
  76.      { 1, -3}, { 3, -3},
  77.      {-3, -1}, {-2, -2},
  78.      { 0, -2}, { 2, -2},
  79.      { 4, -2}, {-2,  0},
  80.     };
  81.  
  82. static av_cold int yop_decode_close(AVCodecContext *avctx)
  83. {
  84.     YopDecContext *s = avctx->priv_data;
  85.  
  86.     av_frame_free(&s->frame);
  87.  
  88.     return 0;
  89. }
  90.  
  91. static av_cold int yop_decode_init(AVCodecContext *avctx)
  92. {
  93.     YopDecContext *s = avctx->priv_data;
  94.     s->avctx = avctx;
  95.  
  96.     if (avctx->width & 1 || avctx->height & 1 ||
  97.         av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
  98.         av_log(avctx, AV_LOG_ERROR, "YOP has invalid dimensions\n");
  99.         return AVERROR_INVALIDDATA;
  100.     }
  101.  
  102.     if (avctx->extradata_size < 3) {
  103.         av_log(avctx, AV_LOG_ERROR, "Missing or incomplete extradata.\n");
  104.         return AVERROR_INVALIDDATA;
  105.     }
  106.  
  107.     avctx->pix_fmt = AV_PIX_FMT_PAL8;
  108.  
  109.     s->num_pal_colors = avctx->extradata[0];
  110.     s->first_color[0] = avctx->extradata[1];
  111.     s->first_color[1] = avctx->extradata[2];
  112.  
  113.     if (s->num_pal_colors + s->first_color[0] > 256 ||
  114.         s->num_pal_colors + s->first_color[1] > 256) {
  115.         av_log(avctx, AV_LOG_ERROR,
  116.                "Palette parameters invalid, header probably corrupt\n");
  117.         return AVERROR_INVALIDDATA;
  118.     }
  119.  
  120.     s->frame = av_frame_alloc();
  121.     if (!s->frame)
  122.         return AVERROR(ENOMEM);
  123.  
  124.     return 0;
  125. }
  126.  
  127. /**
  128.  * Paint a macroblock using the pattern in paint_lut.
  129.  * @param s codec context
  130.  * @param tag the tag that was in the nibble
  131.  */
  132. static int yop_paint_block(YopDecContext *s, int linesize, int tag)
  133. {
  134.     if (s->src_end - s->srcptr < paint_lut[tag][3]) {
  135.         av_log(s->avctx, AV_LOG_ERROR, "Packet too small.\n");
  136.         return AVERROR_INVALIDDATA;
  137.     }
  138.  
  139.     s->dstptr[0]            = s->srcptr[0];
  140.     s->dstptr[1]            = s->srcptr[paint_lut[tag][0]];
  141.     s->dstptr[linesize]     = s->srcptr[paint_lut[tag][1]];
  142.     s->dstptr[linesize + 1] = s->srcptr[paint_lut[tag][2]];
  143.  
  144.     // The number of src bytes consumed is in the last part of the lut entry.
  145.     s->srcptr += paint_lut[tag][3];
  146.     return 0;
  147. }
  148.  
  149. /**
  150.  * Copy a previously painted macroblock to the current_block.
  151.  * @param copy_tag the tag that was in the nibble
  152.  */
  153. static int yop_copy_previous_block(YopDecContext *s, int linesize, int copy_tag)
  154. {
  155.     uint8_t *bufptr;
  156.  
  157.     // Calculate position for the copy source
  158.     bufptr = s->dstptr + motion_vector[copy_tag][0] +
  159.              linesize * motion_vector[copy_tag][1];
  160.     if (bufptr < s->dstbuf) {
  161.         av_log(s->avctx, AV_LOG_ERROR, "File probably corrupt\n");
  162.         return AVERROR_INVALIDDATA;
  163.     }
  164.  
  165.     s->dstptr[0]            = bufptr[0];
  166.     s->dstptr[1]            = bufptr[1];
  167.     s->dstptr[linesize]     = bufptr[linesize];
  168.     s->dstptr[linesize + 1] = bufptr[linesize + 1];
  169.  
  170.     return 0;
  171. }
  172.  
  173. /**
  174.  * Return the next nibble in sequence, consuming a new byte on the input
  175.  * only if necessary.
  176.  */
  177. static uint8_t yop_get_next_nibble(YopDecContext *s)
  178. {
  179.     int ret;
  180.  
  181.     if (s->low_nibble) {
  182.         ret           = *s->low_nibble & 0xf;
  183.         s->low_nibble = NULL;
  184.     }else {
  185.         s->low_nibble = s->srcptr++;
  186.         ret           = *s->low_nibble >> 4;
  187.     }
  188.     return ret;
  189. }
  190.  
  191. static int yop_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
  192.                             AVPacket *avpkt)
  193. {
  194.     YopDecContext *s = avctx->priv_data;
  195.     AVFrame *frame = s->frame;
  196.     int tag, firstcolor, is_odd_frame;
  197.     int ret, i, x, y;
  198.     uint32_t *palette;
  199.  
  200.     if (avpkt->size < 4 + 3 * s->num_pal_colors) {
  201.         av_log(avctx, AV_LOG_ERROR, "Packet too small.\n");
  202.         return AVERROR_INVALIDDATA;
  203.     }
  204.  
  205.     if ((ret = ff_reget_buffer(avctx, frame)) < 0)
  206.         return ret;
  207.  
  208.     if (!avctx->frame_number)
  209.         memset(frame->data[1], 0, AVPALETTE_SIZE);
  210.  
  211.     s->dstbuf     = frame->data[0];
  212.     s->dstptr     = frame->data[0];
  213.     s->srcptr     = avpkt->data + 4;
  214.     s->src_end    = avpkt->data + avpkt->size;
  215.     s->low_nibble = NULL;
  216.  
  217.     is_odd_frame = avpkt->data[0];
  218.     if(is_odd_frame>1){
  219.         av_log(avctx, AV_LOG_ERROR, "frame is too odd %d\n", is_odd_frame);
  220.         return AVERROR_INVALIDDATA;
  221.     }
  222.     firstcolor   = s->first_color[is_odd_frame];
  223.     palette      = (uint32_t *)frame->data[1];
  224.  
  225.     for (i = 0; i < s->num_pal_colors; i++, s->srcptr += 3) {
  226.         palette[i + firstcolor] = (s->srcptr[0] << 18) |
  227.                                   (s->srcptr[1] << 10) |
  228.                                   (s->srcptr[2] << 2);
  229.         palette[i + firstcolor] |= 0xFFU << 24 |
  230.                                    (palette[i + firstcolor] >> 6) & 0x30303;
  231.     }
  232.  
  233.     frame->palette_has_changed = 1;
  234.  
  235.     for (y = 0; y < avctx->height; y += 2) {
  236.         for (x = 0; x < avctx->width; x += 2) {
  237.             if (s->srcptr - avpkt->data >= avpkt->size) {
  238.                 av_log(avctx, AV_LOG_ERROR, "Packet too small.\n");
  239.                 return AVERROR_INVALIDDATA;
  240.             }
  241.  
  242.             tag = yop_get_next_nibble(s);
  243.  
  244.             if (tag != 0xf) {
  245.                 ret = yop_paint_block(s, frame->linesize[0], tag);
  246.                 if (ret < 0)
  247.                     return ret;
  248.             } else {
  249.                 tag = yop_get_next_nibble(s);
  250.                 ret = yop_copy_previous_block(s, frame->linesize[0], tag);
  251.                 if (ret < 0)
  252.                     return ret;
  253.             }
  254.             s->dstptr += 2;
  255.         }
  256.         s->dstptr += 2*frame->linesize[0] - x;
  257.     }
  258.  
  259.     if ((ret = av_frame_ref(data, s->frame)) < 0)
  260.         return ret;
  261.  
  262.     *got_frame = 1;
  263.     return avpkt->size;
  264. }
  265.  
  266. AVCodec ff_yop_decoder = {
  267.     .name           = "yop",
  268.     .long_name      = NULL_IF_CONFIG_SMALL("Psygnosis YOP Video"),
  269.     .type           = AVMEDIA_TYPE_VIDEO,
  270.     .id             = AV_CODEC_ID_YOP,
  271.     .priv_data_size = sizeof(YopDecContext),
  272.     .init           = yop_decode_init,
  273.     .close          = yop_decode_close,
  274.     .decode         = yop_decode_frame,
  275. };
  276.