Example #1
0
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;
}
Example #2
0
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;
  }
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
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;
  }
}
Example #10
0
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;
  }
}
Example #11
0
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;
  }
}