Support for VP9 high-color/high-bit-depth encoding
Patch to support VP9 encoding with new profiles 1-3. Profile 1 (8-bit 422/444) should work with default libvpx configuration. However you will need to configure libvpx with --enable-vp9-highbitdepth before building and linking with ffmpeg for profile 2 (10-/12-bit 420) and profile 3 (10-/12-bit 422/444) 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. Signed-off-by: James Zern <jzern@google.com>
This commit is contained in:
parent
e6e8cc8ce9
commit
26a0bcb15b
@ -19,12 +19,57 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vpx/vpx_codec.h>
|
#include <vpx/vpx_codec.h>
|
||||||
|
|
||||||
#include "libvpx.h"
|
#include "libvpx.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if CONFIG_LIBVPX_VP9_ENCODER
|
||||||
|
#include <vpx/vpx_encoder.h>
|
||||||
|
#include <vpx/vp8cx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const enum AVPixelFormat vp9_pix_fmts_def[] = {
|
||||||
|
AV_PIX_FMT_YUV420P,
|
||||||
|
AV_PIX_FMT_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
#if CONFIG_LIBVPX_VP9_ENCODER
|
||||||
|
static const enum AVPixelFormat vp9_pix_fmts_highcol[] = {
|
||||||
|
AV_PIX_FMT_YUV420P,
|
||||||
|
AV_PIX_FMT_YUV422P,
|
||||||
|
AV_PIX_FMT_YUV444P,
|
||||||
|
AV_PIX_FMT_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const enum AVPixelFormat vp9_pix_fmts_highbd[] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
av_cold void ff_vp9_init_static(AVCodec *codec)
|
av_cold void ff_vp9_init_static(AVCodec *codec)
|
||||||
{
|
{
|
||||||
if ( vpx_codec_version_major() < 1
|
if ( vpx_codec_version_major() < 1
|
||||||
|| (vpx_codec_version_major() == 1 && vpx_codec_version_minor() < 3))
|
|| (vpx_codec_version_major() == 1 && vpx_codec_version_minor() < 3))
|
||||||
codec->capabilities |= CODEC_CAP_EXPERIMENTAL;
|
codec->capabilities |= CODEC_CAP_EXPERIMENTAL;
|
||||||
|
codec->pix_fmts = vp9_pix_fmts_def;
|
||||||
|
#if CONFIG_LIBVPX_VP9_ENCODER
|
||||||
|
if ( vpx_codec_version_major() > 1
|
||||||
|
|| (vpx_codec_version_major() == 1 && vpx_codec_version_minor() >= 4)) {
|
||||||
|
#ifdef VPX_CODEC_CAP_HIGHBITDEPTH
|
||||||
|
vpx_codec_caps_t codec_caps = vpx_codec_get_caps(vpx_codec_vp9_cx());
|
||||||
|
if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH)
|
||||||
|
codec->pix_fmts = vp9_pix_fmts_highbd;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
codec->pix_fmts = vp9_pix_fmts_highcol;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -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, "vpx_codec_enc_cfg\n");
|
||||||
av_log(avctx, level, "generic settings\n"
|
av_log(avctx, level, "generic settings\n"
|
||||||
" %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\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",
|
" %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n",
|
||||||
width, "g_usage:", cfg->g_usage,
|
width, "g_usage:", cfg->g_usage,
|
||||||
width, "g_threads:", cfg->g_threads,
|
width, "g_threads:", cfg->g_threads,
|
||||||
width, "g_profile:", cfg->g_profile,
|
width, "g_profile:", cfg->g_profile,
|
||||||
width, "g_w:", cfg->g_w,
|
width, "g_w:", cfg->g_w,
|
||||||
width, "g_h:", cfg->g_h,
|
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_timebase:", cfg->g_timebase.num, cfg->g_timebase.den,
|
||||||
width, "g_error_resilient:", cfg->g_error_resilient,
|
width, "g_error_resilient:", cfg->g_error_resilient,
|
||||||
width, "g_pass:", cfg->g_pass,
|
width, "g_pass:", cfg->g_pass,
|
||||||
@ -259,6 +266,66 @@ static av_cold int vp8_free(AVCodecContext *avctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_LIBVPX_VP9_ENCODER
|
||||||
|
static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps,
|
||||||
|
struct vpx_codec_enc_cfg *enccfg, vpx_codec_flags_t *flags,
|
||||||
|
vpx_img_fmt_t *img_fmt) {
|
||||||
|
#ifdef VPX_IMG_FMT_HIGHBITDEPTH
|
||||||
|
enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
|
||||||
|
#endif
|
||||||
|
switch (avctx->pix_fmt) {
|
||||||
|
case AV_PIX_FMT_YUV420P:
|
||||||
|
enccfg->g_profile = 0;
|
||||||
|
*img_fmt = VPX_IMG_FMT_I420;
|
||||||
|
return 0;
|
||||||
|
case AV_PIX_FMT_YUV422P:
|
||||||
|
case AV_PIX_FMT_YUV444P:
|
||||||
|
enccfg->g_profile = 1;
|
||||||
|
*img_fmt = avctx->pix_fmt == AV_PIX_FMT_YUV422P ? VPX_IMG_FMT_I422 : VPX_IMG_FMT_I444;
|
||||||
|
return 0;
|
||||||
|
#ifdef VPX_IMG_FMT_HIGHBITDEPTH
|
||||||
|
case AV_PIX_FMT_YUV420P10LE:
|
||||||
|
case AV_PIX_FMT_YUV420P12LE:
|
||||||
|
if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AV_PIX_FMT_YUV422P10LE:
|
||||||
|
case AV_PIX_FMT_YUV422P12LE:
|
||||||
|
if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AV_PIX_FMT_YUV444P10LE:
|
||||||
|
case AV_PIX_FMT_YUV444P12LE:
|
||||||
|
if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static av_cold int vpx_init(AVCodecContext *avctx,
|
static av_cold int vpx_init(AVCodecContext *avctx,
|
||||||
const struct vpx_codec_iface *iface)
|
const struct vpx_codec_iface *iface)
|
||||||
{
|
{
|
||||||
@ -267,6 +334,10 @@ static av_cold int vpx_init(AVCodecContext *avctx,
|
|||||||
struct vpx_codec_enc_cfg enccfg_alpha;
|
struct vpx_codec_enc_cfg enccfg_alpha;
|
||||||
vpx_codec_flags_t flags = (avctx->flags & CODEC_FLAG_PSNR) ? VPX_CODEC_USE_PSNR : 0;
|
vpx_codec_flags_t flags = (avctx->flags & CODEC_FLAG_PSNR) ? VPX_CODEC_USE_PSNR : 0;
|
||||||
int res;
|
int res;
|
||||||
|
vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420;
|
||||||
|
#if CONFIG_LIBVPX_VP9_ENCODER
|
||||||
|
vpx_codec_caps_t codec_caps = vpx_codec_get_caps(iface);
|
||||||
|
#endif
|
||||||
|
|
||||||
av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
|
av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
|
||||||
av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());
|
av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());
|
||||||
@ -280,6 +351,13 @@ static av_cold int vpx_init(AVCodecContext *avctx,
|
|||||||
return AVERROR(EINVAL);
|
return AVERROR(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_LIBVPX_VP9_ENCODER
|
||||||
|
if (avctx->codec_id == AV_CODEC_ID_VP9) {
|
||||||
|
if (set_pix_fmt(avctx, codec_caps, &enccfg, &flags, &img_fmt))
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!avctx->bit_rate)
|
if(!avctx->bit_rate)
|
||||||
if(avctx->rc_max_rate || avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
|
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");
|
av_log( avctx, AV_LOG_ERROR, "Rate control parameters set without a bitrate\n");
|
||||||
@ -483,8 +561,12 @@ static av_cold int vpx_init(AVCodecContext *avctx,
|
|||||||
av_log(avctx, AV_LOG_DEBUG, "Using deadline: %d\n", ctx->deadline);
|
av_log(avctx, AV_LOG_DEBUG, "Using deadline: %d\n", ctx->deadline);
|
||||||
|
|
||||||
//provide dummy value to initialize wrapper, values will be updated each _encode()
|
//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);
|
(unsigned char*)1);
|
||||||
|
#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
|
||||||
|
if (avctx->codec_id == AV_CODEC_ID_VP9 && (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH))
|
||||||
|
ctx->rawimg.bit_depth = enccfg.g_bit_depth;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ctx->is_alpha)
|
if (ctx->is_alpha)
|
||||||
vpx_img_wrap(&ctx->rawimg_alpha, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
|
vpx_img_wrap(&ctx->rawimg_alpha, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
|
||||||
@ -915,7 +997,6 @@ AVCodec ff_libvpx_vp9_encoder = {
|
|||||||
.encode2 = vp8_encode,
|
.encode2 = vp8_encode,
|
||||||
.close = vp8_free,
|
.close = vp8_free,
|
||||||
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
|
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
|
||||||
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
|
|
||||||
.priv_class = &class_vp9,
|
.priv_class = &class_vp9,
|
||||||
.defaults = defaults,
|
.defaults = defaults,
|
||||||
.init_static_data = ff_vp9_init_static,
|
.init_static_data = ff_vp9_init_static,
|
||||||
|
Loading…
Reference in New Issue
Block a user