[FFmpeg-devel] [WIP][RFC][PATCH] avcodec: add BRAW video decoder
Paul B Mahol
onemda at gmail.com
Sat Dec 14 13:57:05 EET 2019
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
Does not use optimized 8x8 idct as its buggy and give errors around high contrast borders.
Sending to receive general feedback and useful comments.
Still probabbly missing additional post processing.
---
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/avcodec.h | 1 +
libavcodec/braw.c | 576 +++++++++++++++++++++++++++++++++++++++
libavcodec/codec_desc.c | 7 +
libavcodec/simple_idct.c | 41 +++
libavcodec/simple_idct.h | 2 +
libavformat/isom.c | 7 +
8 files changed, 636 insertions(+)
create mode 100644 libavcodec/braw.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index c1f35b40d8..81ba7e7380 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -238,6 +238,7 @@ OBJS-$(CONFIG_BMP_DECODER) += bmp.o msrledec.o
OBJS-$(CONFIG_BMP_ENCODER) += bmpenc.o
OBJS-$(CONFIG_BMV_AUDIO_DECODER) += bmvaudio.o
OBJS-$(CONFIG_BMV_VIDEO_DECODER) += bmvvideo.o
+OBJS-$(CONFIG_BRAW_DECODER) += braw.o
OBJS-$(CONFIG_BRENDER_PIX_DECODER) += brenderpix.o
OBJS-$(CONFIG_C93_DECODER) += c93.o
OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index c33edf23c9..a3e9d0b4ad 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -64,6 +64,7 @@ extern AVCodec ff_bitpacked_decoder;
extern AVCodec ff_bmp_encoder;
extern AVCodec ff_bmp_decoder;
extern AVCodec ff_bmv_video_decoder;
+extern AVCodec ff_braw_decoder;
extern AVCodec ff_brender_pix_decoder;
extern AVCodec ff_c93_decoder;
extern AVCodec ff_cavs_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 119b32dc1f..b6d1cc4a3a 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -460,6 +460,7 @@ enum AVCodecID {
AV_CODEC_ID_IMM5,
AV_CODEC_ID_MVDV,
AV_CODEC_ID_MVHA,
+ AV_CODEC_ID_BRAW,
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/braw.c b/libavcodec/braw.c
new file mode 100644
index 0000000000..4ed4a4ef15
--- /dev/null
+++ b/libavcodec/braw.c
@@ -0,0 +1,576 @@
+/*
+ * Blackmagic RAW codec
+ *
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/thread.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "get_bits.h"
+#include "idctdsp.h"
+#include "internal.h"
+#include "simple_idct.h"
+#include "thread.h"
+
+static const uint8_t half_scan[] =
+{
+ 0, 1, 2, 3, 8, 9, 16, 17, 10, 11, 4, 5, 6, 7, 12, 13, 18,
+ 19, 24, 25, 26, 27, 20, 21, 14,15, 22, 23, 28, 29, 30, 31,
+};
+
+static const int16_t dcval_tab[2][16] = {
+ { -1, -3, -7, -15,
+ -31, -63, -127, -255,
+ -511, -1023, -2047, -4095,
+ -8191, -16383, -32767, 0 },
+ { 1, 2, 4, 8,
+ 16, 32, 64, 128,
+ 256, 512, 1024, 2048,
+ 4096, 8192, 16384, 0 },
+};
+
+static const uint8_t dc_bits[16] =
+{
+ 2, 3, 3, 3, 3, 3, 5, 5, 6, 12, 12, 12, 12, 5, 12, 13,
+};
+
+static const uint16_t dc_codes[16] =
+{
+ 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x1C, 0x1D, 0x3E, 0xFF4, 0xFF5, 0xFF7, 0xFED, 0x1E, 0xFFE, 0x1FFE,
+};
+
+static const uint8_t dc_table[16][3] =
+{
+ { 0, 0, 15 }, { 0, 1, 0 }, { 1, 1, 1 }, { 2, 1, 2 },
+ { 3, 1, 3 }, { 4, 1, 4 }, { 5, 1, 5 }, { 6, 1, 6 },
+ { 7, 1, 7 }, { 8, 1, 8 }, { 9, 1, 9 }, { 10, 1, 10 },
+ { 11, 1, 11 }, { 12, 1, 12 }, { 13, 1, 13 }, { 14, 1, 14 },
+};
+
+static const uint8_t ac_bits[194] =
+{
+ 2, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10,
+ 10, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 15, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+};
+
+static const uint32_t ac_codes[194] =
+{
+ 0x000000, 0x000001, 0x000004, 0x00000B, 0x00000C, 0x00000A,
+ 0x00001A, 0x00001B, 0x00001C, 0x00003A, 0x00003B, 0x000078,
+ 0x000079, 0x00007A, 0x00007B, 0x0000F8, 0x0000F9, 0x0000FA,
+ 0x0001F6, 0x0001F7, 0x0001F8, 0x0001F9, 0x0001FA, 0x0003F6,
+ 0x0003F7, 0x0003F8, 0x0003F9, 0x0003FA, 0x0007F8, 0x0007F9,
+ 0x000FED, 0x000FF4, 0x000FF5, 0x000FF7, 0x000FEC, 0x000FF6,
+ 0x001FDC, 0x001FDD, 0x001FDE, 0x001FDF, 0x007FC0, 0x00FF84,
+ 0x00FF85, 0x00FF86, 0x00FF87, 0x00FF88, 0x00FF89, 0x00FF8A,
+ 0x00FF8B, 0x00FF8C, 0x00FF8D, 0x00FF8E, 0x00FF8F, 0x00FF90,
+ 0x00FF91, 0x00FF92, 0x00FF93, 0x00FF94, 0x00FF95, 0x00FF96,
+ 0x00FF97, 0x00FF98, 0x00FF99, 0x00FF9A, 0x00FF9B, 0x00FF9C,
+ 0x00FF9D, 0x00FF9E, 0x00FF9F, 0x00FFA0, 0x00FFA1, 0x00FFA2,
+ 0x00FFA3, 0x00FFA4, 0x00FFA5, 0x00FFA6, 0x00FFA7, 0x00FFA8,
+ 0x00FFA9, 0x00FFAA, 0x00FFAB, 0x00FFAC, 0x00FFAE, 0x00FFAF,
+ 0x00FFB0, 0x00FFB1, 0x00FFB2, 0x00FFB3, 0x00FFB4, 0x00FFB6,
+ 0x00FFB7, 0x00FFB8, 0x00FFB9, 0x00FFBA, 0x00FFBB, 0x00FFBC,
+ 0x00FFBE, 0x00FFBF, 0x00FFC0, 0x00FFC1, 0x00FFC2, 0x00FFC3,
+ 0x00FFC4, 0x00FFC5, 0x00FFC7, 0x00FFC8, 0x00FFC9, 0x00FFCA,
+ 0x00FFCB, 0x00FFCC, 0x00FFCD, 0x00FFCE, 0x00FFD0, 0x00FFD1,
+ 0x00FFD2, 0x00FFD3, 0x00FFD4, 0x00FFD5, 0x00FFD6, 0x00FFD7,
+ 0x00FFD9, 0x00FFDA, 0x00FFDB, 0x00FFDC, 0x00FFDD, 0x00FFDE,
+ 0x00FFDF, 0x00FFE0, 0x00FFE2, 0x00FFE3, 0x00FFE4, 0x00FFE5,
+ 0x00FFE6, 0x00FFE7, 0x00FFE8, 0x00FFE9, 0x00FFEB, 0x00FFEC,
+ 0x00FFED, 0x00FFEE, 0x00FFEF, 0x00FFF0, 0x00FFF1, 0x00FFF2,
+ 0x00FFF3, 0x00FFF5, 0x00FFF6, 0x00FFF7, 0x00FFF8, 0x00FFF9,
+ 0x00FFFA, 0x00FFFB, 0x00FFFC, 0x00FFFD, 0x03FEB5, 0x03FEB6,
+ 0x03FEB7, 0x03FED5, 0x03FED6, 0x03FED7, 0x03FEF5, 0x03FEF6,
+ 0x03FEF7, 0x03FF19, 0x03FEB4, 0x03FF1A, 0x03FF1B, 0x03FED4,
+ 0x03FF3D, 0x03FF3E, 0x03FEF4, 0x03FF3F, 0x03FF61, 0x03FF18,
+ 0x03FF62, 0x03FF63, 0x03FF3C, 0x03FF85, 0x03FF86, 0x03FF60,
+ 0x03FF87, 0x03FFA9, 0x03FF84, 0x03FFAA, 0x03FFAB, 0x03FFA8,
+ 0x03FFD1, 0x03FFD2, 0x03FFD0, 0x03FFD3, 0x03FFF9, 0x03FFF8,
+ 0x03FFFA, 0x03FFFB,
+};
+
+static const uint8_t ac_table[194][2] =
+{
+ { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 4 }, { 1, 1 }, { 255, 0 },
+ { 0, 5 }, { 1, 2 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 0, 6 },
+ { 1, 3 }, { 5, 1 }, { 6, 1 }, { 0, 7 }, { 2, 2 }, { 7, 1 },
+ { 1, 4 }, { 3, 2 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 0, 8 },
+ { 2, 3 }, { 4, 2 }, { 11, 1 }, { 12, 1 }, { 13, 1 }, { 15, 0 },
+ { 0, 12 },{ 0, 9 }, { 0, 10 }, { 0, 11 }, { 1, 5 }, { 6, 2 },
+ { 2, 4 }, { 3, 3 }, { 5, 2 }, { 7, 2 }, { 8, 2 }, { 1, 6 },
+ { 1, 7 }, { 1, 8 }, { 1, 9 }, { 1, 10 }, { 2, 5 }, { 2, 6 },
+ { 2, 7 }, { 2, 8 }, { 2, 9 }, { 2, 10 }, { 3, 4 }, { 3, 5 },
+ { 3, 6 }, { 3, 7 }, { 3, 8 }, { 3, 9 }, { 3, 10 }, { 4, 3 },
+ { 4, 4 }, { 4, 5 }, { 4, 6 }, { 4, 7 }, { 4, 8 }, { 4, 9 },
+ { 4, 10 }, { 5, 3 }, { 5, 4 }, { 5, 5 }, { 5, 6 }, { 5, 7 },
+ { 5, 8 }, { 5, 9 }, { 5, 10 }, { 6, 3 }, { 6, 4 }, { 6, 5 },
+ { 6, 6 }, { 6, 7 }, { 6, 8 }, { 6, 9 }, { 7, 3 }, { 7, 4 },
+ { 7, 5 }, { 7, 6 }, { 7, 7 }, { 7, 8 }, { 7, 9 }, { 8, 3 },
+ { 8, 4 }, { 8, 5 }, { 8, 6 }, { 8, 7 }, { 8, 8 }, { 8, 9 },
+ { 9, 2 }, { 9, 3 }, { 9, 4 }, { 9, 5 }, { 9, 6 }, { 9, 7 },
+ { 9, 8 }, { 9, 9 }, { 10, 2 }, { 10, 3 }, { 10, 4 }, { 10, 5 },
+ { 10, 6 }, { 10, 7 }, { 10, 8 }, { 10, 9 }, { 11, 2 }, { 11, 3 },
+ { 11, 4 }, { 11, 5 }, { 11, 6 }, { 11, 7 }, { 11, 8 }, { 11, 9 },
+ { 12, 2 }, { 12, 3 }, { 12, 4 }, { 12, 5 }, { 12, 6 }, { 12, 7 },
+ { 12, 8 }, { 12, 9 }, { 13, 2 }, { 13, 3 }, { 13, 4 }, { 13, 5 },
+ { 13, 6 }, { 13, 7 }, { 13, 8 }, { 13, 9 }, { 14, 1 }, { 14, 2 },
+ { 14, 3 }, { 14, 4 }, { 14, 5 }, { 14, 6 }, { 14, 7 }, { 14, 8 },
+ { 14, 9 }, { 15, 1 }, { 15, 2 }, { 15, 3 }, { 15, 4 }, { 15, 5 },
+ { 15, 6 }, { 15, 7 }, { 15, 8 }, { 15, 9 }, { 1, 11 }, { 1, 12 },
+ { 2, 11 }, { 2, 12 }, { 3, 11 }, { 3, 12 }, { 4, 11 }, { 4, 12 },
+ { 5, 11 }, { 5, 12 }, { 6, 10 }, { 6, 11 }, { 6, 12 }, { 7, 10 },
+ { 7, 11 }, { 7, 12 }, { 8, 10 }, { 8, 11 }, { 8, 12 }, { 9, 10 },
+ { 9, 11 }, { 9, 12 }, { 10, 10 }, { 10, 11 }, { 10, 12 }, { 11, 10 },
+ { 11, 11 }, { 11, 12 }, { 12, 10 }, { 12, 11 }, { 12, 12 }, { 13, 10 },
+ { 13, 11 }, { 13, 12 }, { 14, 10 }, { 14, 11 }, { 14, 12 }, { 15, 10 },
+ { 15, 11 }, { 15, 12 },
+};
+
+static VLC dc_vlc;
+static VLC ac_vlc;
+
+typedef struct BRAWContext {
+ const AVClass *class;
+
+ GetByteContext gb;
+ GetBitContext gbit;
+
+ uint32_t header_size;
+
+ int offsets[4][2];
+
+ int nb_tiles_w;
+ int nb_tiles_h;
+ int tile_size_w[256];
+ int tile_offset_w[257];
+ int tile_size_h;
+ int blocks_w_in_tile;
+ int blocks_h_in_tile;
+
+ int qscale[3];
+ int quant[2][64];
+
+ ScanTable scan;
+ IDCTDSPContext idsp;
+
+ DECLARE_ALIGNED(32, int16_t, block)[4][64];
+ DECLARE_ALIGNED(32, uint8_t, out)[2][64];
+} BRAWContext;
+
+static int parse_frame_metadata(AVCodecContext *avctx)
+{
+ BRAWContext *s = avctx->priv_data;
+ GetByteContext *gb = &s->gb;
+
+ s->header_size = bytestream2_get_be32(gb);
+ if (s->header_size <= 8 ||
+ s->header_size - 8 >= bytestream2_get_bytes_left(gb))
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_le32(gb) != MKTAG('b','m','d','f'))
+ return AVERROR_INVALIDDATA;
+ bytestream2_skip(gb, s->header_size - 8);
+
+ return 0;
+}
+
+static int decode_block(AVCodecContext *avctx,
+ int16_t *dst, const int *quant,
+ int *prev_dc, int max,
+ int mul, int add,
+ const uint8_t *scan)
+{
+ BRAWContext *s = avctx->priv_data;
+ GetBitContext *gbit = &s->gbit;
+ int dc_idx, sgnbit = 0, sign, len, val, code;
+
+ memset(dst, 0, 64 * 2);
+
+ dc_idx = get_vlc2(gbit, dc_vlc.table, dc_vlc.bits, 2);
+ if (dc_idx < 0)
+ return AVERROR_INVALIDDATA;
+
+ sign = dc_table[dc_idx][1];
+ sgnbit = get_bitsz(gbit, sign);
+ len = dc_table[dc_idx][0];
+ code = get_bitsz(gbit, len);
+ val = code + *prev_dc + dcval_tab[sgnbit][dc_table[dc_idx][2]];
+ *prev_dc = val;
+ dst[0] = FFMIN(((val * quant[0] + 0x8000) >> 16) + add, 32767);
+
+ for (int i = 0;;) {
+ int skip, len, ac_idx = get_vlc2(gbit, ac_vlc.table, ac_vlc.bits, 3);
+
+ if (ac_idx < 0)
+ return AVERROR_INVALIDDATA;
+ skip = ac_table[ac_idx][0];
+ if (skip == 255)
+ break;
+
+ len = ac_table[ac_idx][1];
+ val = get_bits_long(gbit, len);
+ i = i + 1 + skip;
+ if (i >= max)
+ return AVERROR_INVALIDDATA;
+ if (len && val < 1 << (len - 1))
+ val -= (1 << len) - 1;
+ dst[scan[i]] = (val * quant[scan[i]] + 0x8000) >> 16;
+ }
+
+ return 0;
+}
+
+static void decorrelate(AVCodecContext *avctx, AVFrame *frame, int pos_x, int pos_y)
+{
+ BRAWContext *s = avctx->priv_data;
+ uint16_t *dst = (uint16_t *)(frame->data[0] + pos_y * frame->linesize[0] + pos_x * 2);
+ uint16_t *dst0 = (uint16_t *)(frame->data[0] + pos_y * frame->linesize[0] + pos_x * 2);
+ uint16_t *dst1 = (uint16_t *)(frame->data[0] + (pos_y + 1) * frame->linesize[0] + (pos_x + 1) * 2);
+ uint16_t *src0 = (uint16_t *)(s->out[0]);
+ uint16_t *src1 = (uint16_t *)(s->out[1]);
+
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 8; x++) {
+ dst0[x*2] = av_clip_uintp2(dst0[x*2] + src1[x] - 2048, 12);
+ dst1[x*2] = av_clip_uintp2(dst1[x*2] + src0[x] - 2048, 12);
+ }
+
+ src0 += 8;
+ src1 += 8;
+ dst0 += frame->linesize[0];
+ dst1 += frame->linesize[0];
+ }
+
+ for (int y = 0; y < 8; y++) {
+ for (int x = 0; x < 16; x++) {
+ dst[x] = (dst[x] << 4) + (dst[x] & 15);
+ }
+
+ dst += frame->linesize[0] / 2;
+ }
+}
+
+static int decode_tile(AVCodecContext *avctx, AVFrame *frame, int tile_x, int tile_y,
+ int blocks_w_in_tile, int blocks_h_in_tile)
+{
+ BRAWContext *s = avctx->priv_data;
+ GetBitContext *gbit = &s->gbit;
+ int prev_dc[3];
+ int ret = 0;
+
+ prev_dc[0] = prev_dc[1] = prev_dc[2] = 0;
+
+ for (int y = 0; y < blocks_h_in_tile; y++) {
+ int pos_y = y * 8 + tile_y * s->tile_size_h;
+
+ for (int x = 0; x < blocks_w_in_tile; x++) {
+ int pos_x = s->tile_offset_w[tile_x] + x * 16;
+
+ ret = decode_block(avctx, s->block[0], s->quant[0], &prev_dc[0], 64, 1, 16384, ff_zigzag_direct);
+ if (ret < 0)
+ goto end;
+ ret = decode_block(avctx, s->block[1], s->quant[0], &prev_dc[0], 64, 1, 16384, ff_zigzag_direct);
+ if (ret < 0)
+ goto end;
+ ret = decode_block(avctx, s->block[2], s->quant[1], &prev_dc[1], 32, 1, 8192, half_scan);
+ if (ret < 0)
+ goto end;
+ ret = decode_block(avctx, s->block[3], s->quant[1], &prev_dc[2], 32, 1, 8192, half_scan);
+ if (ret < 0)
+ goto end;
+
+ ff_simple_idct_put_int16_12bit(frame->data[0] + pos_y * frame->linesize[0] + pos_x * 2,
+ frame->linesize[0], s->block[0]);
+ ff_simple_idct_put_int16_12bit(frame->data[0] + pos_y * frame->linesize[0] + pos_x * 2 + 16,
+ frame->linesize[0], s->block[1]);
+ ff_simple_idct84_put_int16_12bit(s->out[0], 16, s->block[2]);
+ ff_simple_idct84_put_int16_12bit(s->out[1], 16, s->block[3]);
+
+ decorrelate(avctx, frame, pos_x, pos_y);
+
+ skip_bits(gbit, 8);
+ if (get_bits_left(gbit) < 0)
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "bits left: %d\n", get_bits_left(gbit));
+end:
+ return ret;
+}
+
+static int get_offset(AVCodecContext *avctx, int x)
+{
+ BRAWContext *s = avctx->priv_data;
+ GetByteContext *gb = &s->gb;
+ int a, b, nb, idx = 4;
+
+ a = bytestream2_get_byte(gb);
+ b = bytestream2_get_byte(gb);
+
+ nb = a * 2 + b;
+ if (nb != 0) {
+ int i = 0, j = 0;
+
+ while (i = j, (nb >> j & 1) == 0) {
+ j++;
+ }
+
+ idx = 4 - i;
+ }
+
+ s->offsets[x][0] = a << (idx & 0x1f);
+ s->offsets[x][1] = b << (idx & 0x1f);
+
+ av_log(avctx, AV_LOG_DEBUG, "offset:%d %dx%d\n", x, s->offsets[x][0], s->offsets[x][1]);
+
+ return 0;
+}
+
+static int get_offsets(AVCodecContext *avctx)
+{
+ for (int i = 0; i < 4; i++)
+ get_offset(avctx, i);
+
+ return 0;
+}
+
+static int decode_quants(AVCodecContext *avctx)
+{
+ BRAWContext *s = avctx->priv_data;
+ GetByteContext *gb = &s->gb;
+ int scale, dcq;
+
+ scale = (s->qscale[0] + 4) * 2048;
+ for (int n = 0; n < 64; n++) {
+ s->quant[0][n] = bytestream2_get_be16(gb) * scale;
+ }
+
+ dcq = s->qscale[1];
+ if (s->quant[0][0] <= dcq)
+ s->quant[0][0] = dcq;
+
+ scale = lrint(fmax(4.0, round((s->qscale[0] + 4) * 0.5 + 0.5)) * 2048.);
+
+ for (int n = 0; n < 32; n++) {
+ s->quant[1][n] = bytestream2_get_be16(gb) * scale;
+ }
+
+ dcq = s->qscale[2];
+ if (s->quant[1][0] <= dcq)
+ s->quant[1][0] = dcq;
+
+ return 0;
+}
+
+static int decode_tiles(AVCodecContext *avctx, AVFrame *frame, ThreadFrame *tframe)
+{
+ BRAWContext *s = avctx->priv_data;
+ GetBitContext *gbit = &s->gbit;
+ GetByteContext *gb = &s->gb;
+ uint32_t braw_size;
+ int version, ret, w, h;
+
+ if (bytestream2_get_le32(gb) != MKTAG('b','r','a','w'))
+ return AVERROR_INVALIDDATA;
+ braw_size = bytestream2_get_be32(gb);
+ if (braw_size < 4352)
+ return AVERROR_INVALIDDATA;
+ if (braw_size - 8 > bytestream2_get_bytes_left(gb))
+ return AVERROR_INVALIDDATA;
+
+ version = bytestream2_get_byte(gb);
+ av_log(avctx, AV_LOG_DEBUG, "version: %d\n", version);
+ if (version != 1 && version != 2)
+ return AVERROR_INVALIDDATA;
+ s->qscale[0] = bytestream2_get_byte(gb);
+ av_log(avctx, AV_LOG_DEBUG, "qscale[0]: %d\n", s->qscale[0]);
+
+ s->nb_tiles_w = bytestream2_get_byte(gb);
+ s->nb_tiles_h = bytestream2_get_byte(gb);
+ av_log(avctx, AV_LOG_DEBUG, "nb_tiles: %dx%d\n", s->nb_tiles_w, s->nb_tiles_h);
+ if (!s->nb_tiles_w ||
+ !s->nb_tiles_h ||
+ s->nb_tiles_w * s->nb_tiles_h > 1024)
+ return AVERROR_INVALIDDATA;
+
+ w = bytestream2_get_be16(gb);
+ h = bytestream2_get_be16(gb);
+ av_log(avctx, AV_LOG_DEBUG, "WxH: %dx%d\n", w, h);
+
+ s->tile_size_h = bytestream2_get_be16(gb);
+ av_log(avctx, AV_LOG_DEBUG, "tile_size_h = %d\n", s->tile_size_h);
+ if (s->tile_size_h & 7)
+ return AVERROR_INVALIDDATA;
+
+ bytestream2_skip(gb, 2);
+
+ ret = get_offsets(avctx);
+ if (ret < 0)
+ return ret;
+ bytestream2_skip(gb, 4);
+
+ s->qscale[1] = bytestream2_get_be16(gb);
+ av_log(avctx, AV_LOG_DEBUG, "qscale[1]: %d\n", s->qscale[1]);
+ s->qscale[2] = bytestream2_get_be16(gb);
+ av_log(avctx, AV_LOG_DEBUG, "qscale[2]: %d\n", s->qscale[2]);
+
+ bytestream2_skip(gb, 28);
+
+ s->tile_offset_w[0] = 0;
+
+ for (int x = 0; x < s->nb_tiles_w; x++) {
+ s->tile_size_w[x] = bytestream2_get_be16(gb);
+ s->tile_offset_w[x+1] = s->tile_offset_w[x] + s->tile_size_w[x];
+ av_log(avctx, AV_LOG_DEBUG, "tile_size_w[%d] = %d\n", x, s->tile_size_w[x]);
+ av_log(avctx, AV_LOG_DEBUG, "tile_offset_w[%d] = %d\n", x+1, s->tile_offset_w[x+1]);
+ if (s->tile_offset_w[x+1] > w)
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = ff_set_dimensions(avctx, s->tile_offset_w[s->nb_tiles_w], s->tile_size_h * s->nb_tiles_h);
+ if (ret < 0)
+ return ret;
+ avctx->width = w;
+ avctx->height = h;
+
+ ret = ff_thread_get_buffer(avctx, tframe, 0);
+ if (ret < 0)
+ return ret;
+
+ bytestream2_seek(gb, 0x1180, SEEK_SET);
+
+ ret = decode_quants(avctx);
+ if (ret < 0)
+ return ret;
+
+ bytestream2_seek(gb, 0x180, SEEK_SET);
+
+ for (int x = 0; x < s->nb_tiles_w; x++) {
+ s->blocks_w_in_tile = s->tile_size_w[x] / 16;
+
+ for (int y = 0; y < s->nb_tiles_h; y++) {
+ uint32_t tile_offset = bytestream2_get_be32(gb);
+ int last_tile = (x == (s->nb_tiles_w - 1)) && (y == (s->nb_tiles_h - 1));
+ int tile_size = last_tile ? bytestream2_size(gb) - tile_offset - s->header_size : bytestream2_peek_be32(gb) - tile_offset;
+
+ if (tile_offset > bytestream2_size(gb) || tile_size <= 0)
+ return AVERROR_INVALIDDATA;
+
+ av_log(avctx, AV_LOG_DEBUG, "%dx%d: tile_bitstream_size: 0x%X, tile_bitstream_offset: 0x%X\n", x, y, tile_size, tile_offset + s->header_size);
+ ret = init_get_bits8(gbit, gb->buffer_start + tile_offset + s->header_size, tile_size);
+ if (ret < 0)
+ return ret;
+
+ if (y == s->nb_tiles_h - 1)
+ s->blocks_h_in_tile = (h - y * s->tile_size_h) / 8;
+ else
+ s->blocks_h_in_tile = s->tile_size_h / 8;
+
+ ret = decode_tile(avctx, frame, x, y, s->blocks_w_in_tile, s->blocks_h_in_tile);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int braw_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ BRAWContext *s = avctx->priv_data;
+ AVFrame *p = data;
+ ThreadFrame frame = { .f = data };
+ int ret;
+
+ if (avpkt->size <= 4608)
+ return AVERROR_INVALIDDATA;
+
+ bytestream2_init(&s->gb, avpkt->data, avpkt->size);
+ ret = parse_frame_metadata(avctx);
+ if (ret < 0)
+ return ret;
+
+ ret = decode_tiles(avctx, p, &frame);
+ if (ret < 0)
+ return ret;
+
+ p->pict_type = AV_PICTURE_TYPE_I;
+ p->key_frame = 1;
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+static av_cold void braw_static_init(void)
+{
+ INIT_VLC_STATIC(&dc_vlc, 13, 16, dc_bits, 1, 1, dc_codes, 2, 2, 8192);
+ INIT_VLC_STATIC(&ac_vlc, 18, 194, ac_bits, 1, 1, ac_codes, 4, 4, 262144);
+}
+
+static av_cold int braw_decode_init(AVCodecContext *avctx)
+{
+ BRAWContext *s = avctx->priv_data;
+ static AVOnce init_once = AV_ONCE_INIT;
+ int ret;
+
+ avctx->pix_fmt = AV_PIX_FMT_BAYER_RGGB16;
+ avctx->bits_per_raw_sample = 12;
+
+ ff_idctdsp_init(&s->idsp, avctx);
+ ff_init_scantable(s->idsp.idct_permutation, &s->scan, ff_zigzag_direct);
+
+ ret = ff_thread_once(&init_once, braw_static_init);
+ if (ret)
+ return AVERROR_UNKNOWN;
+
+ return 0;
+}
+
+AVCodec ff_braw_decoder = {
+ .name = "braw",
+ .long_name = NULL_IF_CONFIG_SMALL("Blackmagic RAW"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_BRAW,
+ .priv_data_size = sizeof(BRAWContext),
+ .init = braw_decode_init,
+ .decode = braw_decode_frame,
+ .capabilities = AV_CODEC_CAP_DR1 |
+ AV_CODEC_CAP_FRAME_THREADS,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
+ FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 529b838e5b..29cb4578e5 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1747,6 +1747,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("MidiVid Archive Codec"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_BRAW,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "braw",
+ .long_name = NULL_IF_CONFIG_SMALL("Blackmagic RAW"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
/* various PCM "codecs" */
{
diff --git a/libavcodec/simple_idct.c b/libavcodec/simple_idct.c
index 3b2e736538..a29f51164f 100644
--- a/libavcodec/simple_idct.c
+++ b/libavcodec/simple_idct.c
@@ -267,3 +267,44 @@ void ff_prores_idct_12(int16_t *block, const int16_t *qmat)
idctSparseCol_int16_12bit(block + i);
}
}
+
+static inline void idct4ColPut_int16_12bit(uint16_t *dest, ptrdiff_t line_size, int16_t *in)
+{
+ const int X0 = 17734;
+ const int X1 = 42813;
+ const int X2 = 32768;
+ int a0 = (in[8*0] * X2);
+ int a2 = (in[8*2] * X2);
+ int a1 = in[8*1];
+ int a3 = in[8*3];
+ int c0 = a0 + a2;
+ int c1 = a0 - a2;
+ int c2 = a1 * X0 - a3 * X1;
+ int c3 = a3 * X0 + a1 * X1;
+ int d0 = av_clip_uintp2((c0 + c3) >> 16, 12);
+ int d1 = av_clip_uintp2((c1 + c2) >> 16, 12);
+ int d2 = av_clip_uintp2((c1 - c2) >> 16, 12);
+ int d3 = av_clip_uintp2((c0 - c3) >> 16, 12);
+
+ dest[0] = d0;
+ dest += line_size;
+ dest[0] = d1;
+ dest += line_size;
+ dest[0] = d2;
+ dest += line_size;
+ dest[0] = d3;
+}
+
+void ff_simple_idct84_put_int16_12bit(uint8_t *dest_, ptrdiff_t line_size, int16_t *block)
+{
+ uint16_t *dest = (uint16_t *)dest_;
+ int i;
+
+ line_size /= 2;
+
+ for (i = 0; i < 4; i++)
+ idctRowCondDC_int16_12bit(block + i * 8, 0);
+
+ for (i = 0; i < 8; i++)
+ idct4ColPut_int16_12bit(dest + i, line_size, block + i);
+}
diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h
index 20578b3347..98d3074ae3 100644
--- a/libavcodec/simple_idct.h
+++ b/libavcodec/simple_idct.h
@@ -61,4 +61,6 @@ void ff_simple_idct84_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block);
void ff_simple_idct48_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block);
void ff_simple_idct44_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block);
+void ff_simple_idct84_put_int16_12bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block);
+
#endif /* AVCODEC_SIMPLE_IDCT_H */
diff --git a/libavformat/isom.c b/libavformat/isom.c
index 824e811177..e9f8590812 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -312,6 +312,13 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_PIXLET, MKTAG('p', 'x', 'l', 't') },
+ { AV_CODEC_ID_BRAW, MKTAG('b', 'r', 'x', 'q') },
+ { AV_CODEC_ID_BRAW, MKTAG('b', 'r', 'h', 'q') },
+ { AV_CODEC_ID_BRAW, MKTAG('b', 'r', 's', 't') },
+ { AV_CODEC_ID_BRAW, MKTAG('b', 'r', 'l', 't') },
+ { AV_CODEC_ID_BRAW, MKTAG('b', 'r', 'v', 'l') },
+ { AV_CODEC_ID_BRAW, MKTAG('b', 'r', 'v', 'm') },
+
{ AV_CODEC_ID_NONE, 0 },
};
--
2.17.1
More information about the ffmpeg-devel
mailing list