diff --git a/sys/mediafoundation/gstmfh264enc.cpp b/sys/mediafoundation/gstmfh264enc.cpp index 2babe40ffb..c672eb3fb3 100644 --- a/sys/mediafoundation/gstmfh264enc.cpp +++ b/sys/mediafoundation/gstmfh264enc.cpp @@ -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); } diff --git a/sys/mediafoundation/gstmfh265enc.cpp b/sys/mediafoundation/gstmfh265enc.cpp index e2b9de56b2..95c87b675c 100644 --- a/sys/mediafoundation/gstmfh265enc.cpp +++ b/sys/mediafoundation/gstmfh265enc.cpp @@ -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); } diff --git a/sys/mediafoundation/gstmfvideoenc.cpp b/sys/mediafoundation/gstmfvideoenc.cpp index fd24af215e..372b946805 100644 --- a/sys/mediafoundation/gstmfvideoenc.cpp +++ b/sys/mediafoundation/gstmfvideoenc.cpp @@ -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; } diff --git a/sys/mediafoundation/gstmfvideoenc.h b/sys/mediafoundation/gstmfvideoenc.h index 3b8a2c2074..afc2e66c91 100644 --- a/sys/mediafoundation/gstmfvideoenc.h +++ b/sys/mediafoundation/gstmfvideoenc.h @@ -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, diff --git a/sys/mediafoundation/gstmfvp9enc.cpp b/sys/mediafoundation/gstmfvp9enc.cpp index 20f4fd79ab..673326cb13 100644 --- a/sys/mediafoundation/gstmfvp9enc.cpp +++ b/sys/mediafoundation/gstmfvp9enc.cpp @@ -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); }