gboolean gst_vaapiencode_init_properties (GstVaapiEncode * encode) { GPtrArray *const props = get_properties (GST_VAAPIENCODE_GET_CLASS (encode)); guint i; /* XXX: use base_init()/base_finalize() to avoid multiple initializations */ if (!props) return FALSE; encode->prop_values = g_ptr_array_new_full (props->len, (GDestroyNotify) prop_value_free); if (!encode->prop_values) { g_ptr_array_unref (props); return FALSE; } for (i = 0; i < props->len; i++) { PropValue *const prop_value = prop_value_new ((GstVaapiEncoderPropInfo *) g_ptr_array_index (props, i)); if (!prop_value) return FALSE; g_ptr_array_add (encode->prop_values, prop_value); } return TRUE; }
static gboolean ensure_encoder (GstVaapiEncode * encode) { GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode); GstVaapiEncoderStatus status; GPtrArray *const prop_values = encode->prop_values; guint i; g_return_val_if_fail (klass->alloc_encoder, FALSE); if (encode->encoder) return FALSE; encode->encoder = klass->alloc_encoder (encode, GST_VAAPI_PLUGIN_BASE_DISPLAY (encode)); if (!encode->encoder) return FALSE; if (prop_values) { for (i = 0; i < prop_values->len; i++) { PropValue *const prop_value = g_ptr_array_index (prop_values, i); status = gst_vaapi_encoder_set_property (encode->encoder, prop_value->id, &prop_value->value); if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) return FALSE; } } return TRUE; }
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); if (encode->need_codec_data) { 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_video_encoder_negotiate (venc)) return FALSE; encode->input_state_changed = FALSE; return TRUE; }
static void gst_vaapiencode_mpeg2_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_GET_CLASS (object); GstVaapiEncode *const base_encode = GST_VAAPIENCODE_CAST (object); switch (prop_id) { default: if (!encode_class->set_property (base_encode, prop_id, value)) G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean set_codec_state (GstVaapiEncode * encode, GstVideoCodecState * state) { GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode); GstVaapiEncoderStatus status; g_return_val_if_fail (encode->encoder, FALSE); /* Initialize codec specific parameters */ if (klass->set_config && !klass->set_config (encode)) return FALSE; status = gst_vaapi_encoder_set_codec_state (encode->encoder, state); if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) return FALSE; return TRUE; }
static gboolean ensure_allowed_sinkpad_caps (GstVaapiEncode * encode) { GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode); GstCaps *out_caps, *raw_caps = NULL; GArray *formats = NULL; gboolean ret = FALSE; GstVaapiProfile profile = GST_VAAPI_PROFILE_UNKNOWN; if (encode->allowed_sinkpad_caps) return TRUE; if (!encode->encoder) return TRUE; out_caps = gst_caps_from_string (GST_VAAPI_MAKE_SURFACE_CAPS); if (!out_caps) goto failed_create_va_caps; if (klass->get_profile) { GstCaps *allowed = gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); if (allowed) { if (!gst_caps_is_empty (allowed) && !gst_caps_is_any (allowed)) profile = klass->get_profile (allowed); gst_caps_unref (allowed); } } formats = gst_vaapi_encoder_get_surface_formats (encode->encoder, profile); if (!formats) goto failed_get_formats; raw_caps = gst_vaapi_video_format_new_template_caps_from_list (formats); if (!raw_caps) goto failed_create_raw_caps; out_caps = gst_caps_make_writable (out_caps); gst_caps_append (out_caps, gst_caps_copy (raw_caps)); gst_caps_replace (&encode->allowed_sinkpad_caps, out_caps); GST_INFO_OBJECT (encode, "Allowed sink caps %" GST_PTR_FORMAT, encode->allowed_sinkpad_caps); ret = TRUE; bail: if (out_caps) gst_caps_unref (out_caps); if (raw_caps) gst_caps_unref (raw_caps); if (formats) g_array_unref (formats); return ret; failed_create_va_caps: { GST_WARNING_OBJECT (encode, "failed to create VA/GL sink caps"); return FALSE; } failed_get_formats: { GST_WARNING_OBJECT (encode, "failed to get allowed surface formats"); goto bail; } failed_create_raw_caps: { GST_WARNING_OBJECT (encode, "failed to create raw sink caps"); goto bail; } }
static GstFlowReturn gst_vaapiencode_push_frame (GstVaapiEncode * encode, gint64 timeout) { GstVideoEncoder *const venc = GST_VIDEO_ENCODER_CAST (encode); GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode); GstVideoCodecFrame *out_frame; GstVaapiCodedBufferProxy *codedbuf_proxy = NULL; GstVaapiEncoderStatus status; GstBuffer *out_buffer; GstFlowReturn ret; status = gst_vaapi_encoder_get_buffer_with_timeout (encode->encoder, &codedbuf_proxy, timeout); if (status == GST_VAAPI_ENCODER_STATUS_NO_BUFFER) return GST_VAAPI_ENCODE_FLOW_TIMEOUT; if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) goto error_get_buffer; out_frame = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy); if (!out_frame) goto error_get_buffer; 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, GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy), &out_buffer); gst_vaapi_coded_buffer_proxy_replace (&codedbuf_proxy, NULL); if (ret != GST_FLOW_OK) goto error_allocate_buffer; gst_buffer_replace (&out_frame->output_buffer, out_buffer); gst_buffer_unref (out_buffer); GST_TRACE_OBJECT (encode, "output:%" GST_TIME_FORMAT ", size:%zu", GST_TIME_ARGS (out_frame->pts), gst_buffer_get_size (out_buffer)); return gst_video_encoder_finish_frame (venc, out_frame); /* ERRORS */ error_get_buffer: { GST_ERROR ("failed to get encoded buffer (status %d)", status); if (codedbuf_proxy) gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy); return GST_FLOW_ERROR; } error_allocate_buffer: { GST_ERROR ("failed to allocate encoded buffer in system memory"); if (out_buffer) gst_buffer_unref (out_buffer); gst_video_codec_frame_unref (out_frame); return ret; } error_output_state: { GST_ERROR ("failed to negotiate output state (status %d)", status); GST_VIDEO_ENCODER_STREAM_UNLOCK (encode); gst_video_codec_frame_unref (out_frame); return GST_FLOW_NOT_NEGOTIATED; } }