av1enc: Add to configure image formats

Expanded to support image format to YV12/I422/I444. It's related to the
color bit-depth and profile of the codec. It can make configuring
appropriate profile according to bit-depth and format.

https://bugzilla.gnome.org/show_bug.cgi?id=791674
This commit is contained in:
Wonchul Lee 2018-10-07 16:19:03 +09:00 committed by Olivier Crête
parent cc9d65a512
commit 51d5db3f47
3 changed files with 92 additions and 3 deletions

View file

@ -198,7 +198,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw, " GST_STATIC_CAPS ("video/x-raw, "
"format = (string) \"I420\", " "format = (string) { I420, Y42B, Y444, YV12 }, "
"framerate = (fraction) [0, MAX], " "framerate = (fraction) [0, MAX], "
"width = (int) [ 4, MAX ], " "width = (int) [ 4, MAX ], "
"height = (int) [ 4, MAX ]") "height = (int) [ 4, MAX ]")
@ -382,6 +382,7 @@ gst_av1_enc_init (GstAV1Enc * av1enc)
av1enc->keyframe_dist = 30; av1enc->keyframe_dist = 30;
av1enc->cpu_used = DEFAULT_CPU_USED; av1enc->cpu_used = DEFAULT_CPU_USED;
av1enc->format = AOM_IMG_FMT_I420;
av1enc->aom_cfg.rc_dropframe_thresh = DEFAULT_DROP_FRAME; av1enc->aom_cfg.rc_dropframe_thresh = DEFAULT_DROP_FRAME;
av1enc->aom_cfg.rc_resize_mode = DEFAULT_RESIZE_MODE; av1enc->aom_cfg.rc_resize_mode = DEFAULT_RESIZE_MODE;
@ -404,7 +405,7 @@ gst_av1_enc_init (GstAV1Enc * av1enc)
av1enc->aom_cfg.g_timebase.num = DEFAULT_TIMEBASE_N; av1enc->aom_cfg.g_timebase.num = DEFAULT_TIMEBASE_N;
av1enc->aom_cfg.g_timebase.den = DEFAULT_TIMEBASE_D; av1enc->aom_cfg.g_timebase.den = DEFAULT_TIMEBASE_D;
av1enc->aom_cfg.g_bit_depth = DEFAULT_BIT_DEPTH; av1enc->aom_cfg.g_bit_depth = DEFAULT_BIT_DEPTH;
av1enc->aom_cfg.g_input_bit_depth = (int) DEFAULT_BIT_DEPTH; av1enc->aom_cfg.g_input_bit_depth = (unsigned int) DEFAULT_BIT_DEPTH;
g_mutex_init (&av1enc->encoder_lock); g_mutex_init (&av1enc->encoder_lock);
} }
@ -552,6 +553,54 @@ gst_av1_enc_get_downstream_profile (GstAV1Enc * av1enc)
return profile; return profile;
} }
static void
gst_av1_enc_adjust_profile (GstAV1Enc * av1enc, GstVideoFormat format)
{
guint depth = av1enc->aom_cfg.g_bit_depth;
guint profile = av1enc->aom_cfg.g_profile;
gboolean update = FALSE;
switch (profile) {
case 0:
if (depth < 12 && format == GST_VIDEO_FORMAT_Y444) {
profile = 1;
update = TRUE;
} else if (depth == 12 || format == GST_VIDEO_FORMAT_Y42B) {
profile = 2;
update = TRUE;
}
break;
case 1:
if (depth == 12 || format == GST_VIDEO_FORMAT_Y42B) {
profile = 2;
update = TRUE;
} else if (depth < 12 && format == GST_VIDEO_FORMAT_I420) {
profile = 0;
update = TRUE;
}
break;
case 2:
if (depth < 12) {
if (format == GST_VIDEO_FORMAT_Y444) {
profile = 1;
update = TRUE;
} else if (format == GST_VIDEO_FORMAT_I420) {
profile = 0;
update = TRUE;
}
}
break;
default:
break;
}
if (update) {
GST_INFO_OBJECT (av1enc, "profile updated to %d from %d",
profile, av1enc->aom_cfg.g_profile);
av1enc->aom_cfg.g_profile = profile;
}
}
static gboolean static gboolean
gst_av1_enc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) gst_av1_enc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
{ {
@ -591,6 +640,18 @@ gst_av1_enc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
av1enc->aom_cfg.g_error_resilient = AOM_ERROR_RESILIENT_DEFAULT; av1enc->aom_cfg.g_error_resilient = AOM_ERROR_RESILIENT_DEFAULT;
/* TODO: do more configuration including bit_depth config */ /* TODO: do more configuration including bit_depth config */
av1enc->format =
gst_video_format_to_av1_img_format (GST_VIDEO_INFO_FORMAT (info));
if (av1enc->aom_cfg.g_bit_depth != DEFAULT_BIT_DEPTH) {
av1enc->aom_cfg.g_input_bit_depth = av1enc->aom_cfg.g_bit_depth;
if (av1enc->aom_cfg.g_bit_depth > 8)
av1enc->format |= AOM_IMG_FMT_HIGHBITDEPTH;
}
/* Adjust profile according to format and bit-depth */
gst_av1_enc_adjust_profile (av1enc, GST_VIDEO_INFO_FORMAT (info));
GST_DEBUG_OBJECT (av1enc, "Calling encoder init with config:"); GST_DEBUG_OBJECT (av1enc, "Calling encoder init with config:");
gst_av1_enc_debug_encoder_cfg (&av1enc->aom_cfg); gst_av1_enc_debug_encoder_cfg (&av1enc->aom_cfg);
@ -672,7 +733,7 @@ gst_av1_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstVideoFrame vframe; GstVideoFrame vframe;
if (!aom_img_alloc (&raw, AOM_IMG_FMT_I420, av1enc->aom_cfg.g_w, if (!aom_img_alloc (&raw, av1enc->format, av1enc->aom_cfg.g_w,
av1enc->aom_cfg.g_h, 1)) { av1enc->aom_cfg.g_h, 1)) {
GST_ERROR_OBJECT (encoder, "Failed to initialize encoder"); GST_ERROR_OBJECT (encoder, "Failed to initialize encoder");
return FALSE; return FALSE;

View file

@ -23,6 +23,19 @@
#include "gstav1utils.h" #include "gstav1utils.h"
typedef struct
{
enum aom_img_fmt aom_format;
GstVideoFormat gst_format;
} AomImageFormat;
static const AomImageFormat img_formats[] = {
{AOM_IMG_FMT_YV12, GST_VIDEO_FORMAT_YV12},
{AOM_IMG_FMT_I420, GST_VIDEO_FORMAT_I420},
{AOM_IMG_FMT_I422, GST_VIDEO_FORMAT_Y42B},
{AOM_IMG_FMT_I444, GST_VIDEO_FORMAT_Y444},
};
const char * const char *
gst_av1_get_error_name (aom_codec_err_t status) gst_av1_get_error_name (aom_codec_err_t status)
{ {
@ -49,3 +62,16 @@ gst_av1_get_error_name (aom_codec_err_t status)
return "unknown"; return "unknown";
} }
} }
gint
gst_video_format_to_av1_img_format (GstVideoFormat format)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (img_formats); i++)
if (img_formats[i].gst_format == format)
return img_formats[i].aom_format;
GST_WARNING ("av1 img format not found");
return -1;
}

View file

@ -18,11 +18,13 @@
*/ */
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/video/video.h>
#include <aom/aom_codec.h> #include <aom/aom_codec.h>
G_BEGIN_DECLS G_BEGIN_DECLS
const char *gst_av1_get_error_name (aom_codec_err_t status); const char *gst_av1_get_error_name (aom_codec_err_t status);
gint gst_video_format_to_av1_img_format (GstVideoFormat format);
G_END_DECLS G_END_DECLS