Subversion Repositories Kolibri OS

Rev

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