mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
vaapiencode: fix negotiation process of output caps.
The specified caps in gst_video_encoder_set_output_state() function arguments should not contain any resolution, pixel-aspect-ratio, framerate, codec-data et al. Those rather should be set through the returned GstVideoCodecState. This means that output caps creation could be delayed until before gst_video_encoder_finish_frame() is called. This greatly simplifies the GstVideoEncoder::set_format() callback by the way.
This commit is contained in:
parent
37fa6a8a3d
commit
449ac54348
5 changed files with 135 additions and 102 deletions
|
@ -36,7 +36,6 @@
|
|||
#define GST_VAAPI_ENCODE_FLOW_TIMEOUT GST_FLOW_CUSTOM_SUCCESS
|
||||
#define GST_VAAPI_ENCODE_FLOW_MEM_ERROR GST_FLOW_CUSTOM_ERROR
|
||||
#define GST_VAAPI_ENCODE_FLOW_CONVERT_ERROR GST_FLOW_CUSTOM_ERROR_1
|
||||
#define GST_VAAPI_ENCODE_FLOW_CODEC_DATA_ERROR GST_FLOW_CUSTOM_ERROR_2
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_vaapiencode_debug);
|
||||
#define GST_CAT_DEFAULT gst_vaapiencode_debug
|
||||
|
@ -220,6 +219,40 @@ error_copy_buffer:
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ensure_output_state (GstVaapiEncode * encode)
|
||||
{
|
||||
GstVideoEncoder *const venc = GST_VIDEO_ENCODER_CAST (encode);
|
||||
GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode);
|
||||
GstVaapiEncoderStatus status;
|
||||
GstCaps *out_caps;
|
||||
|
||||
if (!encode->input_state_changed)
|
||||
return TRUE;
|
||||
|
||||
out_caps = klass->get_caps (encode);
|
||||
if (!out_caps)
|
||||
return FALSE;
|
||||
|
||||
if (encode->output_state)
|
||||
gst_video_codec_state_unref (encode->output_state);
|
||||
encode->output_state = gst_video_encoder_set_output_state (venc, out_caps,
|
||||
encode->input_state);
|
||||
|
||||
status = gst_vaapi_encoder_get_codec_data (encode->encoder,
|
||||
&encode->output_state->codec_data);
|
||||
if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
#if GST_CHECK_VERSION(1,0,0)
|
||||
if (!gst_video_encoder_negotiate (venc))
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
encode->input_state_changed = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vaapiencode_push_frame (GstVaapiEncode * encode, gint64 timeout)
|
||||
{
|
||||
|
@ -244,6 +277,12 @@ gst_vaapiencode_push_frame (GstVaapiEncode * encode, gint64 timeout)
|
|||
gst_video_codec_frame_ref (out_frame);
|
||||
gst_video_codec_frame_set_user_data (out_frame, NULL, NULL);
|
||||
|
||||
/* Update output state */
|
||||
GST_VIDEO_ENCODER_STREAM_LOCK (encode);
|
||||
if (!ensure_output_state (encode))
|
||||
goto error_output_state;
|
||||
GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
|
||||
|
||||
/* Allocate and copy buffer into system memory */
|
||||
out_buffer = NULL;
|
||||
ret = klass->alloc_buffer (encode,
|
||||
|
@ -255,35 +294,6 @@ gst_vaapiencode_push_frame (GstVaapiEncode * encode, gint64 timeout)
|
|||
gst_buffer_replace (&out_frame->output_buffer, out_buffer);
|
||||
gst_buffer_unref (out_buffer);
|
||||
|
||||
/* Check output caps */
|
||||
GST_VIDEO_ENCODER_STREAM_LOCK (encode);
|
||||
if (!encode->out_caps_done) {
|
||||
GstVideoCodecState *old_state, *new_state;
|
||||
GstBuffer *codec_data;
|
||||
|
||||
status = gst_vaapi_encoder_get_codec_data (encode->encoder, &codec_data);
|
||||
if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
|
||||
goto error_codec_data;
|
||||
|
||||
if (codec_data) {
|
||||
encode->srcpad_caps = gst_caps_make_writable (encode->srcpad_caps);
|
||||
gst_caps_set_simple (encode->srcpad_caps,
|
||||
"codec_data", GST_TYPE_BUFFER, codec_data, NULL);
|
||||
gst_buffer_unref (codec_data);
|
||||
old_state =
|
||||
gst_video_encoder_get_output_state (GST_VIDEO_ENCODER_CAST (encode));
|
||||
new_state =
|
||||
gst_video_encoder_set_output_state (GST_VIDEO_ENCODER_CAST (encode),
|
||||
gst_caps_ref (encode->srcpad_caps), old_state);
|
||||
gst_video_codec_state_unref (old_state);
|
||||
gst_video_codec_state_unref (new_state);
|
||||
GST_DEBUG ("updated srcpad caps to: %" GST_PTR_FORMAT,
|
||||
encode->srcpad_caps);
|
||||
}
|
||||
encode->out_caps_done = TRUE;
|
||||
}
|
||||
GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
|
||||
|
||||
GST_DEBUG ("output:%" GST_TIME_FORMAT ", size:%zu",
|
||||
GST_TIME_ARGS (out_frame->pts), gst_buffer_get_size (out_buffer));
|
||||
|
||||
|
@ -305,12 +315,12 @@ error_allocate_buffer:
|
|||
gst_video_codec_frame_unref (out_frame);
|
||||
return ret;
|
||||
}
|
||||
error_codec_data:
|
||||
error_output_state:
|
||||
{
|
||||
GST_ERROR ("failed to construct codec-data (status %d)", status);
|
||||
GST_ERROR ("failed to negotiate output state", status);
|
||||
GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
|
||||
gst_video_codec_frame_unref (out_frame);
|
||||
return GST_VAAPI_ENCODE_FLOW_CODEC_DATA_ERROR;
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,6 +384,15 @@ gst_vaapiencode_get_caps (GstVideoEncoder * venc, GstCaps * filter)
|
|||
static gboolean
|
||||
gst_vaapiencode_destroy (GstVaapiEncode * encode)
|
||||
{
|
||||
if (encode->input_state) {
|
||||
gst_video_codec_state_unref (encode->input_state);
|
||||
encode->input_state = NULL;
|
||||
}
|
||||
|
||||
if (encode->output_state) {
|
||||
gst_video_codec_state_unref (encode->output_state);
|
||||
encode->output_state = NULL;
|
||||
}
|
||||
gst_vaapi_encoder_replace (&encode->encoder, NULL);
|
||||
gst_caps_replace (&encode->sinkpad_caps, NULL);
|
||||
gst_caps_replace (&encode->srcpad_caps, NULL);
|
||||
|
@ -446,19 +465,12 @@ gst_vaapiencode_update_sink_caps (GstVaapiEncode * encode,
|
|||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapiencode_update_src_caps (GstVaapiEncode * encode,
|
||||
GstVideoCodecState * in_state)
|
||||
set_codec_state (GstVaapiEncode * encode, GstVideoCodecState * state)
|
||||
{
|
||||
GstVideoCodecState *out_state;
|
||||
GstStructure *structure;
|
||||
GstCaps *outcaps, *allowed_caps, *template_caps, *intersect;
|
||||
GstVaapiEncoderStatus status;
|
||||
GstBuffer *codec_data = NULL;
|
||||
GstCaps *out_caps, *allowed_caps, *template_caps, *intersect;
|
||||
|
||||
g_return_val_if_fail (encode->encoder, FALSE);
|
||||
|
||||
encode->out_caps_done = FALSE;
|
||||
|
||||
/* get peer caps for stream-format avc/bytestream, codec_data */
|
||||
template_caps = gst_pad_get_pad_template_caps (encode->srcpad);
|
||||
allowed_caps = gst_pad_get_allowed_caps (encode->srcpad);
|
||||
|
@ -467,38 +479,19 @@ gst_vaapiencode_update_src_caps (GstVaapiEncode * encode,
|
|||
gst_caps_unref (allowed_caps);
|
||||
|
||||
/* codec data was not set */
|
||||
outcaps = gst_vaapi_encoder_set_format (encode->encoder, in_state, intersect);
|
||||
out_caps = gst_vaapi_encoder_set_format (encode->encoder, state, intersect);
|
||||
gst_caps_unref (intersect);
|
||||
g_return_val_if_fail (outcaps, FALSE);
|
||||
g_return_val_if_fail (out_caps, FALSE);
|
||||
|
||||
if (!gst_caps_is_fixed (outcaps)) {
|
||||
if (!gst_caps_is_fixed (out_caps)) {
|
||||
GST_ERROR ("encoder output caps was not fixed");
|
||||
gst_caps_unref (outcaps);
|
||||
gst_caps_unref (out_caps);
|
||||
return FALSE;
|
||||
}
|
||||
structure = gst_caps_get_structure (outcaps, 0);
|
||||
if (!gst_structure_has_field (structure, "codec_data")) {
|
||||
status = gst_vaapi_encoder_get_codec_data (encode->encoder, &codec_data);
|
||||
if (status == GST_VAAPI_ENCODER_STATUS_SUCCESS) {
|
||||
if (codec_data) {
|
||||
outcaps = gst_caps_make_writable (outcaps);
|
||||
gst_caps_set_simple (outcaps,
|
||||
"codec_data", GST_TYPE_BUFFER, codec_data, NULL);
|
||||
gst_buffer_replace (&codec_data, NULL);
|
||||
}
|
||||
encode->out_caps_done = TRUE;
|
||||
}
|
||||
} else
|
||||
encode->out_caps_done = TRUE;
|
||||
|
||||
out_state =
|
||||
gst_video_encoder_set_output_state (GST_VIDEO_ENCODER_CAST (encode),
|
||||
outcaps, in_state);
|
||||
|
||||
gst_caps_replace (&encode->srcpad_caps, out_state->caps);
|
||||
gst_video_codec_state_unref (out_state);
|
||||
|
||||
GST_DEBUG ("set srcpad caps to: %" GST_PTR_FORMAT, encode->srcpad_caps);
|
||||
GST_DEBUG ("set srcpad caps to: %" GST_PTR_FORMAT, out_caps);
|
||||
gst_caps_replace (&encode->srcpad_caps, out_caps);
|
||||
gst_caps_unref (out_caps);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -511,39 +504,25 @@ gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
|
|||
|
||||
if (!ensure_encoder (encode))
|
||||
return FALSE;
|
||||
if (!gst_vaapiencode_update_sink_caps (encode, state))
|
||||
if (!set_codec_state (encode, state))
|
||||
return FALSE;
|
||||
if (!gst_vaapiencode_update_src_caps (encode, state))
|
||||
|
||||
if (!gst_vaapiencode_update_sink_caps (encode, state))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode),
|
||||
encode->sinkpad_caps, encode->srcpad_caps))
|
||||
state->caps, NULL))
|
||||
return FALSE;
|
||||
|
||||
#if GST_CHECK_VERSION(1,0,0)
|
||||
if (encode->out_caps_done && !gst_video_encoder_negotiate (venc)) {
|
||||
GST_ERROR ("failed to negotiate with caps %" GST_PTR_FORMAT,
|
||||
encode->srcpad_caps);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
if (encode->input_state)
|
||||
gst_video_codec_state_unref (encode->input_state);
|
||||
encode->input_state = gst_video_codec_state_ref (state);
|
||||
encode->input_state_changed = TRUE;
|
||||
|
||||
return gst_pad_start_task (encode->srcpad,
|
||||
(GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapiencode_reset (GstVideoEncoder * venc, gboolean hard)
|
||||
{
|
||||
GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
|
||||
|
||||
GST_DEBUG ("vaapiencode starting reset");
|
||||
|
||||
/* FIXME: compare sink_caps with encoder */
|
||||
encode->out_caps_done = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vaapiencode_handle_frame (GstVideoEncoder * venc,
|
||||
GstVideoCodecFrame * frame)
|
||||
|
@ -700,7 +679,6 @@ gst_vaapiencode_class_init (GstVaapiEncodeClass * klass)
|
|||
venc_class->open = GST_DEBUG_FUNCPTR (gst_vaapiencode_open);
|
||||
venc_class->close = GST_DEBUG_FUNCPTR (gst_vaapiencode_close);
|
||||
venc_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapiencode_set_format);
|
||||
venc_class->reset = GST_DEBUG_FUNCPTR (gst_vaapiencode_reset);
|
||||
venc_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapiencode_handle_frame);
|
||||
venc_class->finish = GST_DEBUG_FUNCPTR (gst_vaapiencode_finish);
|
||||
venc_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapiencode_get_caps);
|
||||
|
|
|
@ -59,9 +59,10 @@ struct _GstVaapiEncode
|
|||
GstPadQueryFunction srcpad_query;
|
||||
|
||||
GstVaapiEncoder *encoder;
|
||||
GstVideoCodecState *input_state;
|
||||
gboolean input_state_changed;
|
||||
GstVideoCodecState *output_state;
|
||||
GPtrArray *prop_values;
|
||||
|
||||
guint32 out_caps_done:1;
|
||||
};
|
||||
|
||||
struct _GstVaapiEncodeClass
|
||||
|
@ -75,6 +76,7 @@ struct _GstVaapiEncodeClass
|
|||
gboolean (*set_property) (GstVaapiEncode * encode,
|
||||
guint prop_id, const GValue * value);
|
||||
|
||||
GstCaps * (*get_caps) (GstVaapiEncode * encode);
|
||||
GstVaapiEncoder * (*alloc_encoder) (GstVaapiEncode * encode,
|
||||
GstVaapiDisplay * display);
|
||||
GstFlowReturn (*alloc_buffer) (GstVaapiEncode * encode,
|
||||
|
|
|
@ -34,7 +34,9 @@
|
|||
GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encode_debug);
|
||||
#define GST_CAT_DEFAULT gst_vaapi_h264_encode_debug
|
||||
|
||||
#define GST_CAPS_CODEC(CODEC) CODEC "; "
|
||||
#define GST_CODEC_CAPS \
|
||||
"video/x-h264, " \
|
||||
"alignment = (string) au"
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static const char gst_vaapiencode_h264_sink_caps_str[] =
|
||||
|
@ -57,7 +59,7 @@ static const char gst_vaapiencode_h264_sink_caps_str[] =
|
|||
|
||||
/* *INDENT-OFF* */
|
||||
static const char gst_vaapiencode_h264_src_caps_str[] =
|
||||
GST_CAPS_CODEC ("video/x-h264");
|
||||
GST_CODEC_CAPS;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
@ -121,6 +123,39 @@ gst_vaapiencode_h264_get_property (GObject * object,
|
|||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_vaapiencode_h264_get_caps (GstVaapiEncode * base_encode)
|
||||
{
|
||||
GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode);
|
||||
GstCaps *caps, *allowed_caps;
|
||||
|
||||
caps = gst_caps_from_string (GST_CODEC_CAPS);
|
||||
|
||||
/* Check whether "stream-format" is avcC mode */
|
||||
allowed_caps = gst_pad_get_allowed_caps (base_encode->srcpad);
|
||||
if (allowed_caps) {
|
||||
const char *stream_format = NULL;
|
||||
GstStructure *structure;
|
||||
guint i, num_structures;
|
||||
|
||||
num_structures = gst_caps_get_size (allowed_caps);
|
||||
for (i = 0; !stream_format && i < num_structures; i++) {
|
||||
structure = gst_caps_get_structure (allowed_caps, i);
|
||||
if (!gst_structure_has_field_typed (structure, "stream-format",
|
||||
G_TYPE_STRING))
|
||||
continue;
|
||||
stream_format = gst_structure_get_string (structure, "stream-format");
|
||||
}
|
||||
encode->is_avc = stream_format && strcmp (stream_format, "avc") == 0;
|
||||
gst_caps_unref (allowed_caps);
|
||||
}
|
||||
gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING,
|
||||
encode->is_avc ? "avc" : "byte-stream", NULL);
|
||||
|
||||
/* XXX: update profile and level information */
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstVaapiEncoder *
|
||||
gst_vaapiencode_h264_alloc_encoder (GstVaapiEncode * base,
|
||||
GstVaapiDisplay * display)
|
||||
|
@ -221,21 +256,23 @@ error:
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vaapiencode_h264_alloc_buffer (GstVaapiEncode * encode,
|
||||
gst_vaapiencode_h264_alloc_buffer (GstVaapiEncode * base_encode,
|
||||
GstVaapiCodedBuffer * coded_buf, GstBuffer ** out_buffer_ptr)
|
||||
{
|
||||
GstVaapiEncoderH264 *const encoder = (GstVaapiEncoderH264 *) encode->encoder;
|
||||
GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode);
|
||||
GstVaapiEncoderH264 *const encoder = (GstVaapiEncoderH264 *)
|
||||
base_encode->encoder;
|
||||
GstFlowReturn ret;
|
||||
|
||||
g_return_val_if_fail (encoder != NULL, GST_FLOW_ERROR);
|
||||
|
||||
ret =
|
||||
GST_VAAPIENCODE_CLASS (gst_vaapiencode_h264_parent_class)->alloc_buffer
|
||||
(encode, coded_buf, out_buffer_ptr);
|
||||
(base_encode, coded_buf, out_buffer_ptr);
|
||||
if (ret != GST_FLOW_OK)
|
||||
return ret;
|
||||
|
||||
if (!gst_vaapi_encoder_h264_is_avc (encoder))
|
||||
if (!encode->is_avc)
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* Convert to avcC format */
|
||||
|
@ -267,6 +304,7 @@ gst_vaapiencode_h264_class_init (GstVaapiEncodeH264Class * klass)
|
|||
object_class->get_property = gst_vaapiencode_h264_get_property;
|
||||
|
||||
encode_class->get_properties = gst_vaapi_encoder_h264_get_default_properties;
|
||||
encode_class->get_caps = gst_vaapiencode_h264_get_caps;
|
||||
encode_class->alloc_encoder = gst_vaapiencode_h264_alloc_encoder;
|
||||
encode_class->alloc_buffer = gst_vaapiencode_h264_alloc_buffer;
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ struct _GstVaapiEncodeH264
|
|||
{
|
||||
/*< private >*/
|
||||
GstVaapiEncode parent_instance;
|
||||
|
||||
guint is_avc:1; /* [FALSE]=byte-stream (default); [TRUE]=avcC */
|
||||
};
|
||||
|
||||
struct _GstVaapiEncodeH264Class
|
||||
|
|
|
@ -34,7 +34,9 @@
|
|||
GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg2_encode_debug);
|
||||
#define GST_CAT_DEFAULT gst_vaapi_mpeg2_encode_debug
|
||||
|
||||
#define GST_CAPS_CODEC(CODEC) CODEC "; "
|
||||
#define GST_CODEC_CAPS \
|
||||
"video/mpeg, mpegversion = (int) 2, " \
|
||||
"systemstream = (boolean) false"
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static const char gst_vaapiencode_mpeg2_sink_caps_str[] =
|
||||
|
@ -57,8 +59,7 @@ static const char gst_vaapiencode_mpeg2_sink_caps_str[] =
|
|||
|
||||
/* *INDENT-OFF* */
|
||||
static const char gst_vaapiencode_mpeg2_src_caps_str[] =
|
||||
GST_CAPS_CODEC ("video/mpeg, mpegversion = (int) 2, "
|
||||
"systemstream = (boolean) false");
|
||||
GST_CODEC_CAPS;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
@ -123,6 +124,17 @@ gst_vaapiencode_mpeg2_get_property (GObject * object,
|
|||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_vaapiencode_mpeg2_get_caps (GstVaapiEncode * base_encode)
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
caps = gst_caps_from_string (GST_CODEC_CAPS);
|
||||
|
||||
/* XXX: update profile and level information */
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstVaapiEncoder *
|
||||
gst_vaapiencode_mpeg2_alloc_encoder (GstVaapiEncode * base,
|
||||
GstVaapiDisplay * display)
|
||||
|
@ -145,6 +157,7 @@ gst_vaapiencode_mpeg2_class_init (GstVaapiEncodeMpeg2Class * klass)
|
|||
object_class->get_property = gst_vaapiencode_mpeg2_get_property;
|
||||
|
||||
encode_class->get_properties = gst_vaapi_encoder_mpeg2_get_default_properties;
|
||||
encode_class->get_caps = gst_vaapiencode_mpeg2_get_caps;
|
||||
encode_class->alloc_encoder = gst_vaapiencode_mpeg2_alloc_encoder;
|
||||
|
||||
gst_element_class_set_static_metadata (element_class,
|
||||
|
|
Loading…
Reference in a new issue