]> git.sesse.net Git - ffmpeg/commitdiff
avcodec: add Newtek SpeedHQ decoder
authorSteinar H. Gunderson <steinar+ffmpeg@gunderson.no>
Sun, 8 Jan 2017 11:07:09 +0000 (12:07 +0100)
committerPaul B Mahol <onemda@gmail.com>
Wed, 11 Jan 2017 15:02:10 +0000 (16:02 +0100)
This decoder can decode all existing SpeedHQ formats (SHQ0–5, 7, and 9),
including correct decoding of the alpha channel.

1080p is decoded in 142 fps on one core of my i7-4600U (2.1 GHz Haswell),
about evenly split between bitstream reader and IDCT. There is currently
no attempt at slice or frame threading, even though the format trivially
supports both.

NewTek very helpfully provided a full set of SHQ samples, as well as
source code for an SHQ2 encoder (not included) and assistance with
understanding some details of the format.

12 files changed:
Changelog
libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/avcodec.h
libavcodec/codec_desc.c
libavcodec/get_bits.h
libavcodec/mpeg12.c
libavcodec/mpeg12.h
libavcodec/speedhq.c [new file with mode: 0644]
libavcodec/version.h
libavcodec/vlc.h
libavformat/riff.c

index e09bf209499b57c7069fb28f7607a8a950b40d70..e15d8e2acfb4e1a648f5b559d5d2e809cbe561d5 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -13,6 +13,7 @@ version <next>:
 - 24.0 floating point pcm decoder
 - Apple Pixlet decoder
 - QDMC audio decoder
+- NewTek SpeedHQ decoder
 
 version 3.2:
 - libopenmpt demuxer
index 44e416e6cd9effa58bd396407700c3d33678eae7..78640792710ff6e43fe9877204336dcdfbeed737 100644 (file)
@@ -521,6 +521,7 @@ OBJS-$(CONFIG_SOL_DPCM_DECODER)        += dpcm.o
 OBJS-$(CONFIG_SONIC_DECODER)           += sonic.o
 OBJS-$(CONFIG_SONIC_ENCODER)           += sonic.o
 OBJS-$(CONFIG_SONIC_LS_ENCODER)        += sonic.o
+OBJS-$(CONFIG_SPEEDHQ_DECODER)         += speedhq.o simple_idct.o
 OBJS-$(CONFIG_SP5X_DECODER)            += sp5xdec.o
 OBJS-$(CONFIG_SRT_DECODER)             += srtdec.o ass.o htmlsubtitles.o
 OBJS-$(CONFIG_SRT_ENCODER)             += srtenc.o ass_split.o
index 4540ef79627708d0207f095f199edce616317690..22a93f305c785c2ce282099cf14fab8d177e4509 100644 (file)
@@ -316,6 +316,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(SMVJPEG,           smvjpeg);
     REGISTER_ENCDEC (SNOW,              snow);
     REGISTER_DECODER(SP5X,              sp5x);
+    REGISTER_DECODER(SPEEDHQ,           speedhq);
     REGISTER_ENCDEC (SUNRAST,           sunrast);
     REGISTER_ENCDEC (SVQ1,              svq1);
     REGISTER_DECODER(SVQ3,              svq3);
index ca8b786077efba0b32b8c47c4c40e808ab5f18cc..4d26d14ccc88810a8a3d3f2ad1a5d30f16eac71a 100644 (file)
@@ -413,6 +413,7 @@ enum AVCodecID {
     AV_CODEC_ID_YLC,
     AV_CODEC_ID_PSD,
     AV_CODEC_ID_PIXLET,
+    AV_CODEC_ID_SPEEDHQ,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
index e7ef368f49ef413cabaf42da94f03321865fa46f..09d3c4809e1873c4effd3f735468ff52bab92f47 100644 (file)
@@ -1290,6 +1290,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("Screenpresso"),
         .props     = AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_SPEEDHQ,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "speedhq",
+        .long_name = NULL_IF_CONFIG_SMALL("NewTek SpeedHQ"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
     {
         .id        = AV_CODEC_ID_WRAPPED_AVFRAME,
         .type      = AVMEDIA_TYPE_VIDEO,
index c094a14caaf59fc8941d3a1e092cfd4a8408b0ff..c530015169e1c8939265658ef5bf0694e3e45be4 100644 (file)
@@ -229,6 +229,20 @@ static inline int get_xbits(GetBitContext *s, int n)
     return (NEG_USR32(sign ^ cache, n) ^ sign) - sign;
 }
 
+static inline int get_xbits_le(GetBitContext *s, int n)
+{
+    register int sign;
+    register int32_t cache;
+    OPEN_READER(re, s);
+    av_assert2(n>0 && n<=25);
+    UPDATE_CACHE_LE(re, s);
+    cache = GET_CACHE(re, s);
+    sign  = sign_extend(~cache, n) >> 31;
+    LAST_SKIP_BITS(re, s, n);
+    CLOSE_READER(re, s);
+    return (zero_extend(sign ^ cache, n) ^ sign) - sign;
+}
+
 static inline int get_sbits(GetBitContext *s, int n)
 {
     register int tmp;
index a61d45b39a9f12f8d464061431bec8103668da48..ab6c19c6151590026dd625f90cd608f4d97b679d 100644 (file)
@@ -67,20 +67,13 @@ static const uint8_t table_mb_btype[11][2] = {
     { 2, 5 }, // 0x1E MB_QUANT|MB_FOR|MB_BACK|MB_PAT
 };
 
-#define INIT_2D_VLC_RL(rl, static_size)\
-{\
-    static RL_VLC_ELEM rl_vlc_table[static_size];\
-    rl.rl_vlc[0] = rl_vlc_table;\
-    init_2d_vlc_rl(&rl, static_size);\
-}
-
-static av_cold void init_2d_vlc_rl(RLTable *rl, unsigned static_size)
+av_cold void ff_init_2d_vlc_rl(RLTable *rl, unsigned static_size, int flags)
 {
     int i;
     VLC_TYPE table[680][2] = {{0}};
     VLC vlc = { .table = table, .table_allocated = static_size };
     av_assert0(static_size <= FF_ARRAY_ELEMS(table));
-    init_vlc(&vlc, TEX_VLC_BITS, rl->n + 2, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC);
+    init_vlc(&vlc, TEX_VLC_BITS, rl->n + 2, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC | flags);
 
     for (i = 0; i < vlc.table_size; i++) {
         int code = vlc.table[i][0];
@@ -173,8 +166,8 @@ av_cold void ff_mpeg12_init_vlcs(void)
         ff_rl_init(&ff_rl_mpeg1, ff_mpeg12_static_rl_table_store[0]);
         ff_rl_init(&ff_rl_mpeg2, ff_mpeg12_static_rl_table_store[1]);
 
-        INIT_2D_VLC_RL(ff_rl_mpeg1, 680);
-        INIT_2D_VLC_RL(ff_rl_mpeg2, 674);
+        INIT_2D_VLC_RL(ff_rl_mpeg1, 680, 0);
+        INIT_2D_VLC_RL(ff_rl_mpeg2, 674, 0);
     }
 }
 
index ad9b00c08baff9cb6670138da29e6b974e70d243..f551504b8cc749612a99af14e302a9b0268f4246 100644 (file)
@@ -29,6 +29,15 @@ extern uint8_t ff_mpeg12_static_rl_table_store[2][2][2*MAX_RUN + MAX_LEVEL + 3];
 
 void ff_mpeg12_common_init(MpegEncContext *s);
 
+#define INIT_2D_VLC_RL(rl, static_size, flags)\
+{\
+    static RL_VLC_ELEM rl_vlc_table[static_size];\
+    rl.rl_vlc[0] = rl_vlc_table;\
+    ff_init_2d_vlc_rl(&rl, static_size, flags);\
+}
+
+void ff_init_2d_vlc_rl(RLTable *rl, unsigned static_size, int flags);
+
 static inline int decode_dc(GetBitContext *gb, int component)
 {
     int code, diff;
diff --git a/libavcodec/speedhq.c b/libavcodec/speedhq.c
new file mode 100644 (file)
index 0000000..9c21c0b
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ * NewTek SpeedHQ codec
+ * Copyright 2017 Steinar H. Gunderson
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * NewTek SpeedHQ decoder.
+ */
+
+#define BITSTREAM_READER_LE
+
+#include "libavutil/attributes.h"
+
+#include "avcodec.h"
+#include "get_bits.h"
+#include "internal.h"
+#include "libavutil/thread.h"
+#include "mathops.h"
+#include "mpeg12.h"
+#include "mpeg12data.h"
+#include "mpeg12vlc.h"
+
+#define MAX_INDEX (64 - 1)
+
+/*
+ * 5 bits makes for very small tables, with no more than two lookups needed
+ * for the longest (10-bit) codes.
+ */
+#define ALPHA_VLC_BITS 5
+
+typedef struct SHQContext {
+    AVCodecContext *avctx;
+    BlockDSPContext bdsp;
+    IDCTDSPContext idsp;
+    ScanTable intra_scantable;
+    int quant_matrix[64];
+    enum { SHQ_SUBSAMPLING_420, SHQ_SUBSAMPLING_422, SHQ_SUBSAMPLING_444 }
+        subsampling;
+    enum { SHQ_NO_ALPHA, SHQ_RLE_ALPHA, SHQ_DCT_ALPHA } alpha_type;
+} SHQContext;
+
+
+/* AC codes: Very similar but not identical to MPEG-2. */
+static uint16_t speedhq_vlc[123][2] = {
+    {0x02, 2}, {0x06, 3}, {0x07, 4}, {0x1c, 5},
+    {0x1d, 5}, {0x05, 6}, {0x04, 6}, {0x7b, 7},
+    {0x7c, 7}, {0x23, 8}, {0x22, 8}, {0xfa, 8},
+    {0xfb, 8}, {0xfe, 8}, {0xff, 8}, {0x1f,14},
+    {0x1e,14}, {0x1d,14}, {0x1c,14}, {0x1b,14},
+    {0x1a,14}, {0x19,14}, {0x18,14}, {0x17,14},
+    {0x16,14}, {0x15,14}, {0x14,14}, {0x13,14},
+    {0x12,14}, {0x11,14}, {0x10,14}, {0x18,15},
+    {0x17,15}, {0x16,15}, {0x15,15}, {0x14,15},
+    {0x13,15}, {0x12,15}, {0x11,15}, {0x10,15},
+    {0x02, 3}, {0x06, 5}, {0x79, 7}, {0x27, 8},
+    {0x20, 8}, {0x16,13}, {0x15,13}, {0x1f,15},
+    {0x1e,15}, {0x1d,15}, {0x1c,15}, {0x1b,15},
+    {0x1a,15}, {0x19,15}, {0x13,16}, {0x12,16},
+    {0x11,16}, {0x10,16}, {0x18,13}, {0x17,13},
+    {0x05, 5}, {0x07, 7}, {0xfc, 8}, {0x0c,10},
+    {0x14,13}, {0x18,12}, {0x14,12}, {0x13,12},
+    {0x10,12}, {0x1a,13}, {0x19,13}, {0x07, 5},
+    {0x26, 8}, {0x1c,12}, {0x13,13}, {0x1b,12},
+    {0x06, 6}, {0xfd, 8}, {0x12,12}, {0x1d,12},
+    {0x07, 6}, {0x04, 9}, {0x12,13}, {0x06, 7},
+    {0x1e,12}, {0x14,16}, {0x04, 7}, {0x15,12},
+    {0x05, 7}, {0x11,12}, {0x78, 7}, {0x11,13},
+    {0x7a, 7}, {0x10,13}, {0x21, 8}, {0x1a,16},
+    {0x25, 8}, {0x19,16}, {0x24, 8}, {0x18,16},
+    {0x05, 9}, {0x17,16}, {0x07, 9}, {0x16,16},
+    {0x0d,10}, {0x15,16}, {0x1f,12}, {0x1a,12},
+    {0x19,12}, {0x17,12}, {0x16,12}, {0x1f,13},
+    {0x1e,13}, {0x1d,13}, {0x1c,13}, {0x1b,13},
+    {0x1f,16}, {0x1e,16}, {0x1d,16}, {0x1c,16},
+    {0x1b,16},
+    {0x01,6}, /* escape */
+    {0x06,4}, /* EOB */
+};
+
+static const uint8_t speedhq_level[121] = {
+     1,  2,  3,  4,  5,  6,  7,  8,
+     9, 10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32,
+    33, 34, 35, 36, 37, 38, 39, 40,
+     1,  2,  3,  4,  5,  6,  7,  8,
+     9, 10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20,  1,  2,  3,  4,
+     5,  6,  7,  8,  9, 10, 11,  1,
+     2,  3,  4,  5,  1,  2,  3,  4,
+     1,  2,  3,  1,  2,  3,  1,  2,
+     1,  2,  1,  2,  1,  2,  1,  2,
+     1,  2,  1,  2,  1,  2,  1,  2,
+     1,  2,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,
+     1,
+};
+
+static const uint8_t speedhq_run[121] = {
+     0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,
+     1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  3,
+     3,  3,  3,  3,  4,  4,  4,  4,
+     5,  5,  5,  6,  6,  6,  7,  7,
+     8,  8,  9,  9, 10, 10, 11, 11,
+    12, 12, 13, 13, 14, 14, 15, 15,
+    16, 16, 17, 18, 19, 20, 21, 22,
+    23, 24, 25, 26, 27, 28, 29, 30,
+    31,
+};
+
+static RLTable ff_rl_speedhq = {
+    121,
+    121,
+    speedhq_vlc,
+    speedhq_run,
+    speedhq_level,
+};
+
+/* NOTE: The first element is always 16, unscaled. */
+static const uint8_t unscaled_quant_matrix[64] = {
+    16, 16, 19, 22, 26, 27, 29, 34,
+    16, 16, 22, 24, 27, 29, 34, 37,
+    19, 22, 26, 27, 29, 34, 34, 38,
+    22, 22, 26, 27, 29, 34, 37, 40,
+    22, 26, 27, 29, 32, 35, 40, 48,
+    26, 27, 29, 32, 35, 40, 48, 58,
+    26, 27, 29, 34, 38, 46, 56, 69,
+    27, 29, 35, 38, 46, 56, 69, 83
+};
+
+static uint8_t ff_speedhq_static_rl_table_store[2][2*MAX_RUN + MAX_LEVEL + 3];
+
+static VLC ff_dc_lum_vlc_le;
+static VLC ff_dc_chroma_vlc_le;
+static VLC ff_dc_alpha_run_vlc_le;
+static VLC ff_dc_alpha_level_vlc_le;
+
+static inline int decode_dc_le(GetBitContext *gb, int component)
+{
+    int code, diff;
+
+    if (component == 0 || component == 3) {
+        code = get_vlc2(gb, ff_dc_lum_vlc_le.table, DC_VLC_BITS, 2);
+    } else {
+        code = get_vlc2(gb, ff_dc_chroma_vlc_le.table, DC_VLC_BITS, 2);
+    }
+    if (code < 0) {
+        av_log(NULL, AV_LOG_ERROR, "invalid dc code at\n");
+        return 0xffff;
+    }
+    if (!code) {
+        diff = 0;
+    } else {
+        diff = get_xbits_le(gb, code);
+    }
+    return diff;
+}
+
+static inline int decode_alpha_block(const SHQContext *s, GetBitContext *gb, uint8_t last_alpha[16], uint8_t *dest, int linesize)
+{
+    uint8_t block[128];
+    int i = 0, x, y;
+
+    memset(block, 0, sizeof(block));
+
+    {
+        OPEN_READER(re, gb);
+
+        for ( ;; ) {
+            int run, level;
+
+            UPDATE_CACHE_LE(re, gb);
+            GET_VLC(run, re, gb, ff_dc_alpha_run_vlc_le.table, ALPHA_VLC_BITS, 2);
+
+            if (run == 128) break;
+            i += run;
+            if (i >= 128)
+                return AVERROR_INVALIDDATA;
+
+            UPDATE_CACHE_LE(re, gb);
+            GET_VLC(level, re, gb, ff_dc_alpha_level_vlc_le.table, ALPHA_VLC_BITS, 2);
+            block[i++] = level;
+        }
+
+        CLOSE_READER(re, gb);
+    }
+
+    for (y = 0; y < 8; y++) {
+        for (x = 0; x < 16; x++) {
+            last_alpha[x] -= block[y * 16 + x];
+        }
+        memcpy(dest, last_alpha, 16);
+        dest += linesize;
+    }
+
+    return 0;
+}
+
+static inline int decode_dct_block(const SHQContext *s, GetBitContext *gb, int last_dc[4], int component, uint8_t *dest, int linesize)
+{
+    const int *quant_matrix = s->quant_matrix;
+    const uint8_t *scantable = s->intra_scantable.permutated;
+    int16_t block[64];
+    int dc_offset;
+
+    s->bdsp.clear_block(block);
+
+    dc_offset = decode_dc_le(gb, component);
+    last_dc[component] -= dc_offset;  /* Note: Opposite of most codecs. */
+    block[scantable[0]] = last_dc[component];  /* quant_matrix[0] is always 16. */
+
+    /* Read AC coefficients. */
+    {
+        int i = 0;
+        OPEN_READER(re, gb);
+        for ( ;; ) {
+            int level, run;
+            UPDATE_CACHE_LE(re, gb);
+            GET_RL_VLC(level, run, re, gb, ff_rl_speedhq.rl_vlc[0],
+                       TEX_VLC_BITS, 2, 0);
+            if (level == 127) {
+                break;
+            } else if (level) {
+                i += run;
+                if (i > MAX_INDEX)
+                    return AVERROR_INVALIDDATA;
+                /* If next bit is 1, level = -level */
+                level = (level ^ SHOW_SBITS(re, gb, 1)) -
+                        SHOW_SBITS(re, gb, 1);
+                LAST_SKIP_BITS(re, gb, 1);
+            } else {
+                /* Escape. */
+#if MIN_CACHE_BITS < 6 + 6 + 12
+#error MIN_CACHE_BITS is too small for the escape code, add UPDATE_CACHE
+#endif
+                run = SHOW_UBITS(re, gb, 6) + 1;
+                SKIP_BITS(re, gb, 6);
+                level = SHOW_UBITS(re, gb, 12) - 2048;
+                LAST_SKIP_BITS(re, gb, 12);
+
+                i += run;
+                if (i > MAX_INDEX)
+                    return AVERROR_INVALIDDATA;
+            }
+
+            block[scantable[i]] = (level * quant_matrix[i]) >> 4;
+        }
+        CLOSE_READER(re, gb);
+    }
+
+    s->idsp.idct_put(dest, linesize, block);
+
+    return 0;
+}
+
+static int decode_speedhq_field(const SHQContext *s, const uint8_t *buf, int buf_size, AVFrame *frame, int field_number, int start, int end, int line_stride)
+{
+    int ret, slice_number, slice_offsets[5];
+    int linesize_y  = frame->linesize[0] * line_stride;
+    int linesize_cb = frame->linesize[1] * line_stride;
+    int linesize_cr = frame->linesize[2] * line_stride;
+    int linesize_a;
+
+    if (s->alpha_type != SHQ_NO_ALPHA)
+        linesize_a = frame->linesize[3] * line_stride;
+
+    if (end < start || end - start < 3 || end > buf_size)
+        return AVERROR_INVALIDDATA;
+
+    slice_offsets[0] = start;
+    slice_offsets[4] = end;
+    for (slice_number = 1; slice_number < 4; slice_number++) {
+        uint32_t last_offset, slice_len;
+
+        last_offset = slice_offsets[slice_number - 1];
+        slice_len = AV_RL24(buf + last_offset);
+        slice_offsets[slice_number] = last_offset + slice_len;
+
+        if (slice_len < 3 || slice_offsets[slice_number] > end - 3)
+            return AVERROR_INVALIDDATA;
+    }
+
+    for (slice_number = 0; slice_number < 4; slice_number++) {
+        GetBitContext gb;
+        uint32_t slice_begin, slice_end;
+        int x, y;
+
+        slice_begin = slice_offsets[slice_number];
+        slice_end = slice_offsets[slice_number + 1];
+
+        if ((ret = init_get_bits8(&gb, buf + slice_begin + 3, slice_end - slice_begin - 3)) < 0)
+            return ret;
+
+        for (y = slice_number * 16 * line_stride; y < frame->height; y += line_stride * 64) {
+            uint8_t *dest_y, *dest_cb, *dest_cr, *dest_a;
+            int last_dc[4] = { 1024, 1024, 1024, 1024 };
+            uint8_t last_alpha[16];
+
+            memset(last_alpha, 255, sizeof(last_alpha));
+
+            dest_y = frame->data[0] + frame->linesize[0] * (y + field_number);
+            if (s->subsampling == SHQ_SUBSAMPLING_420) {
+                dest_cb = frame->data[1] + frame->linesize[1] * (y/2 + field_number);
+                dest_cr = frame->data[2] + frame->linesize[2] * (y/2 + field_number);
+            } else {
+                dest_cb = frame->data[1] + frame->linesize[1] * (y + field_number);
+                dest_cr = frame->data[2] + frame->linesize[2] * (y + field_number);
+            }
+            if (s->alpha_type != SHQ_NO_ALPHA) {
+                dest_a = frame->data[3] + frame->linesize[3] * (y + field_number);
+            }
+
+            for (x = 0; x < frame->width; x += 16) {
+                /* Decode the four luma blocks. */
+                if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y, linesize_y)) < 0)
+                    return ret;
+                if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8, linesize_y)) < 0)
+                    return ret;
+                if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8 * linesize_y, linesize_y)) < 0)
+                    return ret;
+                if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8 * linesize_y + 8, linesize_y)) < 0)
+                    return ret;
+
+                /*
+                 * Decode the first chroma block. For 4:2:0, this is the only one;
+                 * for 4:2:2, it's the top block; for 4:4:4, it's the top-left block.
+                 */
+                if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb, linesize_cb)) < 0)
+                    return ret;
+                if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr, linesize_cr)) < 0)
+                    return ret;
+
+                if (s->subsampling != SHQ_SUBSAMPLING_420) {
+                    /* For 4:2:2, this is the bottom block; for 4:4:4, it's the bottom-left block. */
+                    if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8 * linesize_cb, linesize_cb)) < 0)
+                        return ret;
+                    if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8 * linesize_cr, linesize_cr)) < 0)
+                        return ret;
+
+                    if (s->subsampling == SHQ_SUBSAMPLING_444) {
+                        /* Top-right and bottom-right blocks. */
+                        if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8, linesize_cb)) < 0)
+                            return ret;
+                        if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8, linesize_cr)) < 0)
+                            return ret;
+                        if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8 * linesize_cb + 8, linesize_cb)) < 0)
+                            return ret;
+                        if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8 * linesize_cr + 8, linesize_cr)) < 0)
+                            return ret;
+
+                        dest_cb += 8;
+                        dest_cr += 8;
+                    }
+                }
+                dest_y += 16;
+                dest_cb += 8;
+                dest_cr += 8;
+
+                if (s->alpha_type == SHQ_RLE_ALPHA) {
+                    /* Alpha coded using 16x8 RLE blocks. */
+                    if ((ret = decode_alpha_block(s, &gb, last_alpha, dest_a, linesize_a)) < 0)
+                        return ret;
+                    if ((ret = decode_alpha_block(s, &gb, last_alpha, dest_a + 8 * linesize_a, linesize_a)) < 0)
+                        return ret;
+                    dest_a += 16;
+                } else if (s->alpha_type == SHQ_DCT_ALPHA) {
+                    /* Alpha encoded exactly like luma. */
+                    if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a, linesize_a)) < 0)
+                        return ret;
+                    if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8, linesize_a)) < 0)
+                        return ret;
+                    if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8 * linesize_a, linesize_a)) < 0)
+                        return ret;
+                    if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8 * linesize_a + 8, linesize_a)) < 0)
+                        return ret;
+                    dest_a += 16;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+static void compute_quant_matrix(int *output, int qscale)
+{
+    int i;
+    for (i = 0; i < 64; i++) output[i] = unscaled_quant_matrix[i] * qscale;
+}
+
+static int speedhq_decode_frame(AVCodecContext *avctx,
+                                void *data, int *got_frame,
+                                AVPacket *avpkt)
+{
+    SHQContext * const s = avctx->priv_data;
+    const uint8_t *buf   = avpkt->data;
+    int buf_size         = avpkt->size;
+    AVFrame *frame       = data;
+    uint8_t quality;
+    uint32_t second_field_offset;
+    int ret;
+
+    if (buf_size < 4)
+        return AVERROR_INVALIDDATA;
+
+    quality = buf[0];
+    if (quality >= 100) {
+        return AVERROR_INVALIDDATA;
+    }
+
+    compute_quant_matrix(s->quant_matrix, 100 - quality);
+
+    second_field_offset = AV_RL24(buf + 1);
+    if (second_field_offset >= buf_size - 3) {
+        return AVERROR_INVALIDDATA;
+    }
+
+    avctx->coded_width = FFALIGN(avctx->width, 16);
+    avctx->coded_height = FFALIGN(avctx->height, 16);
+
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+        return ret;
+    }
+    frame->key_frame = 1;
+
+    if (second_field_offset == 4) {
+        /*
+         * Overlapping first and second fields is used to signal
+         * encoding only a single field (the second field then comes
+         * as a separate, later frame).
+         */
+        frame->height >>= 1;
+        if ((ret = decode_speedhq_field(s, buf, buf_size, frame, 0, 4, buf_size, 1)) < 0)
+            return ret;
+    } else {
+        if ((ret = decode_speedhq_field(s, buf, buf_size, frame, 0, 4, second_field_offset, 2)) < 0)
+            return ret;
+        if ((ret = decode_speedhq_field(s, buf, buf_size, frame, 1, second_field_offset, buf_size, 2)) < 0)
+            return ret;
+    }
+
+    *got_frame = 1;
+    return buf_size;
+}
+
+/*
+ * Alpha VLC. Run and level are independently coded, and would be
+ * outside the default limits for MAX_RUN/MAX_LEVEL, so we don't
+ * bother with combining them into one table.
+ */
+static av_cold void compute_alpha_vlcs(void)
+{
+    uint16_t run_code[129], level_code[256];
+    uint8_t run_bits[129], level_bits[256];
+    int run, level;
+
+    for (run = 0; run < 128; run++) {
+        if (!run) {
+            /* 0 -> 0. */
+            run_code[run] = 0;
+            run_bits[run] = 1;
+        } else if (run <= 4) {
+            /* 10xx -> xx plus 1. */
+            run_code[run] = ((run - 1) << 2) | 1;
+            run_bits[run] = 4;
+        } else {
+            /* 111xxxxxxx -> xxxxxxxx. */
+            run_code[run] = (run << 3) | 7;
+            run_bits[run] = 10;
+        }
+    }
+
+    /* 110 -> EOB. */
+    run_code[128] = 3;
+    run_bits[128] = 3;
+
+    INIT_LE_VLC_STATIC(&ff_dc_alpha_run_vlc_le, ALPHA_VLC_BITS, 129,
+                       run_bits, 1, 1,
+                       run_code, 2, 2, 160);
+
+    for (level = 0; level < 256; level++) {
+        int8_t signed_level = (int8_t)level;
+        int abs_signed_level = abs(signed_level);
+        int sign = (signed_level < 0) ? 1 : 0;
+
+        if (abs_signed_level == 1) {
+            /* 1s -> -1 or +1 (depending on sign bit). */
+            level_code[level] = (sign << 1) | 1;
+            level_bits[level] = 2;
+        } else if (abs_signed_level >= 2 && abs_signed_level <= 5) {
+            /* 01sxx -> xx plus 2 (2..5 or -2..-5, depending on sign bit). */
+            level_code[level] = ((abs_signed_level - 2) << 3) | (sign << 2) | 2;
+            level_bits[level] = 5;
+        } else {
+            /*
+             * 00xxxxxxxx -> xxxxxxxx, in two's complement. 0 is technically an
+             * illegal code (that would be encoded by increasing run), but it
+             * doesn't hurt and simplifies indexing.
+             */
+            level_code[level] = level << 2;
+            level_bits[level] = 10;
+        }
+    }
+
+    INIT_LE_VLC_STATIC(&ff_dc_alpha_level_vlc_le, ALPHA_VLC_BITS, 256,
+                       level_bits, 1, 1,
+                       level_code, 2, 2, 288);
+}
+
+static uint32_t reverse(uint32_t num, int bits)
+{
+    return bitswap_32(num) >> (32 - bits);
+}
+
+static void reverse_code(const uint16_t *code, const uint8_t *bits,
+                         uint16_t *reversed_code, int num_entries)
+{
+    int i;
+    for (i = 0; i < num_entries; i++) {
+        reversed_code[i] = reverse(code[i], bits[i]);
+    }
+}
+
+static av_cold void speedhq_static_init(void)
+{
+    uint16_t ff_mpeg12_vlc_dc_lum_code_reversed[12];
+    uint16_t ff_mpeg12_vlc_dc_chroma_code_reversed[12];
+    int i;
+
+    /* Exactly the same as MPEG-2, except little-endian. */
+    reverse_code(ff_mpeg12_vlc_dc_lum_code,
+                 ff_mpeg12_vlc_dc_lum_bits,
+                 ff_mpeg12_vlc_dc_lum_code_reversed,
+                 12);
+    INIT_LE_VLC_STATIC(&ff_dc_lum_vlc_le, DC_VLC_BITS, 12,
+                       ff_mpeg12_vlc_dc_lum_bits, 1, 1,
+                       ff_mpeg12_vlc_dc_lum_code_reversed, 2, 2, 512);
+    reverse_code(ff_mpeg12_vlc_dc_chroma_code,
+                 ff_mpeg12_vlc_dc_chroma_bits,
+                 ff_mpeg12_vlc_dc_chroma_code_reversed,
+                 12);
+    INIT_LE_VLC_STATIC(&ff_dc_chroma_vlc_le, DC_VLC_BITS, 12,
+                       ff_mpeg12_vlc_dc_chroma_bits, 1, 1,
+                       ff_mpeg12_vlc_dc_chroma_code_reversed, 2, 2, 514);
+
+    /* Reverse the AC VLC, because INIT_VLC_LE wants it in that order. */
+    for (i = 0; i < FF_ARRAY_ELEMS(speedhq_vlc); ++i) {
+        speedhq_vlc[i][0] = reverse(speedhq_vlc[i][0], speedhq_vlc[i][1]);
+    }
+    ff_rl_init(&ff_rl_speedhq, ff_speedhq_static_rl_table_store);
+    INIT_2D_VLC_RL(ff_rl_speedhq, 674, INIT_VLC_LE);
+
+    compute_alpha_vlcs();
+}
+
+static av_cold int speedhq_decode_init(AVCodecContext *avctx)
+{
+    int ret;
+    static AVOnce init_once = AV_ONCE_INIT;
+    SHQContext * const s = avctx->priv_data;
+
+    s->avctx = avctx;
+
+    ret = ff_thread_once(&init_once, speedhq_static_init);
+    if (ret)
+        return AVERROR_UNKNOWN;
+
+    ff_blockdsp_init(&s->bdsp, avctx);
+    ff_idctdsp_init(&s->idsp, avctx);
+    ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct);
+
+    switch (avctx->codec_tag) {
+    case MKTAG('S', 'H', 'Q', '0'):
+        s->subsampling = SHQ_SUBSAMPLING_420;
+        s->alpha_type = SHQ_NO_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+        break;
+    case MKTAG('S', 'H', 'Q', '1'):
+        s->subsampling = SHQ_SUBSAMPLING_420;
+        s->alpha_type = SHQ_RLE_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
+        break;
+    case MKTAG('S', 'H', 'Q', '2'):
+        s->subsampling = SHQ_SUBSAMPLING_422;
+        s->alpha_type = SHQ_NO_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+        break;
+    case MKTAG('S', 'H', 'Q', '3'):
+        s->subsampling = SHQ_SUBSAMPLING_422;
+        s->alpha_type = SHQ_RLE_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUVA422P;
+        break;
+    case MKTAG('S', 'H', 'Q', '4'):
+        s->subsampling = SHQ_SUBSAMPLING_444;
+        s->alpha_type = SHQ_NO_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+        break;
+    case MKTAG('S', 'H', 'Q', '5'):
+        s->subsampling = SHQ_SUBSAMPLING_444;
+        s->alpha_type = SHQ_RLE_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
+        break;
+    case MKTAG('S', 'H', 'Q', '7'):
+        s->subsampling = SHQ_SUBSAMPLING_422;
+        s->alpha_type = SHQ_DCT_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUVA422P;
+        break;
+    case MKTAG('S', 'H', 'Q', '9'):
+        s->subsampling = SHQ_SUBSAMPLING_444;
+        s->alpha_type = SHQ_DCT_ALPHA;
+        avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
+        break;
+    default:
+        av_log(avctx, AV_LOG_ERROR, "Unknown NewTek SpeedHQ FOURCC provided (%08X)\n",
+               avctx->codec_tag);
+        return AVERROR_INVALIDDATA;
+    }
+
+    /* This matches what NDI's RGB -> Y'CbCr 4:2:2 converter uses. */
+    avctx->colorspace = AVCOL_SPC_BT470BG;
+    avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
+
+    return 0;
+}
+
+AVCodec ff_speedhq_decoder = {
+    .name           = "speedhq",
+    .long_name      = NULL_IF_CONFIG_SMALL("NewTek SpeedHQ"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_SPEEDHQ,
+    .priv_data_size = sizeof(SHQContext),
+    .init           = speedhq_decode_init,
+    .decode         = speedhq_decode_frame,
+    .capabilities   = AV_CODEC_CAP_DR1,
+};
index 7f1b0a4638fb33aa9d1eee8f6700e613db2aba7a..6b3e62e17fa97602a5657e8f50de562f24afc499 100644 (file)
@@ -28,8 +28,8 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  57
-#define LIBAVCODEC_VERSION_MINOR  71
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR  72
+#define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \
index 9e38f8c6b21a73de2f9832579312d7ea34233015..40096d89448f5067b579d128d6a8c35a34c4645a 100644 (file)
@@ -62,4 +62,13 @@ void ff_free_vlc(VLC *vlc);
         init_vlc(vlc, bits, a, b, c, d, e, f, g, INIT_VLC_USE_NEW_STATIC); \
     } while (0)
 
+#define INIT_LE_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, static_size)    \
+    do {                                                                   \
+        static VLC_TYPE table[static_size][2];                             \
+        (vlc)->table           = table;                                    \
+        (vlc)->table_allocated = static_size;                              \
+        init_vlc(vlc, bits, a, b, c, d, e, f, g,                           \
+            INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);                        \
+    } while (0)
+
 #endif /* AVCODEC_VLC_H */
index cd2143c8762bbc40e9f09332410a0da2e9b22e7f..d44b908f8be24ab28ae0f045d10126854c747870 100644 (file)
@@ -440,6 +440,14 @@ const AVCodecTag ff_codec_bmp_tags[] = {
     { AV_CODEC_ID_MAGICYUV,     MKTAG('M', '0', 'G', '0') },
     { AV_CODEC_ID_MAGICYUV,     MKTAG('M', '0', 'Y', '2') },
     { AV_CODEC_ID_YLC,          MKTAG('Y', 'L', 'C', '0') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '0') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '1') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '2') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '3') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '4') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '5') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '7') },
+    { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '9') },
 
     { AV_CODEC_ID_NONE,         0 }
 };