mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
mfvideoenc: Re-define default GOP size value
The behavior for zero AVEncMPVGOPSize value would be varying depending on GPU vendor implementation and some GPU will produce keyframe only once at the beginning of encoding. That's unlikely expected result for users. To make this property behave consistently among various GPUs, this commit will change default value of "gop-size" property to -1 which means "auto". When "gop-size" is unspecified, then mfvideoenc will calculate GOP size based on framerate like that of our x264enc implementation. See also https://docs.microsoft.com/en-us/windows/win32/directshow/avencmpvgopsize-property Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1911>
This commit is contained in:
parent
8df131ab42
commit
e82f1f8b0b
5 changed files with 90 additions and 30 deletions
|
@ -167,7 +167,7 @@ enum
|
|||
#define DEFAULT_SPS_ID 0
|
||||
#define DEFAULT_PPS_ID 0
|
||||
#define DEFAULT_BFRAMES 0
|
||||
#define DEFAULT_GOP_SIZE 0
|
||||
#define DEFAULT_GOP_SIZE -1
|
||||
#define DEFAULT_THREADS 0
|
||||
#define DEFAULT_CONTENT_TYPE GST_MF_H264_ENC_CONTENT_TYPE_UNKNOWN
|
||||
#define DEFAULT_QP 24
|
||||
|
@ -197,7 +197,7 @@ typedef struct _GstMFH264Enc
|
|||
guint sps_id;
|
||||
guint pps_id;
|
||||
guint bframes;
|
||||
guint gop_size;
|
||||
gint gop_size;
|
||||
guint threads;
|
||||
guint content_type;
|
||||
guint qp;
|
||||
|
@ -222,7 +222,7 @@ static void gst_mf_h264_enc_get_property (GObject * object, guint prop_id,
|
|||
static void gst_mf_h264_enc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static gboolean gst_mf_h264_enc_set_option (GstMFVideoEnc * mfenc,
|
||||
IMFMediaType * output_type);
|
||||
GstVideoCodecState * state, IMFMediaType * output_type);
|
||||
static gboolean gst_mf_h264_enc_set_src_caps (GstMFVideoEnc * mfenc,
|
||||
GstVideoCodecState * state, IMFMediaType * output_type);
|
||||
|
||||
|
@ -354,9 +354,11 @@ gst_mf_h264_enc_class_init (GstMFH264EncClass * klass, gpointer data)
|
|||
|
||||
if (device_caps->gop_size) {
|
||||
g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
|
||||
g_param_spec_uint ("gop-size", "GOP size",
|
||||
"The number of pictures from one GOP header to the next, "
|
||||
"(0 = MFT default)", 0, G_MAXUINT - 1, DEFAULT_GOP_SIZE,
|
||||
g_param_spec_int ("gop-size", "GOP size",
|
||||
"The number of pictures from one GOP header to the next. "
|
||||
"Depending on GPU vendor implementation, zero gop-size might "
|
||||
"produce only one keyframe at the beginning (-1 for automatic)",
|
||||
-1, G_MAXINT, DEFAULT_GOP_SIZE,
|
||||
(GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
}
|
||||
|
@ -553,7 +555,7 @@ gst_mf_h264_enc_get_property (GObject * object, guint prop_id,
|
|||
g_value_set_uint (value, self->bframes);
|
||||
break;
|
||||
case PROP_GOP_SIZE:
|
||||
g_value_set_uint (value, self->gop_size);
|
||||
g_value_set_int (value, self->gop_size);
|
||||
break;
|
||||
case PROP_THREADS:
|
||||
g_value_set_uint (value, self->threads);
|
||||
|
@ -632,7 +634,7 @@ gst_mf_h264_enc_set_property (GObject * object, guint prop_id,
|
|||
self->bframes = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_GOP_SIZE:
|
||||
self->gop_size = g_value_get_uint (value);
|
||||
self->gop_size = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_THREADS:
|
||||
self->threads = g_value_get_uint (value);
|
||||
|
@ -721,7 +723,8 @@ gst_mf_h264_enc_content_type_to_enum (guint rc_mode)
|
|||
} G_STMT_END
|
||||
|
||||
static gboolean
|
||||
gst_mf_h264_enc_set_option (GstMFVideoEnc * mfenc, IMFMediaType * output_type)
|
||||
gst_mf_h264_enc_set_option (GstMFVideoEnc * mfenc, GstVideoCodecState * state,
|
||||
IMFMediaType * output_type)
|
||||
{
|
||||
GstMFH264Enc *self = (GstMFH264Enc *) mfenc;
|
||||
GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (mfenc);
|
||||
|
@ -863,8 +866,25 @@ gst_mf_h264_enc_set_option (GstMFVideoEnc * mfenc, IMFMediaType * output_type)
|
|||
}
|
||||
|
||||
if (device_caps->gop_size) {
|
||||
GstVideoInfo *info = &state->info;
|
||||
gint gop_size = self->gop_size;
|
||||
gint fps_n, fps_d;
|
||||
|
||||
/* Set default value (10 sec or 250 frames) like that of x264enc */
|
||||
if (gop_size < 0) {
|
||||
fps_n = GST_VIDEO_INFO_FPS_N (info);
|
||||
fps_d = GST_VIDEO_INFO_FPS_D (info);
|
||||
if (fps_n <= 0 || fps_d <= 0) {
|
||||
gop_size = 250;
|
||||
} else {
|
||||
gop_size = 10 * fps_n / fps_d;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Update GOP size to %d", gop_size);
|
||||
}
|
||||
|
||||
hr = gst_mf_transform_set_codec_api_uint32 (transform,
|
||||
&CODECAPI_AVEncMPVGOPSize, self->gop_size);
|
||||
&CODECAPI_AVEncMPVGOPSize, gop_size);
|
||||
WARNING_HR (hr, CODECAPI_AVEncMPVGOPSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ enum
|
|||
#define DEFAULT_QUALITY_VS_SPEED 50
|
||||
#define DEFAULT_CABAC TRUE
|
||||
#define DEFAULT_BFRAMES 0
|
||||
#define DEFAULT_GOP_SIZE 0
|
||||
#define DEFAULT_GOP_SIZE -1
|
||||
#define DEFAULT_THREADS 0
|
||||
#define DEFAULT_CONTENT_TYPE GST_MF_H265_ENC_CONTENT_TYPE_UNKNOWN
|
||||
#define DEFAULT_QP 24
|
||||
|
@ -174,7 +174,7 @@ static void gst_mf_h265_enc_get_property (GObject * object, guint prop_id,
|
|||
static void gst_mf_h265_enc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static gboolean gst_mf_h265_enc_set_option (GstMFVideoEnc * mfenc,
|
||||
IMFMediaType * output_type);
|
||||
GstVideoCodecState * state, IMFMediaType * output_type);
|
||||
static gboolean gst_mf_h265_enc_set_src_caps (GstMFVideoEnc * mfenc,
|
||||
GstVideoCodecState * state, IMFMediaType * output_type);
|
||||
|
||||
|
@ -253,9 +253,11 @@ gst_mf_h265_enc_class_init (GstMFH265EncClass * klass, gpointer data)
|
|||
|
||||
if (device_caps->gop_size) {
|
||||
g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
|
||||
g_param_spec_uint ("gop-size", "GOP size",
|
||||
"The number of pictures from one GOP header to the next, "
|
||||
"(0 = MFT default)", 0, G_MAXUINT - 1, DEFAULT_GOP_SIZE,
|
||||
g_param_spec_int ("gop-size", "GOP size",
|
||||
"The number of pictures from one GOP header to the next. "
|
||||
"Depending on GPU vendor implementation, zero gop-size might "
|
||||
"produce only one keyframe at the beginning (-1 for automatic)",
|
||||
-1, G_MAXINT, DEFAULT_GOP_SIZE,
|
||||
(GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
}
|
||||
|
@ -430,7 +432,7 @@ gst_mf_h265_enc_get_property (GObject * object, guint prop_id,
|
|||
g_value_set_uint (value, self->bframes);
|
||||
break;
|
||||
case PROP_GOP_SIZE:
|
||||
g_value_set_uint (value, self->gop_size);
|
||||
g_value_set_int (value, self->gop_size);
|
||||
break;
|
||||
case PROP_THREADS:
|
||||
g_value_set_uint (value, self->threads);
|
||||
|
@ -494,7 +496,7 @@ gst_mf_h265_enc_set_property (GObject * object, guint prop_id,
|
|||
self->bframes = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_GOP_SIZE:
|
||||
self->gop_size = g_value_get_uint (value);
|
||||
self->gop_size = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_THREADS:
|
||||
self->threads = g_value_get_uint (value);
|
||||
|
@ -566,7 +568,8 @@ gst_mf_h265_enc_content_type_to_enum (guint rc_mode)
|
|||
} G_STMT_END
|
||||
|
||||
static gboolean
|
||||
gst_mf_h265_enc_set_option (GstMFVideoEnc * mfenc, IMFMediaType * output_type)
|
||||
gst_mf_h265_enc_set_option (GstMFVideoEnc * mfenc, GstVideoCodecState * state,
|
||||
IMFMediaType * output_type)
|
||||
{
|
||||
GstMFH265Enc *self = (GstMFH265Enc *) mfenc;
|
||||
GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (mfenc);
|
||||
|
@ -632,8 +635,25 @@ gst_mf_h265_enc_set_option (GstMFVideoEnc * mfenc, IMFMediaType * output_type)
|
|||
}
|
||||
|
||||
if (device_caps->gop_size) {
|
||||
GstVideoInfo *info = &state->info;
|
||||
gint gop_size = self->gop_size;
|
||||
gint fps_n, fps_d;
|
||||
|
||||
/* Set default value (10 sec or 250 frames) like that of x264enc */
|
||||
if (gop_size < 0) {
|
||||
fps_n = GST_VIDEO_INFO_FPS_N (info);
|
||||
fps_d = GST_VIDEO_INFO_FPS_D (info);
|
||||
if (fps_n <= 0 || fps_d <= 0) {
|
||||
gop_size = 250;
|
||||
} else {
|
||||
gop_size = 10 * fps_n / fps_d;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Update GOP size to %d", gop_size);
|
||||
}
|
||||
|
||||
hr = gst_mf_transform_set_codec_api_uint32 (transform,
|
||||
&CODECAPI_AVEncMPVGOPSize, self->gop_size);
|
||||
&CODECAPI_AVEncMPVGOPSize, gop_size);
|
||||
WARNING_HR (hr, CODECAPI_AVEncMPVGOPSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ gst_mf_video_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state)
|
|||
return FALSE;
|
||||
|
||||
if (klass->set_option) {
|
||||
if (!klass->set_option (self, out_type.Get ())) {
|
||||
if (!klass->set_option (self, self->input_state, out_type.Get ())) {
|
||||
GST_ERROR_OBJECT (self, "subclass failed to set option");
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ struct _GstMFVideoEncClass
|
|||
GstMFVideoEncDeviceCaps device_caps;
|
||||
|
||||
gboolean (*set_option) (GstMFVideoEnc * mfenc,
|
||||
GstVideoCodecState * state,
|
||||
IMFMediaType * output_type);
|
||||
|
||||
gboolean (*set_src_caps) (GstMFVideoEnc * mfenc,
|
||||
|
|
|
@ -111,7 +111,7 @@ enum
|
|||
#define DEFAULT_RC_MODE GST_MF_VP9_ENC_RC_MODE_CBR
|
||||
#define DEFAULT_MAX_BITRATE 0
|
||||
#define DEFAULT_QUALITY_VS_SPEED 50
|
||||
#define DEFAULT_GOP_SIZE 0
|
||||
#define DEFAULT_GOP_SIZE -1
|
||||
#define DEFAULT_THREADS 0
|
||||
#define DEFAULT_CONTENT_TYPE GST_MF_VP9_ENC_CONTENT_TYPE_UNKNOWN
|
||||
#define DEFAULT_LOW_LATENCY FALSE
|
||||
|
@ -145,7 +145,7 @@ static void gst_mf_vp9_enc_get_property (GObject * object, guint prop_id,
|
|||
static void gst_mf_vp9_enc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static gboolean gst_mf_vp9_enc_set_option (GstMFVideoEnc * mfenc,
|
||||
IMFMediaType * output_type);
|
||||
GstVideoCodecState * state, IMFMediaType * output_type);
|
||||
static gboolean gst_mf_vp9_enc_set_src_caps (GstMFVideoEnc * mfenc,
|
||||
GstVideoCodecState * state, IMFMediaType * output_type);
|
||||
|
||||
|
@ -207,10 +207,11 @@ gst_mf_vp9_enc_class_init (GstMFVP9EncClass * klass, gpointer data)
|
|||
|
||||
if (device_caps->gop_size) {
|
||||
g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
|
||||
g_param_spec_uint ("gop-size", "GOP size",
|
||||
"The number of pictures from one GOP header to the next, "
|
||||
"(0 = MFT default)", 0, G_MAXUINT - 1,
|
||||
DEFAULT_GOP_SIZE,
|
||||
g_param_spec_int ("gop-size", "GOP size",
|
||||
"The number of pictures from one GOP header to the next. "
|
||||
"Depending on GPU vendor implementation, zero gop-size might "
|
||||
"produce only one keyframe at the beginning (-1 for automatic)",
|
||||
-1, G_MAXINT, DEFAULT_GOP_SIZE,
|
||||
(GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
}
|
||||
|
@ -314,7 +315,7 @@ gst_mf_vp9_enc_get_property (GObject * object, guint prop_id,
|
|||
g_value_set_uint (value, self->quality_vs_speed);
|
||||
break;
|
||||
case PROP_GOP_SIZE:
|
||||
g_value_set_uint (value, self->gop_size);
|
||||
g_value_set_int (value, self->gop_size);
|
||||
break;
|
||||
case PROP_THREADS:
|
||||
g_value_set_uint (value, self->threads);
|
||||
|
@ -351,7 +352,7 @@ gst_mf_vp9_enc_set_property (GObject * object, guint prop_id,
|
|||
self->quality_vs_speed = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_GOP_SIZE:
|
||||
self->gop_size = g_value_get_uint (value);
|
||||
self->gop_size = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_THREADS:
|
||||
self->threads = g_value_get_uint (value);
|
||||
|
@ -402,7 +403,8 @@ gst_mf_vp9_enc_content_type_to_enum (guint rc_mode)
|
|||
} G_STMT_END
|
||||
|
||||
static gboolean
|
||||
gst_mf_vp9_enc_set_option (GstMFVideoEnc * mfenc, IMFMediaType * output_type)
|
||||
gst_mf_vp9_enc_set_option (GstMFVideoEnc * mfenc, GstVideoCodecState * state,
|
||||
IMFMediaType * output_type)
|
||||
{
|
||||
GstMFVP9Enc *self = (GstMFVP9Enc *) mfenc;
|
||||
GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (mfenc);
|
||||
|
@ -447,8 +449,25 @@ gst_mf_vp9_enc_set_option (GstMFVideoEnc * mfenc, IMFMediaType * output_type)
|
|||
}
|
||||
|
||||
if (device_caps->gop_size) {
|
||||
GstVideoInfo *info = &state->info;
|
||||
gint gop_size = self->gop_size;
|
||||
gint fps_n, fps_d;
|
||||
|
||||
/* Set default value (10 sec or 250 frames) like that of x264enc */
|
||||
if (gop_size < 0) {
|
||||
fps_n = GST_VIDEO_INFO_FPS_N (info);
|
||||
fps_d = GST_VIDEO_INFO_FPS_D (info);
|
||||
if (fps_n <= 0 || fps_d <= 0) {
|
||||
gop_size = 250;
|
||||
} else {
|
||||
gop_size = 10 * fps_n / fps_d;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Update GOP size to %d", gop_size);
|
||||
}
|
||||
|
||||
hr = gst_mf_transform_set_codec_api_uint32 (transform,
|
||||
&CODECAPI_AVEncMPVGOPSize, self->gop_size);
|
||||
&CODECAPI_AVEncMPVGOPSize, gop_size);
|
||||
WARNING_HR (hr, CODECAPI_AVEncMPVGOPSize);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue