Add TrueMotion 2.0 Real Time decoder
authorPaul B Mahol <onemda@gmail.com>
Fri, 17 Jun 2016 16:30:34 +0000 (12:30 -0400)
committerVittorio Giovara <vittorio.giovara@gmail.com>
Mon, 20 Jun 2016 19:48:12 +0000 (15:48 -0400)
Signed-off-by: Paul B Mahol <onemda@gmail.com>
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/truemotion2rt.c [new file with mode: 0644]
libavcodec/version.h
libavformat/riff.c

index a3f5376..ac4c725 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -58,6 +58,7 @@ version <next>:
 - MMAL-accelerated MPEG-2 and VC-1 decoding
 - G.729 raw demuxer
 - MagicYUV decoder
+- Duck TrueMotion 2.0 Real Time decoder
 
 
 version 11:
index a6a6db6..0590c23 100644 (file)
@@ -607,6 +607,8 @@ following image formats are supported:
     @tab fourcc: DUCK
 @item Duck TrueMotion 2.0    @tab     @tab  X
     @tab fourcc: TM20
+@item Duck TrueMotion 2.0 RT @tab     @tab  X
+    @tab fourcc: TR20
 @item DV (Digital Video)     @tab  X  @tab  X
 @item Dxtory capture format  @tab     @tab  X
 @item Feeble Files/ScummVM DXA  @tab     @tab  X
index 8352c97..1f2096c 100644 (file)
@@ -438,6 +438,7 @@ OBJS-$(CONFIG_TIFF_ENCODER)            += tiffenc.o rle.o lzwenc.o
 OBJS-$(CONFIG_TMV_DECODER)             += tmv.o cga_data.o
 OBJS-$(CONFIG_TRUEMOTION1_DECODER)     += truemotion1.o
 OBJS-$(CONFIG_TRUEMOTION2_DECODER)     += truemotion2.o
+OBJS-$(CONFIG_TRUEMOTION2RT_DECODER)   += truemotion2rt.o
 OBJS-$(CONFIG_TRUESPEECH_DECODER)      += truespeech.o
 OBJS-$(CONFIG_TSCC_DECODER)            += tscc.o msrledec.o
 OBJS-$(CONFIG_TSCC2_DECODER)           += tscc2.o
index bb90627..6fa1617 100644 (file)
@@ -265,6 +265,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(TMV,               tmv);
     REGISTER_DECODER(TRUEMOTION1,       truemotion1);
     REGISTER_DECODER(TRUEMOTION2,       truemotion2);
+    REGISTER_DECODER(TRUEMOTION2RT,     truemotion2rt);
     REGISTER_DECODER(TSCC,              tscc);
     REGISTER_DECODER(TSCC2,             tscc2);
     REGISTER_DECODER(TXD,               txd);
index 623d743..c4bf708 100644 (file)
@@ -390,6 +390,7 @@ enum AVCodecID {
     AV_CODEC_ID_SCREENPRESSO,
     AV_CODEC_ID_RSCC,
     AV_CODEC_ID_MAGICYUV,
+    AV_CODEC_ID_TRUEMOTION2RT,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
index d390e72..78d2cbc 100644 (file)
@@ -1198,6 +1198,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("MagicYUV video"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_TRUEMOTION2RT,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "truemotion2rt",
+        .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0 Real Time"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     /* image codecs */
     {
diff --git a/libavcodec/truemotion2rt.c b/libavcodec/truemotion2rt.c
new file mode 100644 (file)
index 0000000..4d398fb
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Duck TrueMotion 2.0 Real Time decoder
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libavutil/imgutils.h"
+#include "libavutil/internal.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+
+#define BITSTREAM_READER_LE
+#include "avcodec.h"
+#include "get_bits.h"
+#include "internal.h"
+
+typedef struct TrueMotion2RTContext {
+    GetBitContext gb;
+    int delta_size;
+    int hscale;
+} TrueMotion2RTContext;
+
+static const int16_t delta_tab2[] = {
+    5, -7, 36, -36,
+};
+
+static const int16_t delta_tab3[] = {
+    2, -3, 8, -8, 18, -18, 36, -36,
+};
+
+static const int16_t delta_tab4[] = {
+    1, -1, 2, -3, 8, -8, 18, -18, 36, -36, 54, -54, 96, -96, 144, -144,
+};
+
+static const int16_t *const delta_tabs[] = {
+    delta_tab2, delta_tab3, delta_tab4,
+};
+
+/* Returns the number of bytes consumed from the bytestream, or
+ * AVERROR_INVALIDDATA if there was an error while decoding the header. */
+static int truemotion2rt_decode_header(AVCodecContext *avctx, AVPacket *avpkt)
+{
+    TrueMotion2RTContext *s = avctx->priv_data;
+    int header_size;
+    uint8_t header_buffer[128] = { 0 };  /* logical maximum header size */
+    const uint8_t *buf = avpkt->data;
+    int size = avpkt->size;
+    int i;
+
+    if (size < 1) {
+        av_log(avctx, AV_LOG_ERROR, "input packet too small (%d)\n", size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    header_size = ((buf[0] >> 5) | (buf[0] << 3)) & 0x7f;
+    if (header_size < 10) {
+        av_log(avctx, AV_LOG_ERROR, "invalid header size (%d)\n", header_size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (header_size + 1 > size) {
+        av_log(avctx, AV_LOG_ERROR, "input packet too small (%d)\n", size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    /* unscramble the header bytes with a XOR operation */
+    for (i = 1; i < header_size; i++)
+        header_buffer[i - 1] = buf[i] ^ buf[i + 1];
+
+    s->delta_size = header_buffer[1];
+    s->hscale = 1 + !!header_buffer[3];
+    if (s->delta_size < 2 || s->delta_size > 4)
+        return AVERROR_INVALIDDATA;
+
+    avctx->height = AV_RL16(header_buffer + 5);
+    avctx->width  = AV_RL16(header_buffer + 7);
+
+    av_log(avctx, AV_LOG_DEBUG, "Header size: %d\n", header_size);
+    return header_size;
+}
+
+static int truemotion2rt_decode_frame(AVCodecContext *avctx, void *data,
+                                      int *got_frame, AVPacket *avpkt)
+{
+    TrueMotion2RTContext *s = avctx->priv_data;
+    AVFrame * const p = data;
+    GetBitContext *gb = &s->gb;
+    uint8_t *dst;
+    int x, y, delta_mode;
+    int ret;
+
+    ret = truemotion2rt_decode_header(avctx, avpkt);
+    if (ret < 0)
+        return ret;
+
+    ret = init_get_bits8(gb, avpkt->data + ret, avpkt->size - ret);
+    if (ret < 0)
+        return ret;
+
+    ret = ff_get_buffer(avctx, p, 0);
+    if (ret < 0)
+        return ret;
+
+    skip_bits(gb, 32);
+    delta_mode = s->delta_size - 2;
+    dst = p->data[0];
+    for (y = 0; y < avctx->height; y++) {
+        int diff = 0;
+        for (x = 0; x < avctx->width; x += s->hscale) {
+            diff  += delta_tabs[delta_mode][get_bits(gb, s->delta_size)];
+            dst[x] = av_clip_uint8((y ? dst[x - p->linesize[0]] : 0) + diff);
+        }
+        dst += p->linesize[0];
+    }
+
+    if (s->hscale > 1) {
+        dst = p->data[0];
+        for (y = 0; y < avctx->height; y++) {
+            for (x = 1; x < avctx->width; x += s->hscale)
+                dst[x] = dst[x - 1];
+            dst += p->linesize[0];
+        }
+    }
+
+    dst = p->data[0];
+    for (y = 0; y < avctx->height; y++) {
+        for (x = 0; x < avctx->width; x++)
+            dst[x] = av_clip_uint8(dst[x] + (dst[x] - 128) / 3);
+        dst += p->linesize[0];
+    }
+
+    dst = p->data[1];
+    for (y = 0; y < avctx->height >> 2; y++) {
+        int diff = 0;
+        for (x = 0; x < avctx->width >> 2; x += s->hscale) {
+            diff  += delta_tabs[delta_mode][get_bits(gb, s->delta_size)];
+            dst[x] = av_clip_uint8((y ? dst[x - p->linesize[1]] : 128) + diff);
+        }
+        dst += p->linesize[1];
+    }
+
+    if (s->hscale > 1) {
+        dst = p->data[1];
+        for (y = 0; y < avctx->height >> 2; y++) {
+            for (x = 1; x < avctx->width >> 2; x += s->hscale)
+                dst[x] = dst[x - 1];
+            dst += p->linesize[1];
+        }
+    }
+
+    dst = p->data[1];
+    for (y = 0; y < avctx->height >> 2; y++) {
+        for (x = 0; x < avctx->width >> 2; x++)
+            dst[x] += (dst[x] - 128) / 8;
+        dst += p->linesize[1];
+    }
+
+    dst = p->data[2];
+    for (y = 0; y < avctx->height >> 2; y++) {
+        int diff = 0;
+        for (x = 0; x < avctx->width >> 2; x += s->hscale) {
+            diff  += delta_tabs[delta_mode][get_bits(gb, s->delta_size)];
+            dst[x] = av_clip_uint8((y ? dst[x - p->linesize[2]] : 128) + diff);
+        }
+        dst += p->linesize[2];
+    }
+
+    if (s->hscale > 1) {
+        dst = p->data[2];
+        for (y = 0; y < avctx->height >> 2; y++) {
+            for (x = 1; x < avctx->width >> 2; x += s->hscale)
+                dst[x] = dst[x - 1];
+            dst += p->linesize[2];
+        }
+    }
+
+    dst = p->data[2];
+    for (y = 0; y < avctx->height >> 2; y++) {
+        for (x = 0; x < avctx->width >> 2; x++)
+            dst[x] += (dst[x] - 128) / 8;
+        dst += p->linesize[2];
+    }
+
+    p->pict_type = AV_PICTURE_TYPE_I;
+    p->key_frame = 1;
+    *got_frame = 1;
+
+    return avpkt->size;
+}
+
+static av_cold int truemotion2rt_decode_init(AVCodecContext *avctx)
+{
+    avctx->pix_fmt = AV_PIX_FMT_YUV410P;
+    return 0;
+}
+
+AVCodec ff_truemotion2rt_decoder = {
+    .name           = "truemotion2rt",
+    .long_name      = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0 Real Time"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_TRUEMOTION2RT,
+    .priv_data_size = sizeof(TrueMotion2RTContext),
+    .init           = truemotion2rt_decode_init,
+    .decode         = truemotion2rt_decode_frame,
+    .capabilities   = AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
+};
index e5a83e0..4f6e058 100644 (file)
@@ -28,7 +28,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 21
+#define LIBAVCODEC_VERSION_MINOR 22
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
index b1b51e2..1e1e4d8 100644 (file)
@@ -309,6 +309,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
     { AV_CODEC_ID_FRAPS,        MKTAG('F', 'P', 'S', '1') },
     { AV_CODEC_ID_THEORA,       MKTAG('t', 'h', 'e', 'o') },
     { AV_CODEC_ID_TRUEMOTION2,  MKTAG('T', 'M', '2', '0') },
+    { AV_CODEC_ID_TRUEMOTION2RT,MKTAG('T', 'R', '2', '0') },
     { AV_CODEC_ID_CSCD,         MKTAG('C', 'S', 'C', 'D') },
     { AV_CODEC_ID_ZMBV,         MKTAG('Z', 'M', 'B', 'V') },
     { AV_CODEC_ID_KMVC,         MKTAG('K', 'M', 'V', 'C') },