Silicon Graphics Motion Video Compressor 1 & 2 decoder
authorPeter Ross <pross@xvid.org>
Mon, 17 Dec 2012 09:37:54 +0000 (20:37 +1100)
committerVittorio Giovara <vittorio.giovara@gmail.com>
Sat, 19 Apr 2014 14:24:26 +0000 (16:24 +0200)
Signed-off-by: Vittorio Giovara <vittorio.giovara@gmail.com>
Changelog
doc/general.texi
libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/avcodec.h
libavcodec/codec_desc.c
libavcodec/mvcdec.c [new file with mode: 0644]
libavcodec/version.h

index 0205ecd..7d02d6f 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -20,6 +20,7 @@ version <next>:
 - MP2 encoding via TwoLAME
 - asettb filter
 - Silicon Graphics RLE 8-bit video decoder
+- Silicon Graphics Motion Video Compressor 1 & 2 decoder
 
 
 version 10:
index ddf1c90..569bbe0 100644 (file)
@@ -693,6 +693,8 @@ following image formats are supported:
     @tab used in some games by Entertainment Software Partners
 @item Sierra VMD video       @tab     @tab  X
     @tab Used in Sierra VMD files.
+@item Silicon Graphics Motion Video Compressor 1 (MVC1)  @tab     @tab  X
+@item Silicon Graphics Motion Video Compressor 2 (MVC2)  @tab     @tab  X
 @item Silicon Graphics RLE 8-bit video  @tab     @tab  X
 @item Smacker video          @tab     @tab  X
     @tab Video encoding used in Smacker.
index e920964..51df50b 100644 (file)
@@ -272,6 +272,8 @@ OBJS-$(CONFIG_MSS2_DECODER)            += mss2.o mss12.o mss2dsp.o
 OBJS-$(CONFIG_MSVIDEO1_DECODER)        += msvideo1.o
 OBJS-$(CONFIG_MSZH_DECODER)            += lcldec.o
 OBJS-$(CONFIG_MTS2_DECODER)            += mss4.o mss34dsp.o
+OBJS-$(CONFIG_MVC1_DECODER)            += mvcdec.o
+OBJS-$(CONFIG_MVC2_DECODER)            += mvcdec.o
 OBJS-$(CONFIG_MXPEG_DECODER)           += mxpegdec.o
 OBJS-$(CONFIG_NELLYMOSER_DECODER)      += nellymoserdec.o nellymoser.o
 OBJS-$(CONFIG_NELLYMOSER_ENCODER)      += nellymoserenc.o nellymoser.o
index 8f44e88..b7f2cb9 100644 (file)
@@ -199,6 +199,8 @@ void avcodec_register_all(void)
     REGISTER_DECODER(MSVIDEO1,          msvideo1);
     REGISTER_DECODER(MSZH,              mszh);
     REGISTER_DECODER(MTS2,              mts2);
+    REGISTER_DECODER(MVC1,              mvc1);
+    REGISTER_DECODER(MVC2,              mvc2);
     REGISTER_DECODER(MXPEG,             mxpeg);
     REGISTER_DECODER(NUV,               nuv);
     REGISTER_DECODER(PAF_VIDEO,         paf_video);
index b11bffa..2232931 100644 (file)
@@ -291,6 +291,8 @@ enum AVCodecID {
     AV_CODEC_ID_VP7,
     AV_CODEC_ID_SANM,
     AV_CODEC_ID_SGIRLE,
+    AV_CODEC_ID_MVC1,
+    AV_CODEC_ID_MVC2,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
index 2474261..22a7944 100644 (file)
@@ -924,6 +924,20 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("AJA Kona 10-bit RGB Codec"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_MVC1,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "mvc1",
+        .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
+    {
+        .id        = AV_CODEC_ID_MVC2,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "mvc2",
+        .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
     {
         .id        = AV_CODEC_ID_MXPEG,
         .type      = AVMEDIA_TYPE_VIDEO,
diff --git a/libavcodec/mvcdec.c b/libavcodec/mvcdec.c
new file mode 100644 (file)
index 0000000..fefb705
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Silicon Graphics Motion Video Compressor 1 & 2 decoder
+ * Copyright (c) 2012 Peter Ross
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Silicon Graphics Motion Video Compressor 1 & 2 decoder
+ */
+
+#include "libavutil/intreadwrite.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+
+typedef struct MvcContext {
+    AVFrame *frame;
+    int vflip;
+} MvcContext;
+
+static av_cold int mvc_decode_init(AVCodecContext *avctx)
+{
+    MvcContext *s = avctx->priv_data;
+    int width     = avctx->width;
+    int height    = avctx->height;
+    int ret;
+
+    if (avctx->codec_id == AV_CODEC_ID_MVC1) {
+        width  += 3;
+        height += 3;
+    }
+    width  &= ~3;
+    height &= ~3;
+    if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
+        return ret;
+
+    avctx->pix_fmt = (avctx->codec_id == AV_CODEC_ID_MVC1) ? AV_PIX_FMT_RGB555
+                                                           : AV_PIX_FMT_BGRA;
+    s->frame       = av_frame_alloc();
+    if (!s->frame)
+        return AVERROR(ENOMEM);
+
+    s->vflip = avctx->extradata_size >= 9 &&
+               !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
+    return 0;
+}
+
+static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb,
+                       uint8_t *dst_start, int width, int height, int linesize)
+{
+    uint8_t *dst;
+    uint16_t v[8];
+    int mask, x, y, i;
+
+    for (y = 0; y < height; y += 4) {
+        for (x = 0; x < width; x += 4) {
+            if (bytestream2_get_bytes_left(gb) < 6)
+                return 0;
+
+            mask = bytestream2_get_be16u(gb);
+            v[0] = bytestream2_get_be16u(gb);
+            v[1] = bytestream2_get_be16u(gb);
+            if ((v[0] & 0x8000)) {
+                if (bytestream2_get_bytes_left(gb) < 12) {
+                    av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
+                    return AVERROR_INVALIDDATA;
+                }
+                for (i = 2; i < 8; i++)
+                    v[i] = bytestream2_get_be16u(gb);
+            } else {
+                v[2] = v[4] = v[6] = v[0];
+                v[3] = v[5] = v[7] = v[1];
+            }
+
+#define PIX16(target, true, false)                                            \
+    i = (mask & target) ? true : false;                                       \
+    AV_WN16A(dst, v[i] & 0x7FFF);                                             \
+    dst += 2;
+
+#define ROW16(row, a1, a0, b1, b0)                                            \
+    dst = dst_start + (y + row) * linesize + x * 2;                           \
+    PIX16(1 << (row * 4), a1, a0)                                             \
+    PIX16(1 << (row * 4 + 1), a1, a0)                                         \
+    PIX16(1 << (row * 4 + 2), b1, b0)                                         \
+    PIX16(1 << (row * 4 + 3), b1, b0)
+
+            ROW16(0, 0, 1, 2, 3);
+            ROW16(1, 0, 1, 2, 3);
+            ROW16(2, 4, 5, 6, 7);
+            ROW16(3, 4, 5, 6, 7);
+        }
+    }
+    return 0;
+}
+
+static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
+{
+    int i, j;
+    for (j = 0; j < 4; j++)
+        for (i = 0; i < 4; i++)
+            AV_WN32A(dst + j * linesize + i * 4, pixel);
+}
+
+#define PIX32(target, true, false)                                            \
+    AV_WN32A(dst, (mask & target) ? v[true] : v[false]);                      \
+    dst += 4;
+
+#define ROW32(row, a1, a0, b1, b0)                                            \
+    dst = dst_start + (y + row) * linesize + x * 4;                           \
+    PIX32(1 << (row * 4), a1, a0)                                             \
+    PIX32(1 << (row * 4 + 1), a1, a0)                                         \
+    PIX32(1 << (row * 4 + 2), b1, b0)                                         \
+    PIX32(1 << (row * 4 + 3), b1, b0)
+
+#define MVC2_BLOCK                                                            \
+    ROW32(0, 1, 0, 3, 2);                                                     \
+    ROW32(1, 1, 0, 3, 2);                                                     \
+    ROW32(2, 5, 4, 7, 6);                                                     \
+    ROW32(3, 5, 4, 7, 6);
+
+static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb,
+                       uint8_t *dst_start, int width, int height,
+                       int linesize, int vflip)
+{
+    uint8_t *dst;
+    uint32_t color[128], v[8];
+    int w, h, nb_colors, i, x, y, p0, p1, mask;
+
+    if (bytestream2_get_bytes_left(gb) < 6)
+        return AVERROR_INVALIDDATA;
+
+    w = bytestream2_get_be16u(gb);
+    h = bytestream2_get_be16u(gb);
+    if ((w & ~3) != width || (h & ~3) != height)
+        av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
+
+    if (bytestream2_get_byteu(gb)) {
+        avpriv_request_sample(avctx, "bitmap feature");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    nb_colors = bytestream2_get_byteu(gb);
+    if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
+        return AVERROR_INVALIDDATA;
+    for (i = 0; i < FFMIN(nb_colors, 128); i++)
+        color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
+    if (nb_colors > 128)
+        bytestream2_skip(gb, (nb_colors - 128) * 3);
+
+    if (vflip) {
+        dst_start += (height - 1) * linesize;
+        linesize   = -linesize;
+    }
+    x = y = 0;
+    while (bytestream2_get_bytes_left(gb) >= 1) {
+        p0 = bytestream2_get_byteu(gb);
+        if ((p0 & 0x80)) {
+            if ((p0 & 0x40)) {
+                p0 &= 0x3F;
+                p0  = (p0 << 2) | (p0 >> 4);
+                set_4x4_block(dst_start + y * linesize + x * 4, linesize,
+                              0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
+            } else {
+                int g, r;
+                p0 &= 0x3F;
+                p0  = (p0 << 2) | (p0 >> 4);
+                if (bytestream2_get_bytes_left(gb) < 2)
+                    return AVERROR_INVALIDDATA;
+                g = bytestream2_get_byteu(gb);
+                r = bytestream2_get_byteu(gb);
+                set_4x4_block(dst_start + y * linesize + x * 4, linesize,
+                              0xFF000000 | (r << 16) | (g << 8) | p0);
+            }
+        } else {
+            if (bytestream2_get_bytes_left(gb) < 1)
+                return AVERROR_INVALIDDATA;
+            p1 = bytestream2_get_byteu(gb);
+            if ((p1 & 0x80)) {
+                if ((p0 & 0x7F) == (p1 & 0x7F)) {
+                    set_4x4_block(dst_start + y * linesize + x * 4, linesize,
+                                  color[p0 & 0x7F]);
+                } else {
+                    if (bytestream2_get_bytes_left(gb) < 2)
+                        return AVERROR_INVALIDDATA;
+                    v[0] = v[2] = v[4] = v[6] = color[p0 & 0x7F];
+                    v[1] = v[3] = v[5] = v[7] = color[p1 & 0x7F];
+                    mask = bytestream2_get_le16u(gb);
+                    MVC2_BLOCK
+                }
+            } else {
+                if (bytestream2_get_bytes_left(gb) < 8)
+                    return AVERROR_INVALIDDATA;
+                v[0] = color[p0 & 0x7F];
+                v[1] = color[p1 & 0x7F];
+                for (i = 2; i < 8; i++)
+                    v[i] = color[bytestream2_get_byteu(gb) & 0x7F];
+                mask = bytestream2_get_le16u(gb);
+                MVC2_BLOCK
+            }
+        }
+
+        x += 4;
+        if (x >= width) {
+            y += 4;
+            if (y >= height)
+                break;
+            x = 0;
+        }
+    }
+    return 0;
+}
+
+static int mvc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
+                            AVPacket *avpkt)
+{
+    MvcContext *s = avctx->priv_data;
+    GetByteContext gb;
+    int ret;
+
+    if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+        return ret;
+
+    bytestream2_init(&gb, avpkt->data, avpkt->size);
+    if (avctx->codec_id == AV_CODEC_ID_MVC1)
+        ret = decode_mvc1(avctx, &gb, s->frame->data[0],
+                          avctx->width, avctx->height, s->frame->linesize[0]);
+    else
+        ret = decode_mvc2(avctx, &gb, s->frame->data[0],
+                          avctx->width, avctx->height, s->frame->linesize[0],
+                          s->vflip);
+    if (ret < 0)
+        return ret;
+
+    *got_frame = 1;
+    if ((ret = av_frame_ref(data, s->frame)) < 0)
+        return ret;
+
+    return avpkt->size;
+}
+
+static av_cold int mvc_decode_end(AVCodecContext *avctx)
+{
+    MvcContext *s = avctx->priv_data;
+
+    av_frame_free(&s->frame);
+
+    return 0;
+}
+
+#if CONFIG_MVC1_DECODER
+AVCodec ff_mvc1_decoder = {
+    .name           = "mvc1",
+    .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_MVC1,
+    .priv_data_size = sizeof(MvcContext),
+    .init           = mvc_decode_init,
+    .close          = mvc_decode_end,
+    .decode         = mvc_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
+};
+#endif
+
+#if CONFIG_MVC2_DECODER
+AVCodec ff_mvc2_decoder = {
+    .name           = "mvc2",
+    .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_MVC2,
+    .priv_data_size = sizeof(MvcContext),
+    .init           = mvc_decode_init,
+    .close          = mvc_decode_end,
+    .decode         = mvc_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
+};
+#endif
index 234d409..aa5d04c 100644 (file)
@@ -29,7 +29,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 55
-#define LIBAVCODEC_VERSION_MINOR 47
+#define LIBAVCODEC_VERSION_MINOR 48
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \