diff options
Diffstat (limited to 'omx/gstomxvideoenc.c')
-rw-r--r-- | omx/gstomxvideoenc.c | 484 |
1 files changed, 385 insertions, 99 deletions
diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c index a399c07..1e5ddea 100644 --- a/omx/gstomxvideoenc.c +++ b/omx/gstomxvideoenc.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. + * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,28 +32,28 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_video_enc_debug_category); #define GST_CAT_DEFAULT gst_omx_video_enc_debug_category -#define GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE (gst_omx_video_enc_control_rate_get_type ()) +#define GST_TYPE_OMX_VID_ENC_RCMODE (gst_omx_videnc_rc_mode_get_type ()) static GType -gst_omx_video_enc_control_rate_get_type (void) +gst_omx_videnc_rc_mode_get_type (void) { - static GType qtype = 0; - - if (qtype == 0) { - static const GEnumValue values[] = { - {OMX_Video_ControlRateDisable, "Disable", "disable"}, - {OMX_Video_ControlRateVariable, "Variable", "variable"}, - {OMX_Video_ControlRateConstant, "Constant", "constant"}, - {OMX_Video_ControlRateVariableSkipFrames, "Variable Skip Frames", - "variable-skip-frames"}, - {OMX_Video_ControlRateConstantSkipFrames, "Constant Skip Frames", - "constant-skip-frames"}, - {0xffffffff, "Component Default", "default"}, - {0, NULL, NULL} - }; - - qtype = g_enum_register_static ("GstOMXVideoEncControlRate", values); + static volatile gsize rcmode_type_type = 0; + static const GEnumValue rcmode_type[] = { + {NVX_VIDEO_RateControlMode_CBR, "GST_OMX_VIDENC_RCMODE_TYPE_CONSTANT", + "cbr"}, + {NVX_VIDEO_RateControlMode_VBR, "GST_OMX_VIDENC_RCMODE_TYPE_VARIABLE", + "vbr"}, + {NVX_VIDEO_RateControlMode_VBR2, "GST_OMX_VIDENC_RCMODE_TYPE_VARIABLE2", + "vbr2"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&rcmode_type_type)) { + GType tmp = + g_enum_register_static ("GstOmxVideoEncRCModeType", rcmode_type); + g_once_init_leave (&rcmode_type_type, tmp); } - return qtype; + + return (GType) rcmode_type_type; } typedef struct _BufferIdentification BufferIdentification; @@ -101,22 +102,35 @@ static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self, static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame); +static GstCaps *gst_omx_video_enc_negotiate_caps (GstVideoEncoder * encoder, + GstCaps * caps, GstCaps * filter); + +static void +gst_omx_video_enc_check_nvfeatures (GstOMXVideoEnc * self, + GstVideoCodecState * state); + enum { PROP_0, - PROP_CONTROL_RATE, - PROP_TARGET_BITRATE, + PROP_RC_MODE, + PROP_BITRATE, PROP_QUANT_I_FRAMES, PROP_QUANT_P_FRAMES, - PROP_QUANT_B_FRAMES + PROP_QUANT_B_FRAMES, + PROP_INTRA_FRAME_INTERVAL }; /* FIXME: Better defaults */ -#define GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT (0xffffffff) -#define GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT (0xffffffff) +#define DEFAULT_RC_MODE NVX_VIDEO_RateControlMode_VBR2 +#define GST_OMX_VIDEO_ENC_BITRATE_DEFAULT (4000000) #define GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT (0xffffffff) #define GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT (0xffffffff) #define GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT (0xffffffff) +#define DEFAULT_INTRA_FRAME_INTERVAL 60 + +#ifdef USE_OMX_TARGET_TEGRA +#define ENCODER_CONF_LOCATION "/etc/enctune.conf" +#endif /* class initialization */ @@ -127,6 +141,10 @@ enum G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc, GST_TYPE_VIDEO_ENCODER, DEBUG_INIT); +#ifdef USE_OMX_TARGET_TEGRA +#define FORMATS "I420, NV12" +#endif + static void gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) { @@ -139,18 +157,17 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) gobject_class->set_property = gst_omx_video_enc_set_property; gobject_class->get_property = gst_omx_video_enc_get_property; - g_object_class_install_property (gobject_class, PROP_CONTROL_RATE, - g_param_spec_enum ("control-rate", "Control Rate", - "Bitrate control method", - GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE, - GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT, + g_object_class_install_property (gobject_class, PROP_RC_MODE, + g_param_spec_enum ("rc-mode", "rc-mode", + "Encoding rate control mode", + GST_TYPE_OMX_VID_ENC_RCMODE, DEFAULT_RC_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_TARGET_BITRATE, - g_param_spec_uint ("target-bitrate", "Target Bitrate", - "Target bitrate (0xffffffff=component default)", - 0, G_MAXUINT, GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT, + g_object_class_install_property (gobject_class, PROP_BITRATE, + g_param_spec_uint ("bitrate", "Target Bitrate", + "Target bitrate", + 0, G_MAXUINT, GST_OMX_VIDEO_ENC_BITRATE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING)); @@ -175,6 +192,13 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_INTRA_FRAME_INTERVAL, + g_param_spec_uint ("iframeinterval", "Intra Frame interval", + "Encoding Intra Frame occurance frequency", + 0, G_MAXUINT, DEFAULT_INTRA_FRAME_INTERVAL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state); @@ -193,7 +217,16 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_omx_video_enc_getcaps); klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER; - klass->cdata.default_sink_template_caps = "video/x-raw, " + klass->cdata.default_sink_template_caps = "video/x-raw(memory:NVMM), " +#ifdef USE_OMX_TARGET_TEGRA + "format = (string) { " FORMATS " }, " +#endif + "width = " GST_VIDEO_SIZE_RANGE ", " + "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE + ";" "video/x-raw, " +#ifdef USE_OMX_TARGET_TEGRA + "format = (string) { " FORMATS " }, " +#endif "width = " GST_VIDEO_SIZE_RANGE ", " "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE; @@ -204,11 +237,12 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) static void gst_omx_video_enc_init (GstOMXVideoEnc * self) { - self->control_rate = GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT; - self->target_bitrate = GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT; + self->bitrate = GST_OMX_VIDEO_ENC_BITRATE_DEFAULT; + self->rc_mode = DEFAULT_RC_MODE; self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT; self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT; self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT; + self->hw_path = FALSE; g_mutex_init (&self->drain_lock); g_cond_init (&self->drain_cond); @@ -270,50 +304,36 @@ gst_omx_video_enc_open (GstVideoEncoder * encoder) { OMX_ERRORTYPE err; - if (self->control_rate != 0xffffffff || self->target_bitrate != 0xffffffff) { - OMX_VIDEO_PARAM_BITRATETYPE bitrate_param; +#ifdef USE_OMX_TARGET_TEGRA - GST_OMX_INIT_STRUCT (&bitrate_param); - bitrate_param.nPortIndex = self->enc_out_port->index; + OMX_INDEXTYPE eIndex; + NVX_PARAM_TEMPFILEPATH enc_conf_loc; + gchar *location = g_strdup (ENCODER_CONF_LOCATION); - err = gst_omx_component_get_parameter (self->enc, - OMX_IndexParamVideoBitrate, &bitrate_param); + GST_DEBUG_OBJECT (self, "Setting encoder to use default configurations"); - if (err == OMX_ErrorNone) { -#ifdef USE_OMX_TARGET_RPI - /* FIXME: Workaround for RPi returning garbage for this parameter */ - if (bitrate_param.nVersion.nVersion == 0) { - GST_OMX_INIT_STRUCT (&bitrate_param); - bitrate_param.nPortIndex = self->enc_out_port->index; - } -#endif - if (self->control_rate != 0xffffffff) - bitrate_param.eControlRate = self->control_rate; - if (self->target_bitrate != 0xffffffff) - bitrate_param.nTargetBitrate = self->target_bitrate; + err = gst_omx_component_get_index (self->enc, + (char *) NVX_INDEX_PARAM_TEMPFILEPATH, &eIndex); + if (err == OMX_ErrorNone) { + if (location != NULL) { + GST_OMX_INIT_STRUCT (&enc_conf_loc); + enc_conf_loc.pTempPath = location; err = - gst_omx_component_set_parameter (self->enc, - OMX_IndexParamVideoBitrate, &bitrate_param); - if (err == OMX_ErrorUnsupportedIndex) { - GST_WARNING_OBJECT (self, - "Setting a bitrate not supported by the component"); - } else if (err == OMX_ErrorUnsupportedSetting) { - GST_WARNING_OBJECT (self, - "Setting bitrate settings %u %u not supported by the component", - self->control_rate, self->target_bitrate); - } else if (err != OMX_ErrorNone) { - GST_ERROR_OBJECT (self, - "Failed to set bitrate parameters: %s (0x%08x)", - gst_omx_error_to_string (err), err); - return FALSE; - } - } else { - GST_ERROR_OBJECT (self, "Failed to get bitrate parameters: %s (0x%08x)", - gst_omx_error_to_string (err), err); + gst_omx_component_set_parameter (self->enc, eIndex, &enc_conf_loc); } + } else { + GST_WARNING_OBJECT (self, "Coudn't get extension index for %s", + (char *) NVX_INDEX_PARAM_TEMPFILEPATH); } + if (err != OMX_ErrorNone) + GST_WARNING_OBJECT (self, "Couldn't set configurations"); + + g_free (location); + +#endif + if (self->quant_i_frames != 0xffffffff || self->quant_p_frames != 0xffffffff || self->quant_b_frames != 0xffffffff) { @@ -422,18 +442,18 @@ gst_omx_video_enc_set_property (GObject * object, guint prop_id, GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object); switch (prop_id) { - case PROP_CONTROL_RATE: - self->control_rate = g_value_get_enum (value); + case PROP_RC_MODE: + self->rc_mode = g_value_get_enum (value); break; - case PROP_TARGET_BITRATE: - self->target_bitrate = g_value_get_uint (value); + case PROP_BITRATE: + self->bitrate = g_value_get_uint (value); if (self->enc) { OMX_VIDEO_CONFIG_BITRATETYPE config; OMX_ERRORTYPE err; GST_OMX_INIT_STRUCT (&config); config.nPortIndex = self->enc_out_port->index; - config.nEncodeBitrate = self->target_bitrate; + config.nEncodeBitrate = self->bitrate; err = gst_omx_component_set_config (self->enc, OMX_IndexConfigVideoBitrate, &config); @@ -452,6 +472,9 @@ gst_omx_video_enc_set_property (GObject * object, guint prop_id, case PROP_QUANT_B_FRAMES: self->quant_b_frames = g_value_get_uint (value); break; + case PROP_INTRA_FRAME_INTERVAL: + self->iframeinterval = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -465,11 +488,11 @@ gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value, GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object); switch (prop_id) { - case PROP_CONTROL_RATE: - g_value_set_enum (value, self->control_rate); + case PROP_RC_MODE: + g_value_set_enum (value, self->rc_mode); break; - case PROP_TARGET_BITRATE: - g_value_set_uint (value, self->target_bitrate); + case PROP_BITRATE: + g_value_set_uint (value, self->bitrate); break; case PROP_QUANT_I_FRAMES: g_value_set_uint (value, self->quant_i_frames); @@ -480,6 +503,9 @@ gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_QUANT_B_FRAMES: g_value_set_uint (value, self->quant_b_frames); break; + case PROP_INTRA_FRAME_INTERVAL: + g_value_set_uint (value, self->iframeinterval); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -662,13 +688,17 @@ gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, GST_DEBUG_OBJECT (self, "Handling codec data"); caps = klass->get_caps (self, self->enc_out_port, self->input_state); - codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); + if (self->codec_data) { + codec_data = self->codec_data; + } else { + codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); - gst_buffer_map (codec_data, &map, GST_MAP_WRITE); - memcpy (map.data, - buf->omx_buf->pBuffer + buf->omx_buf->nOffset, - buf->omx_buf->nFilledLen); - gst_buffer_unmap (codec_data, &map); + gst_buffer_map (codec_data, &map, GST_MAP_WRITE); + memcpy (map.data, + buf->omx_buf->pBuffer + buf->omx_buf->nOffset, + buf->omx_buf->nFilledLen); + gst_buffer_unmap (codec_data, &map); + } state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps, self->input_state); @@ -1099,12 +1129,149 @@ gst_omx_video_enc_get_supported_colorformats (GstOMXVideoEnc * self) return negotiation_map; } +static OMX_ERRORTYPE +gst_omx_video_enc_reconfigure_output_port (GstOMXVideoEnc * self) +{ + + GstOMXPort *port; + OMX_ERRORTYPE err = OMX_ErrorNone; + + port = self->enc_out_port; + + if (!gst_omx_port_is_enabled (port)) { + err = gst_omx_port_set_enabled (port, TRUE); + if (err != OMX_ErrorNone) { + GST_INFO_OBJECT (self, + "Failed to enable port: %s (0x%08x)", + gst_omx_error_to_string (err), err); + goto done; + } + } + + err = gst_omx_port_allocate_buffers (port); + if (err != OMX_ErrorNone) + goto done; + + err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND); + if (err != OMX_ErrorNone) + goto done; + + err = gst_omx_port_populate (port); + if (err != OMX_ErrorNone) + goto done; + + err = gst_omx_port_mark_reconfigured (port); + if (err != OMX_ErrorNone) + goto done; + +done: + return err; +} + +static void +gst_omx_video_enc_check_nvfeatures (GstOMXVideoEnc * self, + GstVideoCodecState * state) +{ + GstCapsFeatures *feature; + + feature = gst_caps_get_features (state->caps, 0); + if (gst_caps_features_contains (feature, "memory:NVMM")) { + OMX_ERRORTYPE err = OMX_ErrorNone; + NVX_PARAM_USENVBUFFER param; + OMX_INDEXTYPE eIndex; + + GST_DEBUG_OBJECT (self, "Setting encoder to use Nvmm buffer"); + + err = gst_omx_component_get_index (self->enc, + (char *) NVX_INDEX_CONFIG_USENVBUFFER, &eIndex); + + if (err == OMX_ErrorNone) { + GST_OMX_INIT_STRUCT (¶m); + param.nPortIndex = self->enc_in_port->index; + param.bUseNvBuffer = OMX_TRUE; + err = gst_omx_component_set_parameter (self->enc, eIndex, ¶m); + } else { + GST_WARNING_OBJECT (self, "Coudn't get extension index for %s", + (char *) NVX_INDEX_CONFIG_USENVBUFFER); + } + + if (err != OMX_ErrorNone) { + GST_WARNING_OBJECT (self, "Couldn't use HW Accelerated path"); + } else { + self->hw_path = TRUE; + } + } +} + +static OMX_ERRORTYPE +gstomx_set_rc_mode (GstOMXVideoEnc * self) +{ + OMX_INDEXTYPE eIndex; + OMX_ERRORTYPE eError = OMX_ErrorNone; + NVX_PARAM_RATECONTROLMODE oRCMode; + + GST_OMX_INIT_STRUCT (&oRCMode); + oRCMode.nPortIndex = 0; + eError = + gst_omx_component_get_index (self->enc, (gpointer) NVX_INDEX_PARAM_RATECONTROLMODE, + &eIndex); + if (eError == OMX_ErrorNone) { + switch (self->rc_mode) { + case NVX_VIDEO_RateControlMode_CBR: + oRCMode.eRateCtrlMode = NVX_VIDEO_RateControlMode_CBR; + break; + case NVX_VIDEO_RateControlMode_VBR: + oRCMode.eRateCtrlMode = NVX_VIDEO_RateControlMode_VBR; + break; + case NVX_VIDEO_RateControlMode_VBR2: + oRCMode.eRateCtrlMode = NVX_VIDEO_RateControlMode_VBR2; + break; + default: + oRCMode.eRateCtrlMode = NVX_VIDEO_RateControlMode_VBR2; + break; + } + + eError = gst_omx_component_set_parameter (self->enc, eIndex, &oRCMode); + if (eError != OMX_ErrorNone) + GST_ERROR_OBJECT (self, + "Failed to set rc_mode parameter: %s (0x%08x)", + gst_omx_error_to_string (eError), eError); + } + return eError; +} + +static OMX_ERRORTYPE +gstomx_set_bitrate (GstOMXVideoEnc * self) +{ + OMX_VIDEO_CONFIG_BITRATETYPE oBitrate; + OMX_ERRORTYPE err = OMX_ErrorNone; + + GST_OMX_INIT_STRUCT (&oBitrate); + + err = + gst_omx_component_get_config (self->enc, + OMX_IndexConfigVideoBitrate, &oBitrate); + + oBitrate.nEncodeBitrate = self->bitrate; + + err = + gst_omx_component_set_config (self->enc, + OMX_IndexConfigVideoBitrate, &oBitrate); + if (err != OMX_ErrorNone) + GST_ERROR_OBJECT (self, + "Failed to set bitrate parameter: %s (0x%08x)", + gst_omx_error_to_string (err), err); + + return err; +} + static gboolean gst_omx_video_enc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) { GstOMXVideoEnc *self; GstOMXVideoEncClass *klass; + OMX_ERRORTYPE err; gboolean needs_disable = FALSE; OMX_PARAM_PORTDEFINITIONTYPE port_def; GstVideoInfo *info = &state->info; @@ -1117,6 +1284,7 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, gst_video_format_to_string (info->finfo->format)); gst_omx_port_get_port_definition (self->enc_in_port, &port_def); + gst_omx_video_enc_check_nvfeatures (self, state); needs_disable = gst_omx_component_get_state (self->enc, @@ -1242,6 +1410,22 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, } } + err = gstomx_set_rc_mode (self); + if (err != OMX_ErrorNone) { + GST_WARNING_OBJECT (self, + "Error setting rc_mode %u : %s (0x%08x)", + (guint) self->rc_mode, gst_omx_error_to_string (err), err); + return FALSE; + } + + err = gstomx_set_bitrate (self); + if (err != OMX_ErrorNone) { + GST_WARNING_OBJECT (self, + "Error setting bitrate %u : %s (0x%08x)", + (guint) self->bitrate, gst_omx_error_to_string (err), err); + return FALSE; + } + GST_DEBUG_OBJECT (self, "Updating outport port definition"); if (gst_omx_port_update_port_definition (self->enc_out_port, NULL) != OMX_ErrorNone) @@ -1287,6 +1471,12 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, return FALSE; } +#ifdef USE_OMX_TARGET_TEGRA + /* PortSetting change event comes only if output port has buffers allocated */ + if (gst_omx_video_enc_reconfigure_output_port (self) != OMX_ErrorNone) + return FALSE; +#endif + /* Unset flushing to allow ports to accept data again */ gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE); gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE); @@ -1362,7 +1552,12 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, } /* Same strides and everything */ - if (gst_buffer_get_size (inbuf) == + /* + * If component is using HW acceleration path, No need for this check. + * Because contents are not actual data but structures. + * We can copy content of buffer directly. + */ + if (self->hw_path || gst_buffer_get_size (inbuf) == outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) { outbuf->omx_buf->nFilledLen = gst_buffer_get_size (inbuf); @@ -1662,6 +1857,10 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder, gst_buffer_get_size (frame->input_buffer)); self->last_upstream_ts += duration; } +#ifdef USE_OMX_TARGET_TEGRA + if (self->hw_path) + buf->omx_buf->nFlags |= OMX_BUFFERFLAG_RETAIN_OMX_TS; +#endif id = g_slice_new0 (BufferIdentification); id->timestamp = buf->omx_buf->nTimeStamp; @@ -1829,35 +2028,122 @@ gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder, (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query); } +GstCaps * +gst_omx_video_enc_negotiate_caps (GstVideoEncoder * encoder, GstCaps * caps, + GstCaps * filter) +{ + GstCaps *templ_caps; + GstCaps *allowed; + GstCaps *fcaps, *filter_caps; + GstCapsFeatures *feature; + gint i, j; + + /* Allow downstream to specify width/height/framerate/PAR constraints + * and forward them upstream for video converters to handle + */ + templ_caps = + caps ? gst_caps_ref (caps) : + gst_pad_get_pad_template_caps (encoder->sinkpad); + allowed = gst_pad_get_allowed_caps (encoder->srcpad); + + if (!allowed || gst_caps_is_empty (allowed) || gst_caps_is_any (allowed)) { + fcaps = templ_caps; + goto done; + } + + GST_LOG_OBJECT (encoder, "template caps %" GST_PTR_FORMAT, templ_caps); + GST_LOG_OBJECT (encoder, "allowed caps %" GST_PTR_FORMAT, allowed); + + filter_caps = gst_caps_new_empty (); + + for (i = 0; i < gst_caps_get_size (templ_caps); i++) { + GQuark q_name = + gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i)); + gchar *f_name = + gst_caps_features_to_string (gst_caps_get_features (templ_caps, i)); + + for (j = 0; j < gst_caps_get_size (allowed); j++) { + const GstStructure *allowed_s = gst_caps_get_structure (allowed, j); + const GValue *val; + GstStructure *s; + + s = gst_structure_new_id_empty (q_name); + feature = gst_caps_features_new (f_name, NULL); + if ((val = gst_structure_get_value (allowed_s, "width"))) + gst_structure_set_value (s, "width", val); + if ((val = gst_structure_get_value (allowed_s, "height"))) + gst_structure_set_value (s, "height", val); + if ((val = gst_structure_get_value (allowed_s, "framerate"))) + gst_structure_set_value (s, "framerate", val); + if ((val = gst_structure_get_value (allowed_s, "pixel-aspect-ratio"))) + gst_structure_set_value (s, "pixel-aspect-ratio", val); + + filter_caps = gst_caps_merge_structure_full (filter_caps, s, feature); + } + } + + fcaps = gst_caps_intersect (filter_caps, templ_caps); + gst_caps_unref (filter_caps); + gst_caps_unref (templ_caps); + + if (filter) { + GST_LOG_OBJECT (encoder, "intersecting with %" GST_PTR_FORMAT, filter); + filter_caps = gst_caps_intersect (fcaps, filter); + gst_caps_unref (fcaps); + fcaps = filter_caps; + } + +done: + gst_caps_replace (&allowed, NULL); + + GST_LOG_OBJECT (encoder, "proxy caps %" GST_PTR_FORMAT, fcaps); + + return fcaps; +} + static GstCaps * gst_omx_video_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter) { GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder); GList *negotiation_map = NULL, *l; GstCaps *comp_supported_caps; + GstCaps *ret; + GstStructure *str; + gint n; + GValue list = G_VALUE_INIT; + GValue val = G_VALUE_INIT; if (!self->enc) - return gst_video_encoder_proxy_getcaps (encoder, NULL, filter); + return gst_omx_video_enc_negotiate_caps (encoder, NULL, filter); negotiation_map = gst_omx_video_enc_get_supported_colorformats (self); - comp_supported_caps = gst_caps_new_empty (); + comp_supported_caps = gst_pad_get_pad_template_caps (encoder->sinkpad); + comp_supported_caps = gst_caps_make_writable (comp_supported_caps); + + g_value_init (&list, GST_TYPE_LIST); + g_value_init (&val, G_TYPE_STRING); + for (l = negotiation_map; l; l = l->next) { VideoNegotiationMap *map = l->data; - gst_caps_append_structure (comp_supported_caps, - gst_structure_new ("video/x-raw", - "format", G_TYPE_STRING, - gst_video_format_to_string (map->format), NULL)); + g_value_set_static_string (&val, gst_video_format_to_string (map->format)); + gst_value_list_append_value (&list, &val); } if (!gst_caps_is_empty (comp_supported_caps)) { - GstCaps *ret = - gst_video_encoder_proxy_getcaps (encoder, comp_supported_caps, filter); - + for (n = 0; n < gst_caps_get_size (comp_supported_caps); n++) { + str = gst_caps_get_structure (comp_supported_caps, n); + gst_structure_set_value (str, "format", &list); + } + ret = + gst_omx_video_enc_negotiate_caps (encoder, comp_supported_caps, filter); gst_caps_unref (comp_supported_caps); - return ret; } else { gst_caps_unref (comp_supported_caps); - return gst_video_encoder_proxy_getcaps (encoder, NULL, filter); + ret = gst_omx_video_enc_negotiate_caps (encoder, NULL, filter); } + + g_value_unset (&val); + g_value_unset (&list); + return ret; } |