[FFmpeg-devel] [PATCH] avcodec/ffv1: Support for RGBA64 and GBRAP16

Jerome Martinez jerome at mediaarea.net
Thu Feb 1 14:43:00 EET 2018


Add support for 16-bit/component RGB with Alpha encoding and decoding in 
FFV1, both RGBA64 and GBRAP16 for encoding, GBRAP16 for decoding.

Resulting bitstream was tested about lossless encoding/decoding by the 
compression from DPX to FFV1 then decompression from FFV1 to DPX, see 
commands below (resulting framemd5 hashes are all same).
Resulting bitstream is decodable by another decoder (with same resulting 
framemd5 hash).
Resulting bitstream passed through a conformance checker compared to 
current FFV1 specification IETF draft.

About the patch:
- some modified lines are not used (the ones not used when f->use32bit 
is 1), but it makes the code more coherent (especially because 
decode_rgb_frame signature is same for both 16-bit and 32-bit version) 
and prepares the support of RGBA with 10/12/14 bits/component.
- GBRAP16 was chosen for decoding because GBRP16 is already used when no 
alpha, and the code is more prepared for planar pix_fmt when bit depth 
is >8.
- "s->transparency = desc->nb_components == 4 || desc->nb_components == 
2;" is a copy of a line a bit above about the detection of transparency, 
I preferred to reuse it as is even if "YA" 16-bit/component is not (yet) 
supported.

FFmpeg commands used for tests:
./ffmpeg -i in.dpx -c:v ffv1 out.mkv
./ffmpeg -i in.dpx -pix_fmt gbrap16 -strict -2 -c:v ffv1 out2.mkv
./ffmpeg -i out.mkv out.dpx

./ffmpeg -i in.dpx -f framemd5 in.dpx.framemd5
./ffmpeg -i out.mkv -pix_fmt rgba64be -f framemd5 out.mkv.framemd5
./ffmpeg -i out2.mkv -pix_fmt rgba64be -f framemd5 out2.mkv.framemd5
./ffmpeg -i out.dpx -f framemd5 out.dpx.framemd5

Test file used (renamed to in.dpx):
https://mediaarea.net/temp/uncropped_DPX_4K_16bit_Overscan15pros.dpx

Jérôme

-------------- next part --------------
From 0e149afd7eadb1ec05cc79fff78337b2c543ad8e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Martinez?= <jerome at mediaarea.net>
Date: Thu, 1 Feb 2018 13:11:53 +0100
Subject: [PATCH] avcodec/ffv1: Support for RGBA64 and GBRAP16

---
 libavcodec/ffv1dec.c          | 14 ++++++++++----
 libavcodec/ffv1dec_template.c |  6 +++++-
 libavcodec/ffv1enc.c          | 16 ++++++++++++++--
 libavcodec/ffv1enc_template.c | 10 +++++++---
 4 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 5eadb6b158..923b79f3ab 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -336,14 +336,16 @@ static int decode_slice(AVCodecContext *c, void *arg)
          decode_plane(fs, p->data[0] + ps*x + y*p->linesize[0]    , width, height, p->linesize[0], 0, 2);
          decode_plane(fs, p->data[0] + ps*x + y*p->linesize[0] + 1, width, height, p->linesize[0], 1, 2);
     } else if (f->use32bit) {
-        uint8_t *planes[3] = { p->data[0] + ps * x + y * p->linesize[0],
+        uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0],
                                p->data[1] + ps * x + y * p->linesize[1],
-                               p->data[2] + ps * x + y * p->linesize[2] };
+                               p->data[2] + ps * x + y * p->linesize[2],
+                               p->data[3] + ps * x + y * p->linesize[3] };
         decode_rgb_frame32(fs, planes, width, height, p->linesize);
     } else {
-        uint8_t *planes[3] = { p->data[0] + ps * x + y * p->linesize[0],
+        uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0],
                                p->data[1] + ps * x + y * p->linesize[1],
-                               p->data[2] + ps * x + y * p->linesize[2] };
+                               p->data[2] + ps * x + y * p->linesize[2],
+                               p->data[3] + ps * x + y * p->linesize[3] };
         decode_rgb_frame(fs, planes, width, height, p->linesize);
     }
     if (fs->ac != AC_GOLOMB_RICE && f->version > 2) {
@@ -694,6 +696,10 @@ static int read_header(FFV1Context *f)
             f->avctx->pix_fmt = AV_PIX_FMT_GBRP16;
             f->use32bit = 1;
         }
+        else if (f->avctx->bits_per_raw_sample == 16 && f->transparency) {
+            f->avctx->pix_fmt = AV_PIX_FMT_GBRAP16;
+            f->use32bit = 1;
+        }
     } else {
         av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n");
         return AVERROR(ENOSYS);
diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c
index 37df766773..2904a44112 100644
--- a/libavcodec/ffv1dec_template.c
+++ b/libavcodec/ffv1dec_template.c
@@ -107,7 +107,7 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w,
     return 0;
 }
 
-static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[3], int w, int h, int stride[3])
+static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int h, int stride[4])
 {
     int x, y, p;
     TYPE *sample[4][2];
@@ -158,10 +158,14 @@ static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[3], int w, int
                 *((uint16_t*)(src[0] + x*2 + stride[0]*y)) = g;
                 *((uint16_t*)(src[1] + x*2 + stride[1]*y)) = b;
                 *((uint16_t*)(src[2] + x*2 + stride[2]*y)) = r;
+                if (s->transparency)
+                    *((uint16_t*)(src[3] + x*2 + stride[3]*y)) = a;
             } else {
                 *((uint16_t*)(src[0] + x*2 + stride[0]*y)) = b;
                 *((uint16_t*)(src[1] + x*2 + stride[1]*y)) = g;
                 *((uint16_t*)(src[2] + x*2 + stride[2]*y)) = r;
+                if (s->transparency)
+                    *((uint16_t*)(src[3] + x*2 + stride[3]*y)) = a;
             }
         }
     }
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index c0c1558ffe..9ba5c6fcfd 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -624,6 +624,14 @@ FF_ENABLE_DEPRECATION_WARNINGS
         s->chroma_planes = 1;
         s->bits_per_raw_sample = 8;
         break;
+    case AV_PIX_FMT_RGBA64:
+        s->colorspace = 1;
+        s->transparency = 1;
+        s->chroma_planes = 1;
+        s->bits_per_raw_sample = 16;
+        s->use32bit = 1;
+        s->version = FFMAX(s->version, 1);
+        break;
     case AV_PIX_FMT_RGB48:
         s->colorspace = 1;
         s->chroma_planes = 1;
@@ -649,10 +657,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
         if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample)
             s->bits_per_raw_sample = 14;
     case AV_PIX_FMT_GBRP16:
+    case AV_PIX_FMT_GBRAP16:
         if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample)
             s->bits_per_raw_sample = 16;
         else if (!s->bits_per_raw_sample)
             s->bits_per_raw_sample = avctx->bits_per_raw_sample;
+        s->transparency = desc->nb_components == 4 || desc->nb_components == 2;
         s->colorspace = 1;
         s->chroma_planes = 1;
         if (s->bits_per_raw_sample >= 16) {
@@ -1028,9 +1038,10 @@ static int encode_slice(AVCodecContext *c, void *arg)
     const int ps     = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step;
     int ret;
     RangeCoder c_bak = fs->c;
-    const uint8_t *planes[3] = {p->data[0] + ps*x + y*p->linesize[0],
+    const uint8_t *planes[4] = {p->data[0] + ps*x + y*p->linesize[0],
                                 p->data[1] ? p->data[1] + ps*x + y*p->linesize[1] : NULL,
-                                p->data[2] ? p->data[2] + ps*x + y*p->linesize[2] : NULL};
+                                p->data[2] ? p->data[2] + ps*x + y*p->linesize[2] : NULL,
+                                p->data[3] ? p->data[3] + ps*x + y*p->linesize[3] : NULL};
 
     fs->slice_coding_mode = 0;
     if (f->version > 3) {
@@ -1322,6 +1333,7 @@ AVCodec ff_ffv1_encoder = {
         AV_PIX_FMT_YA8,
         AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12,
         AV_PIX_FMT_GBRP16, AV_PIX_FMT_RGB48,
+        AV_PIX_FMT_GBRAP16, AV_PIX_FMT_RGBA64,
         AV_PIX_FMT_NONE
 
     },
diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c
index b7eea0dd70..2763082540 100644
--- a/libavcodec/ffv1enc_template.c
+++ b/libavcodec/ffv1enc_template.c
@@ -122,8 +122,8 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *s, int w,
     return 0;
 }
 
-static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[3],
-                                    int w, int h, const int stride[3])
+static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[4],
+                                    int w, int h, const int stride[4])
 {
     int x, y, p, i;
     const int ring_size = s->context_model ? 3 : 2;
@@ -152,14 +152,18 @@ static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[3],
                 r = (v >> 16) & 0xFF;
                 a =  v >> 24;
             } else if (packed) {
-                const uint16_t *p = ((const uint16_t*)(src[0] + x*6 + stride[0]*y));
+                const uint16_t *p = ((const uint16_t*)(src[0] + x*(3 + s->transparency)*2 + stride[0]*y));
                 r = p[0];
                 g = p[1];
                 b = p[2];
+                if (s->transparency)
+                  a = p[3];
             } else if (sizeof(TYPE) == 4) {
                 g = *((const uint16_t *)(src[0] + x*2 + stride[0]*y));
                 b = *((const uint16_t *)(src[1] + x*2 + stride[1]*y));
                 r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y));
+                if (s->transparency)
+                    a = *((const uint16_t *)(src[3] + x*2 + stride[2]*y));
             } else {
                 b = *((const uint16_t *)(src[0] + x*2 + stride[0]*y));
                 g = *((const uint16_t *)(src[1] + x*2 + stride[1]*y));
-- 
2.13.3.windows.1



More information about the ffmpeg-devel mailing list