Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
  3.  * Copyright (c) 2012 Peter Ross
  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. /**
  23.  * @file
  24.  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
  25.  */
  26.  
  27. #include "libavutil/intreadwrite.h"
  28. #include "avcodec.h"
  29. #include "bytestream.h"
  30. #include "internal.h"
  31.  
  32. typedef struct MvcContext {
  33.     AVFrame *frame;
  34.     int vflip;
  35. } MvcContext;
  36.  
  37. static av_cold int mvc_decode_init(AVCodecContext *avctx)
  38. {
  39.     MvcContext *s = avctx->priv_data;
  40.     int width  = avctx->width;
  41.     int height = avctx->height;
  42.  
  43.     if (avctx->codec_id == AV_CODEC_ID_MVC1) {
  44.         width  += 3;
  45.         height += 3;
  46.     }
  47.     width  &= ~3;
  48.     height &= ~3;
  49.     if (width != avctx->width || height != avctx->height)
  50.         avcodec_set_dimensions(avctx, width, height);
  51.  
  52.     avctx->pix_fmt = (avctx->codec_id == AV_CODEC_ID_MVC1) ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_BGRA;
  53.     s->frame = av_frame_alloc();
  54.     if (!s->frame)
  55.         return AVERROR(ENOMEM);
  56.  
  57.     s->vflip = avctx->extradata_size >= 9 && !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
  58.     return 0;
  59. }
  60.  
  61. static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize)
  62. {
  63.     uint8_t *dst;
  64.     uint16_t v[8];
  65.     int mask, x, y, i;
  66.  
  67.     x = y= 0;
  68.     while (bytestream2_get_bytes_left(gb) >= 6) {
  69.         mask = bytestream2_get_be16u(gb);
  70.         v[0] = bytestream2_get_be16u(gb);
  71.         v[1] = bytestream2_get_be16u(gb);
  72.         if ((v[0] & 0x8000)) {
  73.             if (bytestream2_get_bytes_left(gb) < 12) {
  74.                 av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
  75.                 return AVERROR_INVALIDDATA;
  76.             }
  77.             for (i = 2; i < 8; i++)
  78.                 v[i] = bytestream2_get_be16u(gb);
  79.         } else {
  80.             v[2] = v[4] = v[6] = v[0];
  81.             v[3] = v[5] = v[7] = v[1];
  82.         }
  83.  
  84. #define PIX16(target, true, false) \
  85.         i = (mask & target) ? true : false; \
  86.         AV_WN16A(dst, (v[i] & 0x7C00) | (v[i] & 0x3E0) | (v[i] & 0x1F)); \
  87.         dst += 2;
  88.  
  89. #define ROW16(row, a1, a0, b1, b0) \
  90.         dst = dst_start + (y + row) * linesize + x * 2; \
  91.         PIX16(1 << (row * 4),     a1, a0) \
  92.         PIX16(1 << (row * 4 + 1), a1, a0) \
  93.         PIX16(1 << (row * 4 + 2), b1, b0) \
  94.         PIX16(1 << (row * 4 + 3), b1, b0)
  95.  
  96.         ROW16(0, 0, 1, 2, 3);
  97.         ROW16(1, 0, 1, 2, 3);
  98.         ROW16(2, 4, 5, 6, 7);
  99.         ROW16(3, 4, 5, 6, 7);
  100.  
  101.         x += 4;
  102.         if (x >= width) {
  103.             y += 4;
  104.             if (y >= height) {
  105.                 break;
  106.             }
  107.             x = 0;
  108.         }
  109.     }
  110.     return 0;
  111. }
  112.  
  113. static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
  114. {
  115.     int i, j;
  116.     for (j = 0; j < 4; j++)
  117.         for (i = 0; i < 4; i++)
  118.             AV_WN32A(dst + j * linesize + i * 4, pixel);
  119. }
  120.  
  121. #define PIX32(target, true, false) \
  122.     AV_WN32A(dst, (mask & target) ? v[true] : v[false]); \
  123.     dst += 4;
  124.  
  125. #define ROW32(row, a1, a0, b1, b0) \
  126.     dst = dst_start + (y + row) * linesize + x * 4; \
  127.     PIX32(1 << (row * 4),     a1, a0) \
  128.     PIX32(1 << (row * 4 + 1), a1, a0) \
  129.     PIX32(1 << (row * 4 + 2), b1, b0) \
  130.     PIX32(1 << (row * 4 + 3), b1, b0)
  131.  
  132. #define MVC2_BLOCK \
  133.     ROW32(0, 1, 0, 3, 2); \
  134.     ROW32(1, 1, 0, 3, 2); \
  135.     ROW32(2, 5, 4, 7, 6); \
  136.     ROW32(3, 5, 4, 7, 6);
  137.  
  138. static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize, int vflip)
  139. {
  140.     uint8_t *dst;
  141.     uint32_t color[128], v[8];
  142.     int w, h, nb_colors, i, x, y, p0, p1, mask;
  143.  
  144.     if (bytestream2_get_bytes_left(gb) < 6)
  145.         return AVERROR_INVALIDDATA;
  146.  
  147.     w = bytestream2_get_be16u(gb);
  148.     h = bytestream2_get_be16u(gb);
  149.     if ((w & ~3) != width || (h & ~3) != height)
  150.         av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
  151.  
  152.     if (bytestream2_get_byteu(gb)) {
  153.         avpriv_request_sample(avctx, "bitmap feature");
  154.         return AVERROR_PATCHWELCOME;
  155.     }
  156.  
  157.     nb_colors = bytestream2_get_byteu(gb);
  158.     if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
  159.         return AVERROR_INVALIDDATA;
  160.     for (i = 0; i < FFMIN(nb_colors, 128); i++)
  161.         color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
  162.     if (nb_colors > 128)
  163.         bytestream2_skip(gb, (nb_colors - 128) * 3);
  164.  
  165.     if (vflip) {
  166.         dst_start += (height - 1) * linesize;
  167.         linesize = -linesize;
  168.     }
  169.     x = y = 0;
  170.     while (bytestream2_get_bytes_left(gb) >= 1) {
  171.         p0 = bytestream2_get_byteu(gb);
  172.         if ((p0 & 0x80)) {
  173.             if ((p0 & 0x40)) {
  174.                 p0 &= 0x3F;
  175.                 p0 = (p0 << 2) | (p0 >> 4);
  176.                 set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
  177.             } else {
  178.                 int g, r;
  179.                 p0 &= 0x3F;
  180.                 p0 = (p0 << 2) | (p0 >> 4);
  181.                 if (bytestream2_get_bytes_left(gb) < 2)
  182.                     return AVERROR_INVALIDDATA;
  183.                 g = bytestream2_get_byteu(gb);
  184.                 r = bytestream2_get_byteu(gb);
  185.                 set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (r << 16) | (g << 8) | p0);
  186.             }
  187.         } else {
  188.             if (bytestream2_get_bytes_left(gb) < 1)
  189.                 return AVERROR_INVALIDDATA;
  190.             p1 = bytestream2_get_byteu(gb);
  191.             if ((p1 & 0x80)) {
  192.                 if ((p0 & 0x7F) == (p1 & 0x7F)) {
  193.                     set_4x4_block(dst_start + y * linesize + x * 4, linesize, color[p0 & 0x7F]);
  194.                 } else {
  195.                     if (bytestream2_get_bytes_left(gb) < 2)
  196.                         return AVERROR_INVALIDDATA;
  197.                     v[0] = v[2] = v[4] = v[6] = color[p0 & 0x7F];
  198.                     v[1] = v[3] = v[5] = v[7] = color[p1 & 0x7F];
  199.                     mask = bytestream2_get_le16u(gb);
  200.                     MVC2_BLOCK
  201.                 }
  202.             } else {
  203.                 if (bytestream2_get_bytes_left(gb) < 8)
  204.                     return AVERROR_INVALIDDATA;
  205.                 v[0] = color[p0 & 0x7F];
  206.                 v[1] = color[p1 & 0x7F];
  207.                 for (i = 2; i < 8; i++)
  208.                     v[i] = color[bytestream2_get_byteu(gb) & 0x7F];
  209.                 mask = bytestream2_get_le16u(gb);
  210.                 MVC2_BLOCK
  211.             }
  212.         }
  213.  
  214.         x += 4;
  215.         if (x >= width) {
  216.             y += 4;
  217.             if (y >= height)
  218.                 break;
  219.             x = 0;
  220.         }
  221.     }
  222.     return 0;
  223. }
  224.  
  225. static int mvc_decode_frame(AVCodecContext *avctx,
  226.                             void *data, int *got_frame,
  227.                             AVPacket *avpkt)
  228. {
  229.     MvcContext *s = avctx->priv_data;
  230.     GetByteContext gb;
  231.     int ret;
  232.  
  233.     if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
  234.         return ret;
  235.  
  236.     bytestream2_init(&gb, avpkt->data, avpkt->size);
  237.     if (avctx->codec_id == AV_CODEC_ID_MVC1)
  238.         ret = decode_mvc1(avctx, &gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]);
  239.     else
  240.         ret = decode_mvc2(avctx, &gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0], s->vflip);
  241.     if (ret < 0)
  242.         return ret;
  243.  
  244.     *got_frame = 1;
  245.     if ((ret = av_frame_ref(data, s->frame)) < 0)
  246.         return ret;
  247.  
  248.     return avpkt->size;
  249. }
  250.  
  251. static av_cold int mvc_decode_end(AVCodecContext *avctx)
  252. {
  253.     MvcContext *s = avctx->priv_data;
  254.  
  255.     av_frame_free(&s->frame);
  256.  
  257.     return 0;
  258. }
  259.  
  260. #if CONFIG_MVC1_DECODER
  261. AVCodec ff_mvc1_decoder = {
  262.     .name           = "mvc1",
  263.     .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
  264.     .type           = AVMEDIA_TYPE_VIDEO,
  265.     .id             = AV_CODEC_ID_MVC1,
  266.     .priv_data_size = sizeof(MvcContext),
  267.     .init           = mvc_decode_init,
  268.     .close          = mvc_decode_end,
  269.     .decode         = mvc_decode_frame,
  270.     .capabilities   = CODEC_CAP_DR1,
  271. };
  272. #endif
  273.  
  274. #if CONFIG_MVC2_DECODER
  275. AVCodec ff_mvc2_decoder = {
  276.     .name           = "mvc2",
  277.     .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
  278.     .type           = AVMEDIA_TYPE_VIDEO,
  279.     .id             = AV_CODEC_ID_MVC2,
  280.     .priv_data_size = sizeof(MvcContext),
  281.     .init           = mvc_decode_init,
  282.     .close          = mvc_decode_end,
  283.     .decode         = mvc_decode_frame,
  284.     .capabilities   = CODEC_CAP_DR1,
  285. };
  286. #endif
  287.