示例#1
0
static gboolean
gst_adder_sink_event (GstCollectPads2 * pads, GstCollectData2 * pad,
    GstEvent * event, gpointer user_data)
{
  GstAdder *adder = GST_ADDER (user_data);
  gboolean res = FALSE;

  GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad from %s",
      GST_EVENT_TYPE_NAME (event), GST_OBJECT_NAME (GST_EVENT_SRC (event)));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
      /* drop flush start events, as we forwarded one already when handing the
       * flushing seek on the sink pad */
      gst_event_unref (event);
      res = TRUE;
      break;
    case GST_EVENT_FLUSH_STOP:
      /* we received a flush-stop. We will only forward it when
       * flush_stop_pending is set, and we will unset it then.
       */
      if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
              TRUE, FALSE)) {
        g_atomic_int_set (&adder->new_segment_pending, TRUE);
        GST_DEBUG_OBJECT (pad->pad, "forwarding flush stop");
      } else {
        gst_event_unref (event);
        res = TRUE;
        GST_DEBUG_OBJECT (pad->pad, "eating flush stop");
      }
      /* Clear pending tags */
      if (adder->pending_events) {
        g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL);
        g_list_free (adder->pending_events);
        adder->pending_events = NULL;
      }
      break;
    case GST_EVENT_TAG:
      /* collect tags here so we can push them out when we collect data */
      adder->pending_events = g_list_append (adder->pending_events, event);
      res = TRUE;
      break;
    case GST_EVENT_NEWSEGMENT:
      if (g_atomic_int_compare_and_exchange (&adder->wait_for_new_segment,
              TRUE, FALSE)) {
        /* make sure we push a new segment, to inform about new basetime
         * see FIXME in gst_adder_collected() */
        g_atomic_int_set (&adder->new_segment_pending, TRUE);
      }
      gst_event_unref (event);
      res = TRUE;
      break;
    default:
      break;
  }
  return res;
}
示例#2
0
/* we can only accept caps that we and downstream can handle.
 * if we have filtercaps set, use those to constrain the target caps.
 */
static GstCaps *
gst_adder_sink_getcaps (GstPad * pad)
{
  GstAdder *adder;
  GstCaps *result, *peercaps, *sinkcaps, *filter_caps;

  adder = GST_ADDER (GST_PAD_PARENT (pad));

  GST_OBJECT_LOCK (adder);
  /* take filter */
  if ((filter_caps = adder->filter_caps))
    gst_caps_ref (filter_caps);
  GST_OBJECT_UNLOCK (adder);

  /* get the downstream possible caps */
  peercaps = gst_pad_peer_get_caps (adder->srcpad);

  /* get the allowed caps on this sinkpad, we use the fixed caps function so
   * that it does not call recursively in this function. */
  sinkcaps = gst_pad_get_fixed_caps_func (pad);
  if (peercaps) {
    /* restrict with filter-caps if any */
    if (filter_caps) {
      GST_DEBUG_OBJECT (adder, "filtering peer caps");
      result = gst_caps_intersect (peercaps, filter_caps);
      gst_caps_unref (peercaps);
      peercaps = result;
    }
    /* if the peer has caps, intersect */
    GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
    result = gst_caps_intersect (peercaps, sinkcaps);
    gst_caps_unref (peercaps);
    gst_caps_unref (sinkcaps);
  } else {
    /* the peer has no caps (or there is no peer), just use the allowed caps
     * of this sinkpad. */
    /* restrict with filter-caps if any */
    if (filter_caps) {
      GST_DEBUG_OBJECT (adder, "no peer caps, using filtered sinkcaps");
      result = gst_caps_intersect (sinkcaps, filter_caps);
      gst_caps_unref (sinkcaps);
    } else {
      GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
      result = sinkcaps;
    }
  }

  if (filter_caps)
    gst_caps_unref (filter_caps);

  GST_LOG_OBJECT (adder, "getting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
      GST_PAD_NAME (pad), result);

  return result;
}
示例#3
0
static gboolean
gst_adder_sink_event (GstPad * pad, GstEvent * event)
{
    GstAdder *adder;
    gboolean ret = TRUE;

    adder = GST_ADDER (gst_pad_get_parent (pad));

    GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
               GST_DEBUG_PAD_NAME (pad));

    switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:
        /* we received a flush-stop. The collect_event function will push the
         * event past our element. We simply forward all flush-stop events, even
         * when no flush-stop was pending, this is required because collectpads
         * does not provide an API to handle-but-not-forward the flush-stop.
         * We unset the pending flush-stop flag so that we don't send anymore
         * flush-stop from the collect function later.
         */
        GST_OBJECT_LOCK (adder->collect);
        adder->segment_pending = TRUE;
        adder->flush_stop_pending = FALSE;
        /* Clear pending tags */
        if (adder->pending_events) {
            g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL);
            g_list_free (adder->pending_events);
            adder->pending_events = NULL;
        }
        GST_OBJECT_UNLOCK (adder->collect);
        break;
    case GST_EVENT_TAG:
        GST_OBJECT_LOCK (adder->collect);
        /* collect tags here so we can push them out when we collect data */
        adder->pending_events = g_list_append (adder->pending_events, event);
        GST_OBJECT_UNLOCK (adder->collect);
        goto beach;
    default:
        break;
    }

    /* now GstCollectPads can take care of the rest, e.g. EOS */
    ret = adder->collect_event (pad, event);

beach:
    gst_object_unref (adder);
    return ret;
}
示例#4
0
static gboolean
gst_adder_query (GstPad * pad, GstQuery * query)
{
  GstAdder *adder = GST_ADDER (gst_pad_get_parent (pad));
  gboolean res = FALSE;

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
    {
      GstFormat format;

      gst_query_parse_position (query, &format, NULL);

      switch (format) {
        case GST_FORMAT_TIME:
          /* FIXME, bring to stream time, might be tricky */
          gst_query_set_position (query, format, adder->timestamp);
          res = TRUE;
          break;
        case GST_FORMAT_DEFAULT:
          gst_query_set_position (query, format, adder->offset);
          res = TRUE;
          break;
        default:
          break;
      }
      break;
    }
    case GST_QUERY_DURATION:
      res = gst_adder_query_duration (adder, query);
      break;
    case GST_QUERY_LATENCY:
      res = gst_adder_query_latency (adder, query);
      break;
    default:
      /* FIXME, needs a custom query handler because we have multiple
       * sinkpads */
      res = gst_pad_query_default (pad, query);
      break;
  }

  gst_object_unref (adder);
  return res;
}
示例#5
0
static gboolean
gst_adder_src_event (GstPad * pad, GstEvent * event)
{
  GstAdder *adder;
  gboolean result;

  adder = GST_ADDER (gst_pad_get_parent (pad));

  GST_DEBUG_OBJECT (pad, "Got %s event on src pad from %s",
      GST_EVENT_TYPE_NAME (event), GST_OBJECT_NAME (GST_EVENT_SRC (event)));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      GstSeekFlags flags;
      GstSeekType curtype, endtype;
      gint64 cur, end;
      gboolean flush;

      /* parse the seek parameters */
      gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
          &cur, &endtype, &end);

      if ((curtype != GST_SEEK_TYPE_NONE) && (curtype != GST_SEEK_TYPE_SET)) {
        result = FALSE;
        GST_DEBUG_OBJECT (adder,
            "seeking failed, unhandled seek type for start: %d", curtype);
        goto done;
      }
      if ((endtype != GST_SEEK_TYPE_NONE) && (endtype != GST_SEEK_TYPE_SET)) {
        result = FALSE;
        GST_DEBUG_OBJECT (adder,
            "seeking failed, unhandled seek type for end: %d", endtype);
        goto done;
      }

      flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;

      /* check if we are flushing */
      if (flush) {
        /* flushing seek, start flush downstream, the flush will be done
         * when all pads received a FLUSH_STOP.
         * Make sure we accept nothing anymore and return WRONG_STATE.
         * We send a flush-start before, to ensure no streaming is done
         * as we need to take the stream lock.
         */
        gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
        gst_collect_pads2_set_flushing (adder->collect, TRUE);

        /* We can't send FLUSH_STOP here since upstream could start pushing data
         * after we unlock adder->collect.
         * We set flush_stop_pending to TRUE instead and send FLUSH_STOP after
         * forwarding the seek upstream or from gst_adder_collected,
         * whichever happens first.
         */
        g_atomic_int_set (&adder->flush_stop_pending, TRUE);
      }
      GST_DEBUG_OBJECT (adder, "handling seek event: %" GST_PTR_FORMAT, event);

      /* now wait for the collected to be finished and mark a new
       * segment. After we have the lock, no collect function is running and no
       * new collect function will be called for as long as we're flushing. */
      GST_COLLECT_PADS2_STREAM_LOCK (adder->collect);
      if (curtype == GST_SEEK_TYPE_SET)
        adder->segment_start = cur;
      else
        adder->segment_start = 0;
      if (endtype == GST_SEEK_TYPE_SET)
        adder->segment_end = end;
      else
        adder->segment_end = GST_CLOCK_TIME_NONE;
      if (flush) {
        /* Yes, we need to call _set_flushing again *WHEN* the streaming threads
         * have stopped so that the cookie gets properly updated. */
        gst_collect_pads2_set_flushing (adder->collect, TRUE);
      }
      GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect);
      GST_DEBUG_OBJECT (adder, "forwarding seek event: %" GST_PTR_FORMAT,
          event);

      /* we're forwarding seek to all upstream peers and wait for one to reply
       * with a newsegment-event before we send a newsegment-event downstream */
      g_atomic_int_set (&adder->wait_for_new_segment, TRUE);
      result = forward_event (adder, event, flush);
      if (!result) {
        /* seek failed. maybe source is a live source. */
        GST_DEBUG_OBJECT (adder, "seeking failed");
      }
      if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
              TRUE, FALSE)) {
        GST_DEBUG_OBJECT (adder, "pending flush stop");
        gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop ());
      }
      break;
    }
    case GST_EVENT_QOS:
      /* QoS might be tricky */
      result = FALSE;
      break;
    case GST_EVENT_NAVIGATION:
      /* navigation is rather pointless. */
      result = FALSE;
      break;
    default:
      /* just forward the rest for now */
      GST_DEBUG_OBJECT (adder, "forward unhandled event: %s",
          GST_EVENT_TYPE_NAME (event));
      result = forward_event (adder, event, FALSE);
      break;
  }

done:
  gst_object_unref (adder);

  return result;
}
示例#6
0
/* the first caps we receive on any of the sinkpads will define the caps for all
 * the other sinkpads because we can only mix streams with the same caps.
 */
static gboolean
gst_adder_setcaps (GstPad * pad, GstCaps * caps)
{
  GstAdder *adder;
  GList *pads;
  GstStructure *structure;
  const char *media_type;

  adder = GST_ADDER (GST_PAD_PARENT (pad));

  GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
      GST_PAD_NAME (pad), caps);

  /* FIXME, see if the other pads can accept the format. Also lock the
   * format on the other pads to this new format. */
  GST_OBJECT_LOCK (adder);
  pads = GST_ELEMENT (adder)->pads;
  while (pads) {
    GstPad *otherpad = GST_PAD (pads->data);

    if (otherpad != pad) {
      gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
    }
    pads = g_list_next (pads);
  }
  GST_OBJECT_UNLOCK (adder);

  /* parse caps now */
  structure = gst_caps_get_structure (caps, 0);
  media_type = gst_structure_get_name (structure);
  if (strcmp (media_type, "audio/x-raw-int") == 0) {
    adder->format = GST_ADDER_FORMAT_INT;
    gst_structure_get_int (structure, "width", &adder->width);
    gst_structure_get_int (structure, "depth", &adder->depth);
    gst_structure_get_int (structure, "endianness", &adder->endianness);
    gst_structure_get_boolean (structure, "signed", &adder->is_signed);

    GST_INFO_OBJECT (pad, "parse_caps sets adder to format int, %d bit",
        adder->width);

    if (adder->endianness != G_BYTE_ORDER)
      goto not_supported;

    switch (adder->width) {
      case 8:
        adder->func = (adder->is_signed ?
            (GstAdderFunction) add_int8 : (GstAdderFunction) add_uint8);
        adder->sample_size = 1;
        break;
      case 16:
        adder->func = (adder->is_signed ?
            (GstAdderFunction) add_int16 : (GstAdderFunction) add_uint16);
        adder->sample_size = 2;
        break;
      case 32:
        adder->func = (adder->is_signed ?
            (GstAdderFunction) add_int32 : (GstAdderFunction) add_uint32);
        adder->sample_size = 4;
        break;
      default:
        goto not_supported;
    }
  } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
    adder->format = GST_ADDER_FORMAT_FLOAT;
    gst_structure_get_int (structure, "width", &adder->width);
    gst_structure_get_int (structure, "endianness", &adder->endianness);

    GST_INFO_OBJECT (pad, "parse_caps sets adder to format float, %d bit",
        adder->width);

    if (adder->endianness != G_BYTE_ORDER)
      goto not_supported;

    switch (adder->width) {
      case 32:
        adder->func = (GstAdderFunction) add_float32;
        adder->sample_size = 4;
        break;
      case 64:
        adder->func = (GstAdderFunction) add_float64;
        adder->sample_size = 8;
        break;
      default:
        goto not_supported;
    }
  } else {
    goto not_supported;
  }

  gst_structure_get_int (structure, "channels", &adder->channels);
  gst_structure_get_int (structure, "rate", &adder->rate);
  /* precalc bps */
  adder->bps = (adder->width / 8) * adder->channels;

  return TRUE;

  /* ERRORS */
not_supported:
  {
    GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
    return FALSE;
  }
}
示例#7
0
static gboolean
gst_adder_sink_event (GstCollectPads * pads, GstCollectData * pad,
    GstEvent * event, gpointer user_data)
{
  GstAdder *adder = GST_ADDER (user_data);
  gboolean res = TRUE, discard = FALSE;

  GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad",
      GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      res = gst_adder_setcaps (adder, pad->pad, caps);
      gst_event_unref (event);
      event = NULL;
      break;
    }
    case GST_EVENT_FLUSH_START:
      /* ensure that we will send a flush stop */
      res = gst_collect_pads_event_default (pads, pad, event, discard);
      event = NULL;
      GST_COLLECT_PADS_STREAM_LOCK (adder->collect);
      adder->flush_stop_pending = TRUE;
      GST_COLLECT_PADS_STREAM_UNLOCK (adder->collect);
      break;
    case GST_EVENT_FLUSH_STOP:
      /* we received a flush-stop. We will only forward it when
       * flush_stop_pending is set, and we will unset it then.
       */
      g_atomic_int_set (&adder->new_segment_pending, TRUE);
      GST_COLLECT_PADS_STREAM_LOCK (adder->collect);
      if (adder->flush_stop_pending) {
        GST_DEBUG_OBJECT (pad->pad, "forwarding flush stop");
        res = gst_collect_pads_event_default (pads, pad, event, discard);
        adder->flush_stop_pending = FALSE;
        event = NULL;
      } else {
        discard = TRUE;
        GST_DEBUG_OBJECT (pad->pad, "eating flush stop");
      }
      GST_COLLECT_PADS_STREAM_UNLOCK (adder->collect);
      /* Clear pending tags */
      if (adder->pending_events) {
        g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL);
        g_list_free (adder->pending_events);
        adder->pending_events = NULL;
      }
      break;
    case GST_EVENT_TAG:
      /* collect tags here so we can push them out when we collect data */
      adder->pending_events = g_list_append (adder->pending_events, event);
      event = NULL;
      break;
    case GST_EVENT_SEGMENT:{
      const GstSegment *segment;
      gst_event_parse_segment (event, &segment);
      if (segment->rate != adder->segment.rate) {
        GST_ERROR_OBJECT (pad->pad,
            "Got segment event with wrong rate %lf, expected %lf",
            segment->rate, adder->segment.rate);
        res = FALSE;
        gst_event_unref (event);
        event = NULL;
      }
      discard = TRUE;
      break;
    }
    default:
      break;
  }

  if (G_LIKELY (event))
    return gst_collect_pads_event_default (pads, pad, event, discard);
  else
    return res;
}
示例#8
0
/* we can only accept caps that we and downstream can handle.
 * if we have filtercaps set, use those to constrain the target caps.
 */
static GstCaps *
gst_adder_sink_getcaps (GstPad * pad, GstCaps * filter)
{
  GstAdder *adder;
  GstCaps *result, *peercaps, *current_caps, *filter_caps;
  GstStructure *s;
  gint i, n;

  adder = GST_ADDER (GST_PAD_PARENT (pad));

  GST_OBJECT_LOCK (adder);
  /* take filter */
  if ((filter_caps = adder->filter_caps)) {
    if (filter)
      filter_caps =
          gst_caps_intersect_full (filter, filter_caps,
          GST_CAPS_INTERSECT_FIRST);
    else
      gst_caps_ref (filter_caps);
  } else {
    filter_caps = filter ? gst_caps_ref (filter) : NULL;
  }
  GST_OBJECT_UNLOCK (adder);

  if (filter_caps && gst_caps_is_empty (filter_caps)) {
    GST_WARNING_OBJECT (pad, "Empty filter caps");
    return filter_caps;
  }

  /* get the downstream possible caps */
  peercaps = gst_pad_peer_query_caps (adder->srcpad, filter_caps);

  /* get the allowed caps on this sinkpad */
  GST_OBJECT_LOCK (adder);
  current_caps =
      adder->current_caps ? gst_caps_ref (adder->current_caps) : NULL;
  if (current_caps == NULL) {
    current_caps = gst_pad_get_pad_template_caps (pad);
    if (!current_caps)
      current_caps = gst_caps_new_any ();
  }
  GST_OBJECT_UNLOCK (adder);

  if (peercaps) {
    /* if the peer has caps, intersect */
    GST_DEBUG_OBJECT (adder, "intersecting peer and our caps");
    result =
        gst_caps_intersect_full (peercaps, current_caps,
        GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (peercaps);
    gst_caps_unref (current_caps);
  } else {
    /* the peer has no caps (or there is no peer), just use the allowed caps
     * of this sinkpad. */
    /* restrict with filter-caps if any */
    if (filter_caps) {
      GST_DEBUG_OBJECT (adder, "no peer caps, using filtered caps");
      result =
          gst_caps_intersect_full (filter_caps, current_caps,
          GST_CAPS_INTERSECT_FIRST);
      gst_caps_unref (current_caps);
    } else {
      GST_DEBUG_OBJECT (adder, "no peer caps, using our caps");
      result = current_caps;
    }
  }

  result = gst_caps_make_writable (result);

  n = gst_caps_get_size (result);
  for (i = 0; i < n; i++) {
    GstStructure *sref;

    s = gst_caps_get_structure (result, i);
    sref = gst_structure_copy (s);
    gst_structure_set (sref, "channels", GST_TYPE_INT_RANGE, 0, 2, NULL);
    if (gst_structure_is_subset (s, sref)) {
      /* This field is irrelevant when in mono or stereo */
      gst_structure_remove_field (s, "channel-mask");
    }
    gst_structure_free (sref);
  }

  if (filter_caps)
    gst_caps_unref (filter_caps);

  GST_LOG_OBJECT (adder, "getting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
      GST_PAD_NAME (pad), result);

  return result;
}