--
Debargha Mukherjee, Ph.D.
Staff Software Engineer,
Google, Inc.
Email: [email protected]
Phone: 408-234-5956 (cell)
From ea4e6a0718563bc069d42e5604a9971ae71b3853 Mon Sep 17 00:00:00 2001
From: Deb Mukherjee <[email protected]>
Date: Wed, 25 Mar 2015 17:10:16 -0700
Subject: [PATCH] Support for VP9 high-color/high-bit-depth encoding
Note that you will need to configure libvpx with
--enable-vp9-highbitdepth before building and linking
with ffmpeg for 10-/12-bit encoding.
You may use the appropriate profile option on the
command line:
-profile:v 1 for 422/444 8-bit encoding
-profile:v 2 for 420 10-/12- bit encoding
-profile:v 3 for 422/444 10-/12-bit encoding
If you do not use the -profile:v option, it will be deduced
from the source format.
---
libavcodec/libvpxenc.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 95 insertions(+), 5 deletions(-)
diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c
index 176c6b6..d747e1d 100644
--- a/libavcodec/libvpxenc.c
+++ b/libavcodec/libvpxenc.c
@@ -149,12 +149,19 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx,
av_log(avctx, level, "vpx_codec_enc_cfg\n");
av_log(avctx, level, "generic settings\n"
" %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\n"
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+ " %*s%u\n %*s%u\n"
+#endif
" %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n",
width, "g_usage:", cfg->g_usage,
width, "g_threads:", cfg->g_threads,
width, "g_profile:", cfg->g_profile,
width, "g_w:", cfg->g_w,
width, "g_h:", cfg->g_h,
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+ width, "g_bit_depth:", cfg->g_bit_depth,
+ width, "g_input_bit_depth:", cfg->g_input_bit_depth,
+#endif
width, "g_timebase:", cfg->g_timebase.num, cfg->g_timebase.den,
width, "g_error_resilient:", cfg->g_error_resilient,
width, "g_pass:", cfg->g_pass,
@@ -259,6 +266,59 @@ static av_cold int vp8_free(AVCodecContext *avctx)
return 0;
}
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+static int set_pix_fmt(AVCodecContext *avctx, struct vpx_codec_enc_cfg *enccfg,
+ vpx_codec_flags_t *flags, vpx_img_fmt_t *img_fmt) {
+ if (avctx->codec_id == AV_CODEC_ID_VP8 && avctx->pix_fmt != AV_PIX_FMT_YUV420P) {
+ av_log(avctx, AV_LOG_ERROR, "Can only encode YUV420P format to VP8.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_YUV420P:
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
+ enccfg->g_profile = 0;
+ *img_fmt = VPX_IMG_FMT_I420;
+ return 0;
+ case AV_PIX_FMT_YUV422P:
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
+ enccfg->g_profile = 1;
+ *img_fmt = VPX_IMG_FMT_I422;
+ return 0;
+ case AV_PIX_FMT_YUV444P:
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
+ enccfg->g_profile = 1;
+ *img_fmt = VPX_IMG_FMT_I444;
+ return 0;
+ case AV_PIX_FMT_YUV420P10LE:
+ case AV_PIX_FMT_YUV420P12LE:
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+ avctx->pix_fmt == AV_PIX_FMT_YUV420P10LE ? 10 : 12;
+ enccfg->g_profile = 2;
+ *img_fmt = VPX_IMG_FMT_I42016;
+ *flags |= VPX_CODEC_USE_HIGHBITDEPTH;
+ return 0;
+ case AV_PIX_FMT_YUV422P10LE:
+ case AV_PIX_FMT_YUV422P12LE:
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+ avctx->pix_fmt == AV_PIX_FMT_YUV422P10LE ? 10 : 12;
+ enccfg->g_profile = 3;
+ *img_fmt = VPX_IMG_FMT_I42216;
+ *flags |= VPX_CODEC_USE_HIGHBITDEPTH;
+ return 0;
+ case AV_PIX_FMT_YUV444P10LE:
+ case AV_PIX_FMT_YUV444P12LE:
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+ avctx->pix_fmt == AV_PIX_FMT_YUV444P10LE ? 10 : 12;
+ enccfg->g_profile = 3;
+ *img_fmt = VPX_IMG_FMT_I44416;
+ *flags |= VPX_CODEC_USE_HIGHBITDEPTH;
+ return 0;
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+}
+#endif
+
static av_cold int vpx_init(AVCodecContext *avctx,
const struct vpx_codec_iface *iface)
{
@@ -267,6 +327,7 @@ static av_cold int vpx_init(AVCodecContext *avctx,
struct vpx_codec_enc_cfg enccfg_alpha;
vpx_codec_flags_t flags = (avctx->flags & CODEC_FLAG_PSNR) ? VPX_CODEC_USE_PSNR : 0;
int res;
+ vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420;
av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());
@@ -280,6 +341,14 @@ static av_cold int vpx_init(AVCodecContext *avctx,
return AVERROR(EINVAL);
}
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+ if (avctx->codec_id == AV_CODEC_ID_VP9) {
+ if (set_pix_fmt(avctx, &enccfg, &flags, &img_fmt))
+ return AVERROR(EINVAL);
+ av_log(avctx, AV_LOG_INFO, "Bit-depth: %d\n", enccfg.g_bit_depth);
+ }
+#endif
+
if(!avctx->bit_rate)
if(avctx->rc_max_rate || avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
av_log( avctx, AV_LOG_ERROR, "Rate control parameters set without a bitrate\n");
@@ -412,8 +481,10 @@ static av_cold int vpx_init(AVCodecContext *avctx,
/* 0-3: For non-zero values the encoder increasingly optimizes for reduced
complexity playback on low powered devices at the expense of encode
quality. */
- if (avctx->profile != FF_PROFILE_UNKNOWN)
- enccfg.g_profile = avctx->profile;
+ if (avctx->profile != FF_PROFILE_UNKNOWN) {
+ enccfg.g_profile = avctx->profile;
+ }
+
enccfg.g_error_resilient = ctx->error_resilient || ctx->flags & VP8F_ERROR_RESILIENT;
@@ -483,8 +554,11 @@ static av_cold int vpx_init(AVCodecContext *avctx,
av_log(avctx, AV_LOG_DEBUG, "Using deadline: %d\n", ctx->deadline);
//provide dummy value to initialize wrapper, values will be updated each _encode()
- vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
+ vpx_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1,
(unsigned char*)1);
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+ ctx->rawimg.bit_depth = enccfg.g_bit_depth;
+#endif
if (ctx->is_alpha)
vpx_img_wrap(&ctx->rawimg_alpha, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
@@ -709,7 +783,6 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt,
int64_t timestamp = 0;
int res, coded_size;
vpx_enc_frame_flags_t flags = 0;
-
if (frame) {
rawimg = &ctx->rawimg;
rawimg->planes[VPX_PLANE_Y] = frame->data[0];
@@ -744,6 +817,7 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt,
res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp,
avctx->ticks_per_frame, flags, ctx->deadline);
+
if (res != VPX_CODEC_OK) {
log_encoder_error(avctx, "Error encoding frame");
return AVERROR_INVALIDDATA;
@@ -915,7 +989,23 @@ AVCodec ff_libvpx_vp9_encoder = {
.encode2 = vp8_encode,
.close = vp8_free,
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
- .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
+#ifdef VPX_IMG_FMT_HIGHBITDEPTH
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV420P10LE,
+ AV_PIX_FMT_YUV422P10LE,
+ AV_PIX_FMT_YUV444P10LE,
+ AV_PIX_FMT_YUV420P12LE,
+ AV_PIX_FMT_YUV422P12LE,
+ AV_PIX_FMT_YUV444P12LE,
+ AV_PIX_FMT_NONE },
+#else
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_NONE },
+#endif
.priv_class = &class_vp9,
.defaults = defaults,
.init_static_data = ff_vp9_init_static,
--
2.2.0.rc0.207.ga3a616c
_______________________________________________
ffmpeg-devel mailing list
[email protected]
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel