[FFmpeg-devel] [PATCH] Make decoding alpha option for some codecs.

Reimar Döffinger Reimar.Doeffinger at gmx.de
Tue Sep 17 21:31:07 CEST 2013


For codecs where decoding of a whole plane can simply
be skipped, we should offer applications to not decode
alpha for better performance.
It also means applications do not need to implement support
(even if it is rather simple) for YUVA formats in order to be
able to play these files.
Unfortunately a good way to test this via FFmpeg only is missing,
suggestions welcome.

Signed-off-by: Reimar Döffinger <Reimar.Doeffinger at gmx.de>
---
 libavcodec/ffv1dec.c        | 15 ++++++++++++---
 libavcodec/proresdec2.c     |  8 +++++++-
 libavcodec/proresdec_lgpl.c | 14 +++++++++++++-
 libavcodec/vp56.c           | 12 ++++++++----
 4 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 5455660..75e26bc 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -659,14 +659,23 @@ static int read_header(FFV1Context *f)
                 return AVERROR(ENOSYS);
             }
         } else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) {
+            static const enum AVPixelFormat alpha_fmts[][3] = {
+                {AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE},
+                {AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE},
+                {AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}
+            };
             switch(16*f->chroma_h_shift + f->chroma_v_shift) {
-            case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P; break;
-            case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P; break;
-            case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P; break;
+            case 0x00: f->avctx->pix_fmt = f->avctx->get_format(f->avctx, alpha_fmts[0]); break;
+            case 0x10: f->avctx->pix_fmt = f->avctx->get_format(f->avctx, alpha_fmts[1]); break;
+            case 0x11: f->avctx->pix_fmt = f->avctx->get_format(f->avctx, alpha_fmts[2]); break;
             default:
                 av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
                 return AVERROR(ENOSYS);
             }
+            if (f->avctx->pix_fmt != AV_PIX_FMT_YUVA444P &&
+                f->avctx->pix_fmt != AV_PIX_FMT_YUVA422P &&
+                f->avctx->pix_fmt != AV_PIX_FMT_YUVA420P)
+                f->transparency = 0;
         } else if (f->avctx->bits_per_raw_sample == 9) {
             f->packed_at_lsb = 1;
             switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c
index defefda..eb25a89 100644
--- a/libavcodec/proresdec2.c
+++ b/libavcodec/proresdec2.c
@@ -130,7 +130,13 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
     }
 
     if (ctx->alpha_info) {
-        avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUVA444P10 : AV_PIX_FMT_YUVA422P10;
+        static const enum AVPixelFormat alpha_fmts[][3] = {
+            {AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE},
+            {AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_NONE}};
+        avctx->pix_fmt = avctx->get_format(avctx, alpha_fmts[(buf[12] & 0xC0) == 0xC0]);
+        if (avctx->pix_fmt != AV_PIX_FMT_YUVA422P10 &&
+            avctx->pix_fmt != AV_PIX_FMT_YUVA444P10)
+            ctx->alpha_info = 0;
     } else {
         avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUV444P10 : AV_PIX_FMT_YUV422P10;
     }
diff --git a/libavcodec/proresdec_lgpl.c b/libavcodec/proresdec_lgpl.c
index bf61a38..bf313a1 100644
--- a/libavcodec/proresdec_lgpl.c
+++ b/libavcodec/proresdec_lgpl.c
@@ -145,10 +145,22 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
     case 2:
         avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA422P10
                                          : AV_PIX_FMT_YUV422P10;
+        if (ctx->alpha_info) {
+            static const enum AVPixelFormat alpha_fmts[] = {AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE};
+            avctx->pix_fmt = avctx->get_format(avctx, alpha_fmts);
+            if (avctx->pix_fmt != AV_PIX_FMT_YUVA422P10)
+                ctx->alpha_info = 0;
+        }
         break;
     case 3:
         avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA444P10
                                          : AV_PIX_FMT_YUV444P10;
+        if (ctx->alpha_info) {
+            static const enum AVPixelFormat alpha_fmts[] = {AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_NONE};
+            avctx->pix_fmt = avctx->get_format(avctx, alpha_fmts);
+            if (avctx->pix_fmt != AV_PIX_FMT_YUVA444P10)
+                ctx->alpha_info = 0;
+        }
         break;
     default:
         av_log(avctx, AV_LOG_ERROR,
@@ -608,7 +620,7 @@ static int decode_slice(AVCodecContext *avctx, void *tdata)
     coff[2]     = coff[1] + u_data_size;
     v_data_size = hdr_size > 7 ? AV_RB16(buf + 6) : slice_data_size - coff[2];
     coff[3]     = coff[2] + v_data_size;
-    a_data_size = slice_data_size - coff[3];
+    a_data_size = ctx->alpha_info ? slice_data_size - coff[3] : 0;
 
     /* if V or alpha component size is negative that means that previous
        component sizes are too large */
diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c
index 38f0e08..5f058aa 100644
--- a/libavcodec/vp56.c
+++ b/libavcodec/vp56.c
@@ -528,7 +528,7 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
     if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0)
         return -1;
 
-    if (s->has_alpha) {
+    if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
         av_frame_unref(s->alpha_context->frames[VP56_FRAME_CURRENT]);
         if ((ret = av_frame_ref(s->alpha_context->frames[VP56_FRAME_CURRENT], p)) < 0) {
             av_frame_unref(p);
@@ -543,7 +543,7 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         }
     }
 
-    if (s->has_alpha) {
+    if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
         int bak_w = avctx->width;
         int bak_h = avctx->height;
         int bak_cw = avctx->coded_width;
@@ -565,7 +565,7 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         }
     }
 
-    avctx->execute2(avctx, ff_vp56_decode_mbs, 0, 0, s->has_alpha + 1);
+    avctx->execute2(avctx, ff_vp56_decode_mbs, 0, 0, avctx->pix_fmt == AV_PIX_FMT_YUVA420P ? 2 : 1);
 
     if ((res = av_frame_ref(data, p)) < 0)
         return res;
@@ -687,7 +687,11 @@ av_cold int ff_vp56_init_context(AVCodecContext *avctx, VP56Context *s,
     int i;
 
     s->avctx = avctx;
-    avctx->pix_fmt = has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
+    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+    if (has_alpha) {
+        static const enum AVPixelFormat alpha_fmts[] = {AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
+        avctx->pix_fmt = avctx->get_format(avctx, alpha_fmts);
+    }
 
     ff_h264chroma_init(&s->h264chroma, 8);
     ff_hpeldsp_init(&s->hdsp, avctx->flags);
-- 
1.8.4.rc3



More information about the ffmpeg-devel mailing list