From 8788ea99a87c61d48ce1f411f49b4b9c1489fc66 Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Fri, 10 Jan 2014 12:01:51 +0100 Subject: [PATCH] encoder: improve codec reconfiguration. Improve codec reconfiguration to be performed only through a single function. That is, remove the _set_context_info() hook as subclass should not alter the parent GstVaapiContextInfo itself. Besides, the VA context is constructed only at the final stages of reconfigure(). --- gst-libs/gst/vaapi/gstvaapiencoder.c | 7 +- gst-libs/gst/vaapi/gstvaapiencoder_h264.c | 82 ++++++++++++---------- gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c | 67 ++++++++++-------- gst-libs/gst/vaapi/gstvaapiencoder_priv.h | 5 +- 4 files changed, 86 insertions(+), 75 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.c b/gst-libs/gst/vaapi/gstvaapiencoder.c index 7d194580ac..d629da1ade 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder.c @@ -443,16 +443,14 @@ error_invalid_framerate: static void set_context_info (GstVaapiEncoder * encoder) { - GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); GstVaapiContextInfo *const cip = &encoder->context_info; - cip->profile = GST_VAAPI_PROFILE_UNKNOWN; + cip->profile = encoder->profile; cip->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE; cip->rc_mode = GST_VAAPI_ENCODER_RATE_CONTROL (encoder); cip->width = GST_VAAPI_ENCODER_WIDTH (encoder); cip->height = GST_VAAPI_ENCODER_HEIGHT (encoder); - cip->ref_frames = 0; - klass->set_context_info (encoder); + cip->ref_frames = encoder->num_ref_frames; } /* Ensures the underlying VA context for encoding is created */ @@ -827,7 +825,6 @@ gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display) CHECK_VTABLE_HOOK (encode); CHECK_VTABLE_HOOK (reordering); CHECK_VTABLE_HOOK (flush); - CHECK_VTABLE_HOOK (set_context_info); #undef CHECK_VTABLE_HOOK diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c index e2323a78ee..ad79f7c54c 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c @@ -1248,16 +1248,43 @@ ensure_misc (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) return TRUE; } -gboolean -init_encoder_public_attributes (GstVaapiEncoderH264 * encoder) +static gboolean +ensure_profile_and_level (GstVaapiEncoderH264 * encoder) { - GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); - guint width_mbs, height_mbs, total_mbs; - if (!encoder->profile) encoder->profile = GST_VAAPI_ENCODER_H264_DEFAULT_PROFILE; _set_level (encoder); + return TRUE; +} + +static gboolean +ensure_bitrate (GstVaapiEncoderH264 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + + /* Default compression: 64 bits per macroblock */ + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + case GST_VAAPI_RATECONTROL_VBR: + case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED: + if (!base_encoder->bitrate) + base_encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) * + GST_VAAPI_ENCODER_HEIGHT (encoder) * + GST_VAAPI_ENCODER_FPS_N (encoder) / + GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024; + break; + default: + base_encoder->bitrate = 0; + break; + } + return TRUE; +} + +static void +reset_properties (GstVaapiEncoderH264 * encoder) +{ + guint width_mbs, height_mbs, total_mbs; if (encoder->intra_period > GST_VAAPI_ENCODER_H264_MAX_INTRA_PERIOD) encoder->intra_period = GST_VAAPI_ENCODER_H264_MAX_INTRA_PERIOD; @@ -1272,19 +1299,6 @@ init_encoder_public_attributes (GstVaapiEncoderH264 * encoder) encoder->min_qp < encoder->init_qp)) encoder->min_qp = encoder->init_qp; - /* default compress ratio 1: (4*8*1.5) */ - if (GST_VAAPI_RATECONTROL_CBR == GST_VAAPI_ENCODER_RATE_CONTROL (encoder) || - GST_VAAPI_RATECONTROL_VBR == GST_VAAPI_ENCODER_RATE_CONTROL (encoder) || - GST_VAAPI_RATECONTROL_VBR_CONSTRAINED == - GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { - if (!base_encoder->bitrate) - base_encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) * - GST_VAAPI_ENCODER_HEIGHT (encoder) * - GST_VAAPI_ENCODER_FPS_N (encoder) / - GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024; - } else - base_encoder->bitrate = 0; - width_mbs = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16; height_mbs = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16; total_mbs = width_mbs * height_mbs; @@ -1299,12 +1313,6 @@ init_encoder_public_attributes (GstVaapiEncoderH264 * encoder) if (encoder->b_frame_num > 50) encoder->b_frame_num = 50; - return TRUE; -} - -static gboolean -init_encoder_private_attributes (GstVaapiEncoderH264 * encoder) -{ if (encoder->b_frame_num) encoder->cts_offset = GST_SECOND * GST_VAAPI_ENCODER_FPS_D (encoder) / GST_VAAPI_ENCODER_FPS_N (encoder); @@ -1327,7 +1335,6 @@ init_encoder_private_attributes (GstVaapiEncoderH264 * encoder) encoder->max_reflist1_count = 0; encoder->max_ref_num = encoder->max_reflist0_count + encoder->max_reflist1_count; - return TRUE; } @@ -1572,10 +1579,10 @@ end: } static void -gst_vaapi_encoder_h264_set_context_info (GstVaapiEncoder * base_encoder) +set_context_info (GstVaapiEncoder * base_encoder) { GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); - GstVaapiContextInfo *const cip = &base_encoder->context_info; + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); const guint DEFAULT_SURFACES_COUNT = 3; /* Maximum sizes for common headers (in bits) */ @@ -1588,14 +1595,15 @@ gst_vaapi_encoder_h264_set_context_info (GstVaapiEncoder * base_encoder) MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402, }; - cip->profile = encoder->profile; - cip->ref_frames = (encoder->b_frame_num ? 2 : 1) + DEFAULT_SURFACES_COUNT; + base_encoder->profile = encoder->profile; + base_encoder->num_ref_frames = + (encoder->b_frame_num ? 2 : 1) + DEFAULT_SURFACES_COUNT; /* Only YUV 4:2:0 formats are supported for now. This means that we have a limit of 3200 bits per macroblock. */ /* XXX: check profile and compute RawMbBits */ - base_encoder->codedbuf_size = (GST_ROUND_UP_16 (cip->width) * - GST_ROUND_UP_16 (cip->height) / 256) * 400; + base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) / 256) * 400; /* Account for SPS header */ /* XXX: exclude scaling lists, MVC/SVC extensions */ @@ -1617,15 +1625,13 @@ gst_vaapi_encoder_h264_reconfigure (GstVaapiEncoder * base_encoder) GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264_CAST (base_encoder); - if (!init_encoder_public_attributes (encoder)) { - GST_WARNING ("encoder ensure public attributes failed "); + if (!ensure_profile_and_level (encoder)) + goto error; + if (!ensure_bitrate (encoder)) goto error; - } - if (!init_encoder_private_attributes (encoder)) { - GST_WARNING ("prepare encoding failed "); - goto error; - } + reset_properties (encoder); + set_context_info (base_encoder); return GST_VAAPI_ENCODER_STATUS_SUCCESS; error: diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c index 047289b4b8..1c9f6a229f 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c @@ -103,34 +103,35 @@ ensure_sampling_desity (GstVaapiEncoderMpeg2 * encoder) } static gboolean -ensure_public_attributes (GstVaapiEncoderMpeg2 * encoder) +ensure_profile_and_level (GstVaapiEncoderMpeg2 * encoder) { - GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); - - if (encoder->ip_period > encoder->intra_period) { - encoder->ip_period = encoder->intra_period - 1; - } - if (encoder->profile == GST_ENCODER_MPEG2_PROFILE_SIMPLE) { /* no b frames */ encoder->ip_period = 0; /* only main level is defined in mpeg2 */ encoder->level = GST_VAAPI_ENCODER_MPEG2_LEVEL_MAIN; } + return TRUE; +} - if (!ensure_sampling_desity (encoder)) - return FALSE; - - /* default compress ratio 1: (4*8*1.5) */ - if (GST_VAAPI_RATECONTROL_CBR == GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { - if (!base_encoder->bitrate) - base_encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) * - GST_VAAPI_ENCODER_HEIGHT (encoder) * - GST_VAAPI_ENCODER_FPS_N (encoder) / - GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024; - } else - base_encoder->bitrate = 0; +static gboolean +ensure_bitrate (GstVaapiEncoderMpeg2 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + /* Default compression: 64 bits per macroblock */ + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + if (!base_encoder->bitrate) + base_encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) * + GST_VAAPI_ENCODER_HEIGHT (encoder) * + GST_VAAPI_ENCODER_FPS_N (encoder) / + GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024; + break; + default: + base_encoder->bitrate = 0; + break; + } return TRUE; } @@ -636,10 +637,10 @@ to_vaapi_profile (guint32 profile) } static void -gst_vaapi_encoder_mpeg2_set_context_info (GstVaapiEncoder * base_encoder) +set_context_info (GstVaapiEncoder * base_encoder) { GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2 (base_encoder); - GstVaapiContextInfo *const cip = &base_encoder->context_info; + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); /* Maximum sizes for common headers (in bytes) */ enum @@ -652,13 +653,13 @@ gst_vaapi_encoder_mpeg2_set_context_info (GstVaapiEncoder * base_encoder) MAX_SLICE_HDR_SIZE = 8, }; - cip->profile = to_vaapi_profile (encoder->profile); - cip->ref_frames = 2; + base_encoder->profile = to_vaapi_profile (encoder->profile); + base_encoder->num_ref_frames = 2; /* Only YUV 4:2:0 formats are supported for now. This means that we have a limit of 4608 bits per macroblock. */ - base_encoder->codedbuf_size = (GST_ROUND_UP_16 (cip->width) * - GST_ROUND_UP_16 (cip->height) / 256) * 576; + base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) * + GST_ROUND_UP_16 (vip->height) / 256) * 576; /* Account for Sequence, GOP, and Picture headers */ /* XXX: exclude unused Sequence Display Extension, Sequence Scalable @@ -669,7 +670,7 @@ gst_vaapi_encoder_mpeg2_set_context_info (GstVaapiEncoder * base_encoder) MAX_GOP_SIZE + MAX_PIC_HDR_SIZE + MAX_PIC_EXT_SIZE; /* Account for Slice headers. We use one slice per line of macroblock */ - base_encoder->codedbuf_size += (GST_ROUND_UP_16 (cip->height) / 16) * + base_encoder->codedbuf_size += (GST_ROUND_UP_16 (vip->height) / 16) * MAX_SLICE_HDR_SIZE; } @@ -679,10 +680,18 @@ gst_vaapi_encoder_mpeg2_reconfigure (GstVaapiEncoder * base_encoder) GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder); - if (!ensure_public_attributes (encoder)) { - GST_WARNING ("encoder ensure public attributes failed "); - goto error; + if (encoder->ip_period > encoder->intra_period) { + encoder->ip_period = encoder->intra_period - 1; } + + if (!ensure_profile_and_level (encoder)) + goto error; + if (!ensure_bitrate (encoder)) + goto error; + if (!ensure_sampling_desity (encoder)) + goto error; + + set_context_info (base_encoder); return GST_VAAPI_ENCODER_STATUS_SUCCESS; error: diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h index 98bbee3874..c469deb3c5 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_priv.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h @@ -165,6 +165,8 @@ struct _GstVaapiEncoder VADisplay va_display; VAContextID va_context; GstVideoInfo video_info; + GstVaapiProfile profile; + guint num_ref_frames; GstVaapiRateControl rate_control; guint32 rate_control_mask; guint bitrate; /* kbps */ @@ -204,8 +206,6 @@ struct _GstVaapiEncoderClass gboolean (*init) (GstVaapiEncoder * encoder); void (*finalize) (GstVaapiEncoder * encoder); - void (*set_context_info) (GstVaapiEncoder * encoder); - GstVaapiEncoderStatus (*reconfigure) (GstVaapiEncoder * encoder); GPtrArray * (*get_default_properties) (void); @@ -243,7 +243,6 @@ struct _GstVaapiEncoderClass GST_VAAPI_ENCODER_CLASS_HOOK (codec, finalize), \ GST_VAAPI_ENCODER_CLASS_HOOK (codec, reconfigure), \ GST_VAAPI_ENCODER_CLASS_HOOK (codec, get_default_properties), \ - GST_VAAPI_ENCODER_CLASS_HOOK (codec, set_context_info), \ GST_VAAPI_ENCODER_CLASS_HOOK (codec, reordering), \ GST_VAAPI_ENCODER_CLASS_HOOK (codec, encode), \ GST_VAAPI_ENCODER_CLASS_HOOK (codec, flush)