Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 1/3] avcodec: add AV_CODEC_ID_BRAW
@ 2025-04-15 10:04 Lynne
  2025-04-15 10:04 ` [FFmpeg-devel] [PATCH 2/3] lavf/mov: support demuxing Blackmagic RAW streams Lynne
  2025-04-15 10:04 ` [FFmpeg-devel] [PATCH 3/3] avcodec: add Blackmagic RAW decoder Lynne
  0 siblings, 2 replies; 4+ messages in thread
From: Lynne @ 2025-04-15 10:04 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Lynne

This adds codec entries for the Blackmagic RAW codec.
---
 libavcodec/codec_desc.c | 7 +++++++
 libavcodec/codec_id.h   | 1 +
 2 files changed, 8 insertions(+)

diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 9fb190e35a..90e31a8b6a 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1985,6 +1985,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
         .mime_types= MT("image/jxl"),
     },
+    {
+        .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/codec_id.h b/libavcodec/codec_id.h
index 2f6efe8261..0175fc2d7b 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -329,6 +329,7 @@ enum AVCodecID {
     AV_CODEC_ID_DNXUC,
     AV_CODEC_ID_RV60,
     AV_CODEC_ID_JPEGXL_ANIM,
+    AV_CODEC_ID_BRAW,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
-- 
2.49.0.395.g12beb8f557c
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [FFmpeg-devel] [PATCH 2/3] lavf/mov: support demuxing Blackmagic RAW streams
  2025-04-15 10:04 [FFmpeg-devel] [PATCH 1/3] avcodec: add AV_CODEC_ID_BRAW Lynne
@ 2025-04-15 10:04 ` Lynne
  2025-04-15 10:04 ` [FFmpeg-devel] [PATCH 3/3] avcodec: add Blackmagic RAW decoder Lynne
  1 sibling, 0 replies; 4+ messages in thread
From: Lynne @ 2025-04-15 10:04 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Lynne

---
 libavformat/isom_tags.c | 7 +++++++
 libavformat/mov.c       | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/libavformat/isom_tags.c b/libavformat/isom_tags.c
index f05762beec..7bf2bf7d5b 100644
--- a/libavformat/isom_tags.c
+++ b/libavformat/isom_tags.c
@@ -286,6 +286,13 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
 
     { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'G', 'R') }, /* ASC Bayer BGGR */
 
+    { AV_CODEC_ID_BRAW, MKTAG('b', 'r', 'x', 'q') }, /* Blackmagic RAW */
+    { 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_MEDIA100, MKTAG('6', '0', '1', 'N') },
     { AV_CODEC_ID_MEDIA100, MKTAG('6', '0', '1', 'P') },
     { AV_CODEC_ID_MEDIA100, MKTAG('d', 't', 'n', 't') },
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 452690090c..b4056fba48 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -11349,7 +11349,7 @@ const FFInputFormat ff_mov_demuxer = {
     .p.name         = "mov,mp4,m4a,3gp,3g2,mj2",
     .p.long_name    = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
     .p.priv_class   = &mov_class,
-    .p.extensions   = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v,avif,heic,heif",
+    .p.extensions   = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v,avif,heic,heif,braw",
     .p.flags        = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS | AVFMT_SHOW_IDS,
     .priv_data_size = sizeof(MOVContext),
     .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
-- 
2.49.0.395.g12beb8f557c
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [FFmpeg-devel] [PATCH 3/3] avcodec: add Blackmagic RAW decoder
  2025-04-15 10:04 [FFmpeg-devel] [PATCH 1/3] avcodec: add AV_CODEC_ID_BRAW Lynne
  2025-04-15 10:04 ` [FFmpeg-devel] [PATCH 2/3] lavf/mov: support demuxing Blackmagic RAW streams Lynne
@ 2025-04-15 10:04 ` Lynne
  2025-04-15 12:07   ` Lynne
  1 sibling, 1 reply; 4+ messages in thread
From: Lynne @ 2025-04-15 10:04 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Lynne

Most of the work was done by Paul B Mahol.
I cleaned the patch up, improved the code a bit, and added slice
threading.
---
 configure              |   1 +
 libavcodec/Makefile    |   1 +
 libavcodec/allcodecs.c |   1 +
 libavcodec/braw.c      | 666 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 669 insertions(+)
 create mode 100755 libavcodec/braw.c

diff --git a/configure b/configure
index bd4f872376..1171260d57 100755
--- a/configure
+++ b/configure
@@ -2943,6 +2943,7 @@ av1_decoder_select="atsc_a53 cbs_av1 dovi_rpudec"
 bink_decoder_select="blockdsp hpeldsp"
 binkaudio_dct_decoder_select="wma_freqs"
 binkaudio_rdft_decoder_select="wma_freqs"
+braw_decoder_select="idctdsp"
 cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp"
 clearvideo_decoder_select="idctdsp"
 cllc_decoder_select="bswapdsp"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 7bd1dbec9a..50733ab048 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -289,6 +289,7 @@ OBJS-$(CONFIG_BMP_ENCODER)             += bmpenc.o
 OBJS-$(CONFIG_BMV_AUDIO_DECODER)       += bmvaudio.o
 OBJS-$(CONFIG_BMV_VIDEO_DECODER)       += bmvvideo.o
 OBJS-$(CONFIG_BONK_DECODER)            += bonk.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 f10519617e..277e17acc3 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -69,6 +69,7 @@ extern const FFCodec ff_bitpacked_encoder;
 extern const FFCodec ff_bmp_encoder;
 extern const FFCodec ff_bmp_decoder;
 extern const FFCodec ff_bmv_video_decoder;
+extern const FFCodec ff_braw_decoder;
 extern const FFCodec ff_brender_pix_decoder;
 extern const FFCodec ff_c93_decoder;
 extern const FFCodec ff_cavs_decoder;
diff --git a/libavcodec/braw.c b/libavcodec/braw.c
new file mode 100755
index 0000000000..2246b2d645
--- /dev/null
+++ b/libavcodec/braw.c
@@ -0,0 +1,666 @@
+/*
+ * Blackmagic RAW codec
+ *
+ * Copyright (c) 2019 Paul B Mahol
+ * Copyright (c) 2025 Lynne
+ *
+ * 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/mem_internal.h"
+
+#include "decode.h"
+#include "thread.h"
+#include "codec_internal.h"
+#include "mpegvideo.h"
+#include "bytestream.h"
+#include "get_bits.h"
+#include "vlc.h"
+#include "simple_idct.h"
+
+#define IN_IDCT_DEPTH 16
+#define PRORES_ONLY
+#define BIT_DEPTH 12
+#include "simple_idct_template.c"
+
+#define BRAW_MAX_TILES 1024
+
+typedef struct BRAWTile {
+    const uint8_t *data;
+    uint32_t size;
+    int x;
+    int y;
+    int blocks_w_in_tile;
+    int blocks_h_in_tile;
+    int ret;
+} BRAWTile;
+
+typedef struct BRAWContext {
+    const AVClass    *class;
+
+    enum AVPixelFormat pix_fmt;
+
+    GetByteContext    gb;
+
+    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               qscale[3];
+    int               quant[2][64];
+
+    ScanTable         scan;
+    IDCTDSPContext    idsp;
+
+    BRAWTile          tiles[BRAW_MAX_TILES];
+    AVFrame          *frame;
+} BRAWContext;
+
+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_bits[16] = {
+    2, 3, 3, 3, 3, 3, 5, 5, 6, 12, 12, 12, 12, 5, 12, 13,
+};
+
+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_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,
+};
+
+#define DC_VLC_BITS 13
+#define AC_VLC_BITS 18
+static VLCElem dc_vlc[1 << DC_VLC_BITS];
+static VLCElem ac_vlc[1 << AC_VLC_BITS];
+
+static av_cold void braw_static_init(void)
+{
+    VLC_INIT_STATIC_TABLE(dc_vlc, DC_VLC_BITS, FF_ARRAY_ELEMS(dc_bits), dc_bits, 1, 1, dc_codes, 2, 2, 0);
+    VLC_INIT_STATIC_TABLE(ac_vlc, AC_VLC_BITS, FF_ARRAY_ELEMS(ac_bits), ac_bits, 1, 1, ac_codes, 4, 4, 0);
+}
+
+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;
+}
+
+static void idct84_put_int16_12bit(uint16_t *dest, ptrdiff_t line_size, int16_t *block)
+{
+    line_size >>= 1;
+
+    for (int i = 0; i < 4; i++)
+        idctRowCondDC_int16_12bit(block + i * 8, 0);
+
+    for (int i = 0; i < 8; i++)
+        idct4ColPut_int16_12bit(dest + i, line_size, block + i);
+}
+
+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_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_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 int decode_block(AVCodecContext *avctx, GetBitContext *gbit,
+                        int16_t *dst, const int *quant,
+                        int *prev_dc, int max,
+                        int mul, int add,
+                        const uint8_t *scan)
+{
+    int dc_idx, sgnbit = 0, sign, len, val, code;
+
+    memset(dst, 0, 64 * 2);
+
+    dc_idx = get_vlc2(gbit, dc_vlc, 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;
+
+        ac_idx = get_vlc2(gbit, ac_vlc, 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 (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, uint8_t *data, ptrdiff_t linesize,
+                        uint8_t *out0, uint8_t *out1, int pos_x, int pos_y)
+{
+    uint16_t *dst = (uint16_t *)(data + pos_y * linesize + pos_x * 2);
+    uint16_t *dst0 = (uint16_t *)(data  + pos_y * linesize + pos_x * 2);
+    uint16_t *dst1 = (uint16_t *)(data + (pos_y + 1) * linesize + (pos_x + 1) * 2);
+    uint16_t *src0 = (uint16_t *)(out0);
+    uint16_t *src1 = (uint16_t *)(out1);
+
+    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 += linesize;
+        dst1 += linesize;
+    }
+
+    for (int y = 0; y < 8; y++) {
+        for (int x = 0; x < 16; x++)
+            dst[x] = (dst[x] << 4) + (dst[x] & 15);
+
+        dst += linesize >> 1;
+    }
+}
+
+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 int decode_tile_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr)
+{
+    BRAWContext *s = avctx->priv_data;
+    BRAWTile *t = &s->tiles[jobnr];
+
+    GetBitContext gb;
+    int prev_dc[3];
+    int ret = 0;
+
+    LOCAL_ALIGNED_32(int16_t, block, [4], [64]);
+    LOCAL_ALIGNED_32(uint16_t, out, [2], [64]);
+
+    t->ret = -1;
+
+    ret = init_get_bits8(&gb, t->data, t->size);
+    if (ret < 0)
+        return ret;
+
+    prev_dc[0] = prev_dc[1] = prev_dc[2] = 0;
+
+    for (int y = 0; y < t->blocks_h_in_tile; y++) {
+        int pos_y = y * 8 + t->y * s->tile_size_h;
+
+        for (int x = 0; x < t->blocks_w_in_tile; x++) {
+            int pos_x = s->tile_offset_w[t->x] + x * 16;
+
+            ret = decode_block(avctx, &gb, block[0], s->quant[0], &prev_dc[0], 64, 1, 16384, ff_zigzag_direct);
+            if (ret < 0)
+                return ret;
+            ret = decode_block(avctx, &gb, block[1], s->quant[0], &prev_dc[0], 64, 1, 16384, ff_zigzag_direct);
+            if (ret < 0)
+                return ret;
+            ret = decode_block(avctx, &gb, block[2], s->quant[1], &prev_dc[1], 32, 1,  8192, half_scan);
+            if (ret < 0)
+                return ret;
+            ret = decode_block(avctx, &gb, block[3], s->quant[1], &prev_dc[2], 32, 1,  8192, half_scan);
+            if (ret < 0)
+                return ret;
+
+            ff_simple_idct_put_int16_12bit(s->frame->data[0] + pos_y * s->frame->linesize[0] + pos_x * 2,
+                                           s->frame->linesize[0], block[0]);
+            ff_simple_idct_put_int16_12bit(s->frame->data[0] + pos_y * s->frame->linesize[0] + pos_x * 2 + 16,
+                                           s->frame->linesize[0], block[1]);
+            idct84_put_int16_12bit(out[0], 16, block[2]);
+            idct84_put_int16_12bit(out[1], 16, block[3]);
+
+            decorrelate(avctx, s->frame->data[0], s->frame->linesize[0], (uint8_t *)out[0], (uint8_t *)out[1], pos_x, pos_y);
+
+            skip_bits(&gb, 8);
+            if (get_bits_left(&gb) < 0)
+                return AVERROR_INVALIDDATA;
+        }
+    }
+
+    t->ret = 0;
+    av_log(avctx, AV_LOG_DEBUG, "bits left: %d\n", get_bits_left(&gb));
+    return 0;
+}
+
+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 parse_frame_header(AVCodecContext *avctx)
+{
+    BRAWContext *s = avctx->priv_data;
+    GetByteContext *gb = &s->gb;
+
+    uint32_t braw_size;
+    int version, ret, w, h;
+    enum AVPixelFormat pix_fmt;
+
+    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);
+
+    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 > BRAW_MAX_TILES)
+        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;
+
+    pix_fmt = AV_PIX_FMT_BAYER_RGGB16;
+    avctx->bits_per_raw_sample = 12;
+    if (pix_fmt != s->pix_fmt) {
+        avctx->pix_fmt = s->pix_fmt = pix_fmt;
+    }
+
+    return 0;
+}
+
+static int parse_tiles(AVCodecContext *avctx)
+{
+    BRAWContext *s = avctx->priv_data;
+    GetByteContext *gb = &s->gb;
+
+    for (int x = 0; x < s->nb_tiles_w; x++) {
+        for (int y = 0; y < s->nb_tiles_h; y++) {
+            uint32_t offset;
+            BRAWTile *t = &s->tiles[y*s->nb_tiles_w + x];
+
+            int last_tile = (x == (s->nb_tiles_w - 1)) && (y == (s->nb_tiles_h - 1));
+
+            t->x = x;
+            t->y = y;
+            t->blocks_w_in_tile = s->tile_size_w[x] / 16;
+            if (y == s->nb_tiles_h - 1)
+                t->blocks_h_in_tile = (avctx->height - y * s->tile_size_h) / 8;
+            else
+                t->blocks_h_in_tile = s->tile_size_h / 8;
+            offset = bytestream2_get_be32(gb);
+            t->size = last_tile ? bytestream2_size(gb) - offset - s->header_size : bytestream2_peek_be32(gb) - offset;
+
+            if (offset > bytestream2_size(gb) || t->size <= 0)
+                return AVERROR_INVALIDDATA;
+
+            t->data = gb->buffer_start + offset + s->header_size;
+
+            av_log(avctx, AV_LOG_DEBUG, "%dx%d: tile_bitstream_size: 0x%X, tile_bitstream_offset: 0x%X\n", x, y, t->size, offset + s->header_size);
+        }
+    }
+
+    return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx)
+{
+    BRAWContext *s = avctx->priv_data;
+    int error = 0, tile_count = s->nb_tiles_w * s->nb_tiles_h;
+
+    avctx->execute2(avctx, decode_tile_thread, NULL, NULL, tile_count);
+
+    for (int i = 0; i < tile_count; i++)
+        error += s->tiles[i].ret < 0;
+
+    if (error)
+        s->frame->decode_error_flags = FF_DECODE_ERROR_INVALID_BITSTREAM;
+    if (error < tile_count)
+        return 0;
+
+    return s->tiles[0].ret;
+}
+
+static int braw_decode_frame(AVCodecContext *avctx, AVFrame *f, int *got_frame,
+                             AVPacket *avpkt)
+{
+    int ret;
+    BRAWContext *s = avctx->priv_data;
+
+    if (avpkt->size <= 4608)
+        return AVERROR_INVALIDDATA;
+
+    bytestream2_init(&s->gb, avpkt->data, avpkt->size);
+    ret = parse_frame_header(avctx);
+    if (ret < 0)
+        return ret;
+
+    ret = ff_thread_get_buffer(avctx, f, 0);
+    if (ret < 0)
+        return ret;
+    ff_thread_finish_setup(avctx);
+
+    bytestream2_seek(&s->gb, 0x1180, SEEK_SET);
+    ret = decode_quants(avctx);
+    if (ret < 0)
+        return ret;
+
+    bytestream2_seek(&s->gb, 0x180, SEEK_SET);
+    ret = parse_tiles(avctx);
+    if (ret < 0)
+        return ret;
+
+    s->frame = f;
+    ret = decode_frame(avctx);
+    if (ret < 0)
+        return ret;
+
+    f->pict_type = AV_PICTURE_TYPE_I;
+    f->flags = AV_FRAME_FLAG_KEY;
+    *got_frame = 1;
+
+    return avpkt->size;
+}
+
+static av_cold int braw_decode_init(AVCodecContext *avctx)
+{
+    BRAWContext *s = avctx->priv_data;
+    static AVOnce init_once = AV_ONCE_INIT;
+    int ret;
+
+    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;
+
+    s->pix_fmt = AV_PIX_FMT_NONE;
+
+    return 0;
+}
+
+#if HAVE_THREADS
+static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
+{
+    BRAWContext *csrc = src->priv_data;
+    BRAWContext *cdst = dst->priv_data;
+
+    cdst->pix_fmt = csrc->pix_fmt;
+
+    return 0;
+}
+#endif
+
+const FFCodec ff_braw_decoder = {
+    .p.name           = "braw",
+    CODEC_LONG_NAME("Blackmagic RAW"),
+    .p.type           = AVMEDIA_TYPE_VIDEO,
+    .p.id             = AV_CODEC_ID_BRAW,
+    .priv_data_size   = sizeof(BRAWContext),
+    .init             = braw_decode_init,
+    FF_CODEC_DECODE_CB(braw_decode_frame),
+    UPDATE_THREAD_CONTEXT(update_thread_context),
+    .p.capabilities   = AV_CODEC_CAP_DR1 |
+                        AV_CODEC_CAP_SLICE_THREADS |
+                        AV_CODEC_CAP_FRAME_THREADS,
+    .caps_internal    = FF_CODEC_CAP_INIT_CLEANUP,
+};
+
-- 
2.49.0.395.g12beb8f557c
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [FFmpeg-devel] [PATCH 3/3] avcodec: add Blackmagic RAW decoder
  2025-04-15 10:04 ` [FFmpeg-devel] [PATCH 3/3] avcodec: add Blackmagic RAW decoder Lynne
@ 2025-04-15 12:07   ` Lynne
  0 siblings, 0 replies; 4+ messages in thread
From: Lynne @ 2025-04-15 12:07 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On 15/04/2025 12:04, Lynne wrote:
> Most of the work was done by Paul B Mahol.
> I cleaned the patch up, improved the code a bit, and added slice
> threading.
> ---
>   configure              |   1 +
>   libavcodec/Makefile    |   1 +
>   libavcodec/allcodecs.c |   1 +
>   libavcodec/braw.c      | 666 +++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 669 insertions(+)
>   create mode 100755 libavcodec/braw.c

Output is kinda-bayer but apparently not.
Patch dropped.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-04-15 12:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-15 10:04 [FFmpeg-devel] [PATCH 1/3] avcodec: add AV_CODEC_ID_BRAW Lynne
2025-04-15 10:04 ` [FFmpeg-devel] [PATCH 2/3] lavf/mov: support demuxing Blackmagic RAW streams Lynne
2025-04-15 10:04 ` [FFmpeg-devel] [PATCH 3/3] avcodec: add Blackmagic RAW decoder Lynne
2025-04-15 12:07   ` Lynne

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git