static gboolean gst_raw_base_parse_stop (GstBaseParse * parse) { GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse); raw_base_parse->src_caps_set = FALSE; GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); return TRUE; }
static void gst_raw_base_parse_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object); switch (prop_id) { case PROP_USE_SINK_CAPS: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_boolean (value, gst_raw_base_parse_is_using_sink_caps (raw_base_parse)); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_raw_base_parse_start (GstBaseParse * parse) { GstBaseParse *base_parse = GST_BASE_PARSE (parse); GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse); GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse); g_assert (klass->set_current_config); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse); /* If the config is ready from the start, set the min frame size * (this will happen with the properties config) */ if (klass->is_config_ready (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT)) { gsize frame_size = klass->get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); gst_base_parse_set_min_frame_size (base_parse, frame_size); } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); return TRUE; }
static gboolean gst_raw_base_parse_convert (GstBaseParse * parse, GstFormat src_format, gint64 src_value, GstFormat dest_format, gint64 * dest_value) { GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse); GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse); gboolean ret = TRUE; gsize units_n, units_d; g_assert (klass->is_config_ready); g_assert (klass->get_units_per_second); /* The operations below access the current config. Protect * against race conditions by using the object lock. */ GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse); if (!klass->is_config_ready (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT)) { if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) { goto config_not_ready; } else { /* This should not be reached if the property config is active */ g_assert_not_reached (); } } if (G_UNLIKELY (src_format == dest_format)) { *dest_value = src_value; } else if ((src_format == GST_FORMAT_TIME || dest_format == GST_FORMAT_TIME) && gst_raw_base_parse_is_gstformat_supported (raw_base_parse, src_format) && gst_raw_base_parse_is_gstformat_supported (raw_base_parse, src_format)) { /* Perform conversions here if either the src or dest format * are GST_FORMAT_TIME and the other format is supported by * the subclass. This is because we perform TIME<->non-TIME * conversions here. Typically, subclasses only support * BYTES and DEFAULT formats. */ if (src_format == GST_FORMAT_TIME) { /* The source format is time, so perform a TIME -> non-TIME conversion */ klass->get_units_per_second (raw_base_parse, dest_format, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &units_n, &units_d); *dest_value = (units_n == 0 || units_d == 0) ? src_value : gst_util_uint64_scale (src_value, units_n, GST_SECOND * units_d); } else { /* The dest format is time, so perform a non-TIME -> TIME conversion */ klass->get_units_per_second (raw_base_parse, src_format, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &units_n, &units_d); *dest_value = (units_n == 0 || units_d == 0) ? src_value : gst_util_uint64_scale (src_value, GST_SECOND * units_d, units_n); } } else { /* Fallback for other conversions */ ret = gst_base_parse_convert_default (parse, src_format, src_value, dest_format, dest_value); } GST_DEBUG_OBJECT (parse, "converted %s -> %s %" G_GINT64_FORMAT " -> %" GST_TIME_FORMAT, gst_format_get_name (src_format), gst_format_get_name (dest_format), src_value, GST_TIME_ARGS (*dest_value)); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); return ret; config_not_ready: GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); GST_ELEMENT_ERROR (parse, STREAM, FORMAT, ("sink caps config is the current config, and it is not ready - " "upstream may not have pushed a caps event yet"), (NULL)); return FALSE; }
static GstFlowReturn gst_raw_base_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { gsize in_size, out_size; guint frame_size; guint num_out_frames; gsize units_n, units_d; guint64 buffer_duration; GstFlowReturn flow_ret = GST_FLOW_OK; GstEvent *new_caps_event = NULL; GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse); GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse); g_assert (klass->is_config_ready); g_assert (klass->get_caps_from_config); g_assert (klass->get_config_frame_size); g_assert (klass->get_units_per_second); /* We never skip any bytes this way. Instead, subclass takes care * of skipping any overhead (necessary, since the way it needs to * be skipped is completely subclass specific). */ *skipsize = 0; /* The operations below access the current config. Protect * against race conditions by using the object lock. */ GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse); /* If the source pad caps haven't been set yet, or need to be * set again, do so now, BEFORE any buffers are pushed out */ if (G_UNLIKELY (!raw_base_parse->src_caps_set)) { GstCaps *new_src_caps; if (G_UNLIKELY (!klass->is_config_ready (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT))) { /* The current configuration is not ready. No caps can be * generated out of it. * The most likely reason for this is that the sink caps config * is the current one and no valid sink caps have been pushed * by upstream. Report the problem and exit. */ if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) { goto config_not_ready; } else { /* This should not be reached if the property config is active */ g_assert_not_reached (); } } GST_DEBUG_OBJECT (parse, "setting src caps since this has not been done yet"); /* Convert the current config to a caps structure to * inform downstream about the new format */ if (!klass->get_caps_from_config (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &new_src_caps)) { GST_ERROR_OBJECT (raw_base_parse, "could not get src caps from current config"); flow_ret = GST_FLOW_NOT_NEGOTIATED; goto error_locked; } new_caps_event = gst_event_new_caps (new_src_caps); gst_caps_unref (new_src_caps); raw_base_parse->src_caps_set = TRUE; } frame_size = klass->get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); in_size = gst_buffer_get_size (frame->buffer); /* gst_base_parse_set_min_frame_size() is called when the current * configuration changes and the change affects the frame size. This * means that a buffer must contain at least as many bytes as indicated * by the frame size. If there are fewer inside an error occurred; * either something in the parser went wrong, or the min frame size * wasn't updated properly. */ g_assert (in_size >= frame_size); /* Determine how many complete frames would fit in the input buffer. * Then check if this amount exceeds the maximum number of frames * as indicated by the subclass. */ num_out_frames = (in_size / frame_size); if (klass->get_max_frames_per_buffer) { guint max_num_out_frames = klass->get_max_frames_per_buffer (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); num_out_frames = MIN (num_out_frames, max_num_out_frames); } /* Ensure that the size of the buffers that get pushed downstream * is always an integer multiple of the frame size to prevent cases * where downstream gets buffers with incomplete frames. */ out_size = num_out_frames * frame_size; /* Set the overhead size to ensure that timestamping excludes these * extra overhead bytes. */ frame->overhead = klass->get_overhead_size ? klass->get_overhead_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT) : 0; g_assert (out_size >= (guint) (frame->overhead)); out_size -= frame->overhead; GST_LOG_OBJECT (raw_base_parse, "%" G_GSIZE_FORMAT " bytes input %" G_GSIZE_FORMAT " bytes output (%u frame(s)) %d bytes overhead", in_size, out_size, num_out_frames, frame->overhead); /* Calculate buffer duration */ klass->get_units_per_second (raw_base_parse, GST_FORMAT_BYTES, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &units_n, &units_d); if (units_n == 0 || units_d == 0) buffer_duration = GST_CLOCK_TIME_NONE; else buffer_duration = gst_util_uint64_scale (out_size, GST_SECOND * units_d, units_n); if (klass->process) { GstBuffer *processed_data = NULL; if (!klass->process (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT, frame->buffer, in_size, out_size, &processed_data)) goto process_error; frame->out_buffer = processed_data; } else { frame->out_buffer = NULL; } /* Set the duration of the output buffer, or if none exists, of * the input buffer. Do this after the process() call, since in * case out_buffer is set, the subclass has created a new buffer. * Instead of requiring subclasses to set the duration (which * anyway must always be buffer_duration), let's do it here. */ if (frame->out_buffer != NULL) GST_BUFFER_DURATION (frame->out_buffer) = buffer_duration; else GST_BUFFER_DURATION (frame->buffer) = buffer_duration; /* Access to the current config is not needed in subsequent * operations, so the lock can be released */ GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); /* If any new caps have to be pushed downstrean, do so * *before* the frame is finished */ if (G_UNLIKELY (new_caps_event != NULL)) { gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (raw_base_parse), new_caps_event); new_caps_event = NULL; } gst_base_parse_finish_frame (parse, frame, out_size + frame->overhead); return flow_ret; config_not_ready: GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); GST_ELEMENT_ERROR (parse, STREAM, FORMAT, ("sink caps config is the current config, and it is not ready -" "upstream may not have pushed a caps event yet"), (NULL)); flow_ret = GST_FLOW_ERROR; goto error_end; process_error: GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); GST_ELEMENT_ERROR (parse, STREAM, DECODE, ("could not process data"), (NULL)); flow_ret = GST_FLOW_ERROR; goto error_end; error_locked: GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); goto error_end; error_end: frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP; if (new_caps_event != NULL) gst_event_unref (new_caps_event); return flow_ret; }
static gboolean gst_raw_base_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps) { gboolean ret = FALSE; GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse); GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse); g_assert (klass->set_config_from_caps); g_assert (klass->get_caps_from_config); g_assert (klass->get_config_frame_size); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse); GST_DEBUG_OBJECT (parse, "getting config from new sink caps"); /* Convert the new sink caps to sink caps config. This also * readies the config. */ ret = klass->set_config_from_caps (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_SINKCAPS, caps); if (!ret) { GST_ERROR_OBJECT (raw_base_parse, "could not get config from sink caps"); goto done; } /* If the sink caps config is currently active, push caps downstream, * set the minimum frame size (to guarantee that input buffers hold * complete frames), and update the src_caps_set flag. If the sink * caps config isn't the currently active config, just exit, since in * that case, the caps will always be pushed downstream in handle_frame. */ if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) { GstCaps *new_src_caps; gsize frame_size; GST_DEBUG_OBJECT (parse, "sink caps config is the current one; trying to push new caps downstream"); /* Convert back to caps. The caps may have changed, for example * audio/x-unaligned-raw may have been replaced with audio/x-raw. * (Also, this keeps the behavior in sync with that of the block * in handle_frame that pushes caps downstream if not done already.) */ if (!klass->get_caps_from_config (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &new_src_caps)) { GST_ERROR_OBJECT (raw_base_parse, "could not get src caps from current config"); goto done; } GST_DEBUG_OBJECT (raw_base_parse, "got new sink caps; updating src caps to %" GST_PTR_FORMAT, (gpointer) new_src_caps); frame_size = klass->get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); gst_base_parse_set_min_frame_size (parse, frame_size); raw_base_parse->src_caps_set = TRUE; GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); /* Push caps outside of the lock */ gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (raw_base_parse), gst_event_new_caps (new_src_caps) ); gst_caps_unref (new_src_caps); } else { GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); } ret = TRUE; done: return ret; }
static void gst_raw_base_parse_set_property (GObject * object, guint prop_id, GValue const *value, GParamSpec * pspec) { GstBaseParse *base_parse = GST_BASE_PARSE (object); GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object); GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (object); g_assert (klass->is_config_ready); g_assert (klass->set_current_config); switch (prop_id) { case PROP_USE_SINK_CAPS: { gboolean new_state, cur_state; GstRawBaseParseConfig new_config; GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); /* Check to ensure nothing is done if the value stays the same */ new_state = g_value_get_boolean (value); cur_state = gst_raw_base_parse_is_using_sink_caps (raw_base_parse); if (new_state == cur_state) { GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } GST_DEBUG_OBJECT (raw_base_parse, "switching to %s config", new_state ? "sink caps" : "properties"); new_config = new_state ? GST_RAW_BASE_PARSE_CONFIG_SINKCAPS : GST_RAW_BASE_PARSE_CONFIG_PROPERTIES; if (!klass->set_current_config (raw_base_parse, new_config)) { GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); GST_ELEMENT_ERROR (raw_base_parse, STREAM, FAILED, ("could not set new current config"), ("use-sink-caps property: %d", new_state)); break; } /* Update the minimum frame size if the config is ready. This ensures that * the next buffer that is passed to handle_frame contains complete frames. * If the current config is the properties config, then it will always be * ready, and its frame size will be valid. Ensure that the baseparse minimum * frame size is set properly then. * If the current config is the sink caps config, then it will initially not * be ready until the sink caps are set, so the minimum frame size cannot be * set right here. However, since the caps always come in *before* the actual * data, the config will be readied in the set_sink_caps function, and be ready * by the time handle_frame is called. There, the minimum frame size is set as * well. */ if (klass->is_config_ready (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT)) { gsize frame_size = klass->get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); gst_base_parse_set_min_frame_size (base_parse, frame_size); } /* Since the current config was switched, the source caps change. Ensure the * new caps are pushed downstream by setting src_caps_set to FALSE: This way, * the next handle_frame call will take care of that. */ raw_base_parse->src_caps_set = FALSE; GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_raw_video_parse_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (object); GstRawVideoParseConfig *props_cfg = &(raw_video_parse->properties_config); switch (prop_id) { case PROP_WIDTH: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_int (value, props_cfg->width); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_HEIGHT: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_int (value, props_cfg->height); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_FORMAT: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_enum (value, props_cfg->format); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_PIXEL_ASPECT_RATIO: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); gst_value_set_fraction (value, props_cfg->pixel_aspect_ratio_n, props_cfg->pixel_aspect_ratio_d); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_FRAMERATE: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); gst_value_set_fraction (value, props_cfg->framerate_n, props_cfg->framerate_d); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_INTERLACED: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_boolean (value, props_cfg->interlaced); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_TOP_FIELD_FIRST: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_boolean (value, props_cfg->top_field_first); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_PLANE_STRIDES: { guint i, n_planes; GValue val = G_VALUE_INIT; GValueArray *valarray; GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info)); valarray = g_value_array_new (n_planes); g_value_init (&val, G_TYPE_UINT); for (i = 0; i < n_planes; ++i) { g_value_set_uint (&val, props_cfg->plane_strides[i]); g_value_array_insert (valarray, i, &val); } g_value_unset (&val); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); /* Pass on ownership to the value array, * since we don't need it anymore */ g_value_take_boxed (value, valarray); break; } case PROP_PLANE_OFFSETS: { guint i, n_planes; GValue val = G_VALUE_INIT; GValueArray *valarray; GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info)); valarray = g_value_array_new (n_planes); g_value_init (&val, G_TYPE_UINT); for (i = 0; i < n_planes; ++i) { g_value_set_uint (&val, props_cfg->plane_offsets[i]); g_value_array_insert (valarray, i, &val); } g_value_unset (&val); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); /* Pass on ownership to the value array, * since we don't need it anymore */ g_value_take_boxed (value, valarray); break; } case PROP_FRAME_STRIDE: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_uint (value, raw_video_parse->properties_config.frame_stride); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_raw_video_parse_set_property (GObject * object, guint prop_id, GValue const *value, GParamSpec * pspec) { GstBaseParse *base_parse = GST_BASE_PARSE (object); GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object); GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (object); GstRawVideoParseConfig *props_cfg = &(raw_video_parse->properties_config); /* All properties are handled similarly: * - if the new value is the same as the current value, nothing is done * - the parser lock is held while the new value is set * - if the properties config is the current config, the source caps are * invalidated to ensure that the code in handle_frame pushes a new CAPS * event out * - properties that affect the video frame size call the function to update * the info and also call gst_base_parse_set_min_frame_size() to ensure * that the minimum frame size can hold 1 frame (= one sample for each * channel); to ensure that the min frame size includes any extra padding, * it is set to the result of gst_raw_video_parse_get_config_frame_size() * - property configuration values that require video info updates aren't * written directory into the video info structure, but in the extra * fields instead (gst_raw_video_parse_update_info() then copies the values * from these fields into the video info); see the documentation inside * gst_raw_video_parse_update_info() for the reason why */ switch (prop_id) { case PROP_WIDTH: { gint new_width = g_value_get_int (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_width != props_cfg->width) { props_cfg->width = new_width; gst_raw_video_parse_update_info (props_cfg); if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) { gst_raw_base_parse_invalidate_src_caps (raw_base_parse); gst_base_parse_set_min_frame_size (base_parse, gst_raw_video_parse_get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_PROPERTIES)); } } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_HEIGHT: { gint new_height = g_value_get_int (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_height != props_cfg->height) { props_cfg->height = new_height; gst_raw_video_parse_update_info (props_cfg); if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) { gst_raw_base_parse_invalidate_src_caps (raw_base_parse); gst_base_parse_set_min_frame_size (base_parse, gst_raw_video_parse_get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_PROPERTIES)); } } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_FORMAT: { GstVideoFormat new_format = g_value_get_enum (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_format != props_cfg->format) { props_cfg->format = new_format; gst_raw_video_parse_update_info (props_cfg); if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) { gst_raw_base_parse_invalidate_src_caps (raw_base_parse); gst_base_parse_set_min_frame_size (base_parse, gst_raw_video_parse_get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_PROPERTIES)); } } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_PIXEL_ASPECT_RATIO: { GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); /* The pixel aspect ratio does not affect the video frame size, * so it is just set directly without any updates */ props_cfg->pixel_aspect_ratio_n = GST_VIDEO_INFO_PAR_N (&(props_cfg->info)) = gst_value_get_fraction_numerator (value); props_cfg->pixel_aspect_ratio_d = GST_VIDEO_INFO_PAR_D (&(props_cfg->info)) = gst_value_get_fraction_denominator (value); GST_DEBUG_OBJECT (raw_video_parse, "setting pixel aspect ratio to %u/%u", props_cfg->pixel_aspect_ratio_n, props_cfg->pixel_aspect_ratio_d); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_FRAMERATE: { GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); /* The framerate does not affect the video frame size, * so it is just set directly without any updates */ props_cfg->framerate_n = GST_VIDEO_INFO_FPS_N (&(props_cfg->info)) = gst_value_get_fraction_numerator (value); props_cfg->framerate_d = GST_VIDEO_INFO_FPS_D (&(props_cfg->info)) = gst_value_get_fraction_denominator (value); GST_DEBUG_OBJECT (raw_video_parse, "setting framerate to %u/%u", props_cfg->framerate_n, props_cfg->framerate_d); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_INTERLACED: { GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); /* Interlacing does not affect the video frame size, * so it is just set directly without any updates */ props_cfg->interlaced = g_value_get_boolean (value); GST_VIDEO_INFO_INTERLACE_MODE (&(props_cfg->info)) = props_cfg->interlaced ? GST_VIDEO_INTERLACE_MODE_INTERLEAVED : GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_TOP_FIELD_FIRST: { /* The top-field-first flag is a detail related to * interlacing, so no video info update is needed */ GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); props_cfg->top_field_first = g_value_get_boolean (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_PLANE_STRIDES: { GValueArray *valarray = g_value_get_boxed (value); guint n_planes; guint i; /* If no valarray is given, then disable custom * plane strides & offsets and stick to the * standard computed ones */ if (valarray == NULL) { GST_DEBUG_OBJECT (raw_video_parse, "custom plane strides & offsets disabled"); props_cfg->custom_plane_strides = FALSE; gst_raw_video_parse_update_info (props_cfg); break; } /* Sanity check - reject empty arrays */ if ((valarray != NULL) && (valarray->n_values == 0)) { GST_ELEMENT_ERROR (raw_video_parse, LIBRARY, SETTINGS, ("plane strides property holds an empty array"), (NULL)); break; } GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info)); /* Check that the valarray holds the right number of values */ if (valarray->n_values != n_planes) { GST_ELEMENT_ERROR (raw_video_parse, LIBRARY, SETTINGS, ("incorrect number of elements in plane strides property"), ("expected: %u, got: %u", n_planes, valarray->n_values)); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } /* Copy the values to the stride array */ for (i = 0; i < n_planes; ++i) { GValue *val = g_value_array_get_nth (valarray, i); props_cfg->plane_strides[i] = g_value_get_uint (val); GST_DEBUG_OBJECT (raw_video_parse, "plane #%u stride: %d", i, props_cfg->plane_strides[i]); } props_cfg->custom_plane_strides = TRUE; gst_raw_video_parse_update_info (props_cfg); if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) gst_base_parse_set_min_frame_size (base_parse, gst_raw_video_parse_get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_PROPERTIES)); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_PLANE_OFFSETS: { GValueArray *valarray = g_value_get_boxed (value); guint n_planes; guint i; /* If no valarray is given, then disable custom * plane strides & offsets and stick to the * standard computed ones */ if (valarray == NULL) { GST_DEBUG_OBJECT (raw_video_parse, "custom plane strides & offsets disabled"); props_cfg->custom_plane_strides = FALSE; gst_raw_video_parse_update_info (props_cfg); break; } /* Sanity check - reject empty arrays */ if ((valarray != NULL) && (valarray->n_values == 0)) { GST_ELEMENT_ERROR (raw_video_parse, LIBRARY, SETTINGS, ("plane offsets property holds an empty array"), (NULL)); break; } GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info)); /* Check that the valarray holds the right number of values */ if (valarray->n_values != n_planes) { GST_ELEMENT_ERROR (raw_video_parse, LIBRARY, SETTINGS, ("incorrect number of elements in plane offsets property"), ("expected: %u, got: %u", n_planes, valarray->n_values)); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } /* Copy the values to the offset array */ for (i = 0; i < n_planes; ++i) { GValue *val = g_value_array_get_nth (valarray, i); props_cfg->plane_offsets[i] = g_value_get_uint (val); GST_DEBUG_OBJECT (raw_video_parse, "plane #%u offset: %" G_GSIZE_FORMAT, i, props_cfg->plane_offsets[i]); } props_cfg->custom_plane_strides = TRUE; gst_raw_video_parse_update_info (props_cfg); if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) gst_base_parse_set_min_frame_size (base_parse, gst_raw_video_parse_get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_PROPERTIES)); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_FRAME_STRIDE: { /* The frame stride does not affect the video frame size, * so it is just set directly without any updates */ GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); props_cfg->frame_stride = g_value_get_uint (value); gst_raw_video_parse_update_info (props_cfg); if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) gst_base_parse_set_min_frame_size (base_parse, gst_raw_video_parse_get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_PROPERTIES)); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_raw_audio_parse_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (object); switch (prop_id) { case PROP_FORMAT: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_enum (value, raw_audio_parse->properties_config.format); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_PCM_FORMAT: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_enum (value, raw_audio_parse->properties_config.pcm_format); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_SAMPLE_RATE: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_int (value, raw_audio_parse->properties_config.sample_rate); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_NUM_CHANNELS: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_int (value, raw_audio_parse->properties_config.num_channels); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_INTERLEAVED: GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); g_value_set_boolean (value, raw_audio_parse->properties_config.interleaved); GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; case PROP_CHANNEL_POSITIONS: { GstRawAudioParseConfig *config; GValueArray *valarray; GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); valarray = NULL; config = &(raw_audio_parse->properties_config); /* Copy channel positions into the valuearray */ if (config->num_channels > 0) { guint i; GValue val = G_VALUE_INIT; g_assert (config->channel_positions); g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION); valarray = g_value_array_new (config->num_channels); for (i = 0; i < config->num_channels; ++i) { g_value_set_enum (&val, config->channel_positions[i]); g_value_array_insert (valarray, i, &val); } g_value_unset (&val); } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); /* Pass on ownership to the value array, * since we don't need it anymore */ g_value_take_boxed (value, valarray); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_raw_audio_parse_set_property (GObject * object, guint prop_id, GValue const *value, GParamSpec * pspec) { GstBaseParse *base_parse = GST_BASE_PARSE (object); GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object); GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (object); /* All properties are handled similarly: * - if the new value is the same as the current value, nothing is done * - the parser lock is held while the new value is set * - if the properties config is the current config, the source caps are * invalidated to ensure that the code in handle_frame pushes a new CAPS * event out * - properties that affect the bpf value call the function to update * the bpf and also call gst_base_parse_set_min_frame_size() to ensure * that the minimum frame size can hold 1 frame (= one sample for each * channel) */ switch (prop_id) { case PROP_FORMAT: { GstRawAudioParseFormat new_format = g_value_get_enum (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_format != raw_audio_parse->properties_config.format) { raw_audio_parse->properties_config.format = new_format; gst_raw_audio_parse_update_config_bpf (& (raw_audio_parse->properties_config)); if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) { gst_raw_base_parse_invalidate_src_caps (raw_base_parse); gst_base_parse_set_min_frame_size (base_parse, raw_audio_parse->properties_config.bpf); } } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_PCM_FORMAT: { GstAudioFormat new_pcm_format = g_value_get_enum (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_pcm_format != raw_audio_parse->properties_config.pcm_format) { raw_audio_parse->properties_config.pcm_format = new_pcm_format; gst_raw_audio_parse_update_config_bpf (& (raw_audio_parse->properties_config)); if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) { gst_raw_base_parse_invalidate_src_caps (raw_base_parse); gst_base_parse_set_min_frame_size (base_parse, raw_audio_parse->properties_config.bpf); } } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_SAMPLE_RATE: { guint new_sample_rate = g_value_get_int (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_sample_rate != raw_audio_parse->properties_config.sample_rate) { raw_audio_parse->properties_config.sample_rate = new_sample_rate; if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) gst_raw_base_parse_invalidate_src_caps (raw_base_parse); } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_NUM_CHANNELS: { guint new_num_channels = g_value_get_int (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_num_channels != raw_audio_parse->properties_config.num_channels) { gst_raw_audio_parse_set_config_channels (& (raw_audio_parse->properties_config), new_num_channels, 0, TRUE); raw_audio_parse->properties_config.num_channels = new_num_channels; gst_raw_audio_parse_update_config_bpf (& (raw_audio_parse->properties_config)); if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) { gst_raw_base_parse_invalidate_src_caps (raw_base_parse); gst_base_parse_set_min_frame_size (base_parse, raw_audio_parse->properties_config.bpf); } } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_INTERLEAVED: { gboolean new_interleaved = g_value_get_boolean (value); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if (new_interleaved != raw_audio_parse->properties_config.interleaved) { raw_audio_parse->properties_config.interleaved = new_interleaved; if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) gst_raw_base_parse_invalidate_src_caps (raw_base_parse); } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } case PROP_CHANNEL_POSITIONS: { GValueArray *valarray = g_value_get_boxed (value); GstRawAudioParseConfig *config = &(raw_audio_parse->properties_config); /* Sanity check - reject empty arrays */ if ((valarray != NULL) && (valarray->n_values == 0)) { GST_ELEMENT_ERROR (raw_audio_parse, LIBRARY, SETTINGS, ("channel position property holds an empty array"), (NULL)); break; } GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object); if ((valarray == NULL) && (config->num_channels > 0)) { /* NULL value given, and number of channels is nonzero. * Use the default GStreamer positioning. Call * set_config_channels with the set_positions parameter * set to TRUE to ensure the position values are filled. */ gst_raw_audio_parse_set_config_channels (& (raw_audio_parse->properties_config), config->num_channels, 0, TRUE); } else { /* Non-NULL value given. Make sure the channel_positions * array in the properties config has enough room, and that * the num_channels value equals the array length. Then copy * the values from the valarray to channel_positions, and * produce a copy of that array in case its channel positions * are not in a valid GStreamer order (to be able to apply * channel reordering later). */ guint i; if (valarray->n_values != config->num_channels) { /* Call with set_positions == FALSE to ensure that * the array is properly allocated but not filled * (it is filled below) */ gst_raw_audio_parse_set_config_channels (config, valarray->n_values, 0, FALSE); } for (i = 0; i < config->num_channels; ++i) { GValue *val = g_value_array_get_nth (valarray, i); config->channel_positions[i] = g_value_get_enum (val); } gst_raw_audio_parse_update_channel_reordering_flag (config); } gst_raw_audio_parse_update_config_bpf (& (raw_audio_parse->properties_config)); if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) { gst_raw_base_parse_invalidate_src_caps (raw_base_parse); gst_base_parse_set_min_frame_size (base_parse, raw_audio_parse->properties_config.bpf); } GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }