コード例 #1
0
ファイル: mpegtsbase.c プロジェクト: Haifen/gst-plugins-bad
static void
mpegts_base_loop (MpegTSBase * base)
{
  GstFlowReturn ret = GST_FLOW_ERROR;

  switch (base->mode) {
    case BASE_MODE_SCANNING:
      /* Find first sync point */
      ret = mpegts_base_scan (base);
      if (G_UNLIKELY (ret != GST_FLOW_OK))
        goto error;
      base->mode = BASE_MODE_STREAMING;
      GST_DEBUG ("Changing to Streaming");
      break;
    case BASE_MODE_SEEKING:
      /* FIXME : unclear if we still need mode_seeking... */
      base->mode = BASE_MODE_STREAMING;
      break;
    case BASE_MODE_STREAMING:
    {
      GstBuffer *buf = NULL;

      GST_DEBUG ("Pulling data from %" G_GUINT64_FORMAT, base->seek_offset);

      ret = gst_pad_pull_range (base->sinkpad, base->seek_offset,
          100 * base->packetsize, &buf);
      if (G_UNLIKELY (ret != GST_FLOW_OK))
        goto error;
      base->seek_offset += gst_buffer_get_size (buf);
      ret = mpegts_base_chain (base->sinkpad, GST_OBJECT_CAST (base), buf);
      if (G_UNLIKELY (ret != GST_FLOW_OK))
        goto error;
    }
      break;
    case BASE_MODE_PUSHING:
      GST_WARNING ("wrong BASE_MODE_PUSHING mode in pull loop");
      break;
  }

  return;

error:
  {
    const gchar *reason = gst_flow_get_name (ret);
    GST_DEBUG_OBJECT (base, "Pausing task, reason %s", reason);
    if (ret == GST_FLOW_EOS) {
      if (!GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base,
              gst_event_new_eos ()))
        GST_ELEMENT_ERROR (base, STREAM, FAILED,
            (_("Internal data stream error.")),
            ("No program activated before EOS"));
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (base, STREAM, FAILED,
          (_("Internal data stream error.")),
          ("stream stopped, reason %s", reason));
      GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ());
    }
    gst_pad_pause_task (base->sinkpad);
  }
}
コード例 #2
0
/**
 * hls_progress_buffer_loop()
 *
 * Primary function for push-mode.  Pulls data from progressbuffer's cache queue.
 */
static void hls_progress_buffer_loop(void *data)
{
    HLSProgressBuffer* element = HLS_PROGRESS_BUFFER(data);
    GstFlowReturn      result = GST_FLOW_OK;

    g_mutex_lock(element->lock);

    while (element->srcresult == GST_FLOW_OK && !cache_has_enough_data(element->cache[element->cache_read_index]))
    {
        if (element->is_eos)
        {
            gst_pad_push_event(element->srcpad, gst_event_new_eos());
            element->srcresult = GST_FLOW_WRONG_STATE;
            break;
        }

        if (!element->is_eos)
        {
            g_cond_wait(element->add_cond, element->lock);
        }
    }

    result = element->srcresult;

    if (result == GST_FLOW_OK)
    {
        GstBuffer *buffer = NULL;
        guint64 read_position = cache_read_buffer(element->cache[element->cache_read_index], &buffer);

        if (read_position == element->cache_size[element->cache_read_index])
        {
            element->cache_write_ready[element->cache_read_index] = TRUE;
            element->cache_read_index = (element->cache_read_index + 1) % NUM_OF_CACHED_SEGMENTS;
            send_hls_not_full_message(element);
            g_cond_signal(element->del_cond);
        }

        g_mutex_unlock(element->lock);

        gst_buffer_set_caps(buffer, GST_PAD_CAPS(element->sinkpad));

        // Send the data to the hls progressbuffer source pad
        result = gst_pad_push(element->srcpad, buffer);

        g_mutex_lock(element->lock);
        if (GST_FLOW_OK == element->srcresult || GST_FLOW_OK != result)
            element->srcresult = result;
        else
            result = element->srcresult;
        g_mutex_unlock(element->lock);
    }
    else
    {
        g_mutex_unlock(element->lock);
    }

    if (result != GST_FLOW_OK && !element->is_flushing)
        gst_pad_pause_task(element->srcpad);
}
コード例 #3
0
ファイル: gstpngdec.c プロジェクト: ChinnaSuhas/ossbuild
static void
user_read_data (png_structp png_ptr, png_bytep data, png_size_t length)
{
  GstPngDec *pngdec;
  GstBuffer *buffer;
  GstFlowReturn ret = GST_FLOW_OK;
  guint size;

  pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));

  GST_LOG ("reading %" G_GSIZE_FORMAT " bytes of data at offset %d", length,
      pngdec->offset);

  ret = gst_pad_pull_range (pngdec->sinkpad, pngdec->offset, length, &buffer);
  if (ret != GST_FLOW_OK)
    goto pause;

  size = GST_BUFFER_SIZE (buffer);

  if (size != length)
    goto short_buffer;

  memcpy (data, GST_BUFFER_DATA (buffer), size);

  gst_buffer_unref (buffer);

  pngdec->offset += length;

  return;

  /* ERRORS */
pause:
  {
    GST_INFO_OBJECT (pngdec, "pausing task, reason %s",
        gst_flow_get_name (ret));
    gst_pad_pause_task (pngdec->sinkpad);
    if (ret == GST_FLOW_UNEXPECTED) {
      gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
    } else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED) {
      GST_ELEMENT_ERROR (pngdec, STREAM, FAILED,
          (_("Internal data stream error.")),
          ("stream stopped, reason %s", gst_flow_get_name (ret)));
      gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
    }
    png_error (png_ptr, "Internal data stream error.");
    return;
  }
short_buffer:
  {
    gst_buffer_unref (buffer);
    GST_ELEMENT_ERROR (pngdec, STREAM, FAILED,
        (_("Internal data stream error.")),
        ("Read %u, needed %" G_GSIZE_FORMAT "bytes", size, length));
    ret = GST_FLOW_ERROR;
    goto pause;
  }
}
コード例 #4
0
ファイル: gsttcpmixsrc.c プロジェクト: duzy/gst-switch
static gboolean
gst_tcp_mix_src_pad_pause (GstTCPMixSrcPad * pad, GstTaskFunction func)
{
  gboolean res;

  if (GST_PAD_TASK (pad) != NULL) {     // FIXME: pad->status == started
    res = gst_pad_pause_task (GST_PAD (pad));
  }

  return res;
}
コード例 #5
0
static gboolean
gst_rnd_buffer_size_src_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstRndBufferSize *self;
  GstSeekType start_type;
  GstSeekFlags flags;
  GstFormat format;
  gint64 start;

  if (GST_EVENT_TYPE (event) != GST_EVENT_SEEK) {
    GST_WARNING_OBJECT (pad, "dropping %s event", GST_EVENT_TYPE_NAME (event));
    return FALSE;
  }

  self = GST_RND_BUFFER_SIZE (parent);
  gst_event_parse_seek (event, NULL, &format, &flags, &start_type, &start,
      NULL, NULL);

  if (format != GST_FORMAT_BYTES) {
    GST_WARNING_OBJECT (pad, "only BYTE format supported");
    return FALSE;
  }
  if (start_type != GST_SEEK_TYPE_SET) {
    GST_WARNING_OBJECT (pad, "only SEEK_TYPE_SET supported");
    return FALSE;
  }

  if ((flags & GST_SEEK_FLAG_FLUSH)) {
    gst_pad_push_event (self->srcpad, gst_event_new_flush_start ());
    gst_pad_push_event (self->sinkpad, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (self->sinkpad);
  }

  GST_PAD_STREAM_LOCK (self->sinkpad);

  if ((flags & GST_SEEK_FLAG_FLUSH)) {
    gst_pad_push_event (self->srcpad, gst_event_new_flush_stop (TRUE));
    gst_pad_push_event (self->sinkpad, gst_event_new_flush_stop (TRUE));
  }

  GST_INFO_OBJECT (pad, "seeking to offset %" G_GINT64_FORMAT, start);

  self->offset = start;
  self->need_newsegment = TRUE;

  gst_pad_start_task (self->sinkpad, (GstTaskFunction) gst_rnd_buffer_size_loop,
      self);

  GST_PAD_STREAM_UNLOCK (self->sinkpad);
  return TRUE;
}
コード例 #6
0
static void
gst_vaapiencode_buffer_loop (GstVaapiEncode * encode)
{
  GstFlowReturn ret;
  const gint64 timeout = 50000; /* microseconds */

  ret = gst_vaapiencode_push_frame (encode, timeout);
  if (ret == GST_FLOW_OK || ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT)
    return;

  gst_pad_pause_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
}
コード例 #7
0
/* called repeadedly with @pad as the source pad. This function should push out
 * data to the peer element. */
static void
gst_ts_shifter_loop (GstPad * pad)
{
  GstTSShifter *ts;
  GstFlowReturn ret;

  ts = GST_TS_SHIFTER (GST_PAD_PARENT (pad));

  /* have to lock for thread-safety */
  FLOW_MUTEX_LOCK_CHECK (ts, ts->srcresult, out_flushing);

  if (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos) {
    GST_CAT_LOG_OBJECT (ts_flow, ts, "empty, waiting for new data");
    do {
      /* Wait for data to be available, we could be unlocked because of a flush. */
      FLOW_WAIT_ADD_CHECK (ts, ts->srcresult, out_flushing);
    }
    while (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos);
  }
  ret = gst_ts_shifter_pop (ts);
  ts->srcresult = ret;
  if (ret != GST_FLOW_OK)
    goto out_flushing;

  FLOW_MUTEX_UNLOCK (ts);

  return;

  /* ERRORS */
out_flushing:
  {
    gboolean eos = ts->is_eos;
    GstFlowReturn ret = ts->srcresult;

    gst_pad_pause_task (ts->srcpad);
    FLOW_MUTEX_UNLOCK (ts);
    GST_CAT_LOG_OBJECT (ts_flow, ts,
        "pause task, reason:  %s", gst_flow_get_name (ts->srcresult));
    /* let app know about us giving up if upstream is not expected to do so */
    /* UNEXPECTED is already taken care of elsewhere */
    if (eos && (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS)) {
      GST_ELEMENT_ERROR (ts, STREAM, FAILED,
          ("Internal data flow error."),
          ("streaming task paused, reason %s (%d)",
              gst_flow_get_name (ret), ret));
      GST_CAT_LOG_OBJECT (ts_flow, ts, "pushing EOS");
      gst_pad_push_event (ts->srcpad, gst_event_new_eos ());
    }
    return;
  }
}
コード例 #8
0
static gboolean
gst_type_find_element_activate_src_mode (GstPad * pad, GstObject * parent,
    GstPadMode mode, gboolean active)
{
  gboolean res;
  GstTypeFindElement *typefind;

  typefind = GST_TYPE_FIND_ELEMENT (parent);

  switch (mode) {
    case GST_PAD_MODE_PULL:
      /* make sure our task stops pushing, we can't call _stop here because this
       * activation might happen from the streaming thread. */
      gst_pad_pause_task (typefind->sink);
      res = gst_pad_activate_mode (typefind->sink, mode, active);
      break;
    default:
      res = TRUE;
      break;
  }
  return res;
}
コード例 #9
0
static void
gst_tta_parse_loop (GstTtaParse * ttaparse)
{
  GstFlowReturn ret;

  if (!ttaparse->header_parsed)
    if ((ret = gst_tta_parse_parse_header (ttaparse)) != GST_FLOW_OK)
      goto pause;
  if ((ret = gst_tta_parse_stream_data (ttaparse)) != GST_FLOW_OK)
    goto pause;

  return;

pause:
  GST_LOG_OBJECT (ttaparse, "pausing task, %s", gst_flow_get_name (ret));
  gst_pad_pause_task (ttaparse->sinkpad);
  if (ret == GST_FLOW_UNEXPECTED) {
    gst_pad_push_event (ttaparse->srcpad, gst_event_new_eos ());
  } else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED) {
    GST_ELEMENT_FLOW_ERROR (ttaparse, ret);
    gst_pad_push_event (ttaparse->srcpad, gst_event_new_eos ());
  }
}
コード例 #10
0
static GstFlowReturn
gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
    guint length, GstBuffer ** buffer)
{
  GstRTPDTMFSrcEvent *event;
  GstRTPDTMFSrc *dtmfsrc;
  GstClock *clock;
  GstClockID *clockid;
  GstClockReturn clockret;
  GstMessage *message;
  GQueue messages = G_QUEUE_INIT;

  dtmfsrc = GST_RTP_DTMF_SRC (basesrc);

  do {

    if (dtmfsrc->payload == NULL) {
      GST_DEBUG_OBJECT (dtmfsrc, "popping");
      event = g_async_queue_pop (dtmfsrc->event_queue);

      GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);

      switch (event->event_type) {
        case RTP_DTMF_EVENT_TYPE_STOP:
          GST_WARNING_OBJECT (dtmfsrc,
              "Received a DTMF stop event when already stopped");
          gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
          break;

        case RTP_DTMF_EVENT_TYPE_START:
          dtmfsrc->first_packet = TRUE;
          dtmfsrc->last_packet = FALSE;
          /* Set the redundancy on the first packet */
          dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
          if (!gst_rtp_dtmf_prepare_timestamps (dtmfsrc))
            goto no_clock;

          g_queue_push_tail (&messages,
              gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
                  event));
          dtmfsrc->payload = event->payload;
          dtmfsrc->payload->duration =
              dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
          event->payload = NULL;
          break;

        case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
          /*
           * We're pushing it back because it has to stay in there until
           * the task is really paused (and the queue will then be flushed
           */
          GST_OBJECT_LOCK (dtmfsrc);
          if (dtmfsrc->paused) {
            g_async_queue_push (dtmfsrc->event_queue, event);
            goto paused_locked;
          }
          GST_OBJECT_UNLOCK (dtmfsrc);
          break;
      }

      gst_rtp_dtmf_src_event_free (event);
    } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet &&
        (dtmfsrc->timestamp - dtmfsrc->start_timestamp) / GST_MSECOND >=
        MIN_PULSE_DURATION) {
      GST_DEBUG_OBJECT (dtmfsrc, "try popping");
      event = g_async_queue_try_pop (dtmfsrc->event_queue);


      if (event != NULL) {
        GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type);

        switch (event->event_type) {
          case RTP_DTMF_EVENT_TYPE_START:
            GST_WARNING_OBJECT (dtmfsrc,
                "Received two consecutive DTMF start events");
            gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
            break;

          case RTP_DTMF_EVENT_TYPE_STOP:
            dtmfsrc->first_packet = FALSE;
            dtmfsrc->last_packet = TRUE;
            /* Set the redundancy on the last packet */
            dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
            g_queue_push_tail (&messages,
                gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
                    event));
            break;

          case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
            /*
             * We're pushing it back because it has to stay in there until
             * the task is really paused (and the queue will then be flushed)
             */
            GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
            GST_OBJECT_LOCK (dtmfsrc);
            if (dtmfsrc->paused) {
              g_async_queue_push (dtmfsrc->event_queue, event);
              goto paused_locked;
            }
            GST_OBJECT_UNLOCK (dtmfsrc);
            break;
        }
        gst_rtp_dtmf_src_event_free (event);
      }
    }
  } while (dtmfsrc->payload == NULL);


  GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");

  clock = gst_element_get_clock (GST_ELEMENT (basesrc));
  if (!clock)
    goto no_clock;
  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
      gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
  gst_object_unref (clock);

  GST_OBJECT_LOCK (dtmfsrc);
  if (!dtmfsrc->paused) {
    dtmfsrc->clockid = clockid;
    GST_OBJECT_UNLOCK (dtmfsrc);

    clockret = gst_clock_id_wait (clockid, NULL);

    GST_OBJECT_LOCK (dtmfsrc);
    if (dtmfsrc->paused)
      clockret = GST_CLOCK_UNSCHEDULED;
  } else {
    clockret = GST_CLOCK_UNSCHEDULED;
  }
  gst_clock_id_unref (clockid);
  dtmfsrc->clockid = NULL;
  GST_OBJECT_UNLOCK (dtmfsrc);

  while ((message = g_queue_pop_head (&messages)) != NULL)
    gst_element_post_message (GST_ELEMENT (dtmfsrc), message);

  if (clockret == GST_CLOCK_UNSCHEDULED) {
    goto paused;
  }

send_last:

  if (dtmfsrc->dirty)
    if (!gst_rtp_dtmf_src_negotiate (basesrc))
      return GST_FLOW_NOT_NEGOTIATED;

  /* create buffer to hold the payload */
  *buffer = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc);

  if (dtmfsrc->redundancy_count)
    dtmfsrc->redundancy_count--;

  /* Only the very first one has a marker */
  dtmfsrc->first_packet = FALSE;

  /* This is the end of the event */
  if (dtmfsrc->last_packet == TRUE && dtmfsrc->redundancy_count == 0) {

    g_slice_free (GstRTPDTMFPayload, dtmfsrc->payload);
    dtmfsrc->payload = NULL;

    dtmfsrc->last_packet = FALSE;
  }

  return GST_FLOW_OK;

paused_locked:

  GST_OBJECT_UNLOCK (dtmfsrc);

paused:

  if (dtmfsrc->payload) {
    dtmfsrc->first_packet = FALSE;
    dtmfsrc->last_packet = TRUE;
    /* Set the redundanc on the last packet */
    dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
    goto send_last;
  } else {
    return GST_FLOW_FLUSHING;
  }

no_clock:
  GST_ELEMENT_ERROR (dtmfsrc, STREAM, MUX, ("No available clock"),
      ("No available clock"));
  gst_pad_pause_task (GST_BASE_SRC_PAD (dtmfsrc));
  return GST_FLOW_ERROR;
}
コード例 #11
0
static void
gst_rnd_buffer_size_loop (GstRndBufferSize * self)
{
  GstBuffer *buf = NULL;
  GstFlowReturn ret;
  guint num_bytes, size;

  if (G_UNLIKELY (self->min > self->max))
    goto bogus_minmax;

  if (G_UNLIKELY (self->min != self->max)) {
    num_bytes = g_rand_int_range (self->rand, self->min, self->max);
  } else {
    num_bytes = self->min;
  }

  GST_LOG_OBJECT (self, "pulling %u bytes at offset %" G_GUINT64_FORMAT,
      num_bytes, self->offset);

  ret = gst_pad_pull_range (self->sinkpad, self->offset, num_bytes, &buf);

  if (ret != GST_FLOW_OK)
    goto pull_failed;

  size = gst_buffer_get_size (buf);

  if (size < num_bytes) {
    GST_WARNING_OBJECT (self, "short buffer: %u bytes", size);
  }

  if (self->need_newsegment) {
    GstSegment segment;

    gst_segment_init (&segment, GST_FORMAT_BYTES);
    segment.start = self->offset;
    gst_pad_push_event (self->srcpad, gst_event_new_segment (&segment));
    self->need_newsegment = FALSE;
  }

  self->offset += size;

  ret = gst_pad_push (self->srcpad, buf);

  if (ret != GST_FLOW_OK)
    goto push_failed;

  return;

pause_task:
  {
    GST_DEBUG_OBJECT (self, "pausing task");
    gst_pad_pause_task (self->sinkpad);
    return;
  }

pull_failed:
  {
    if (ret == GST_FLOW_EOS) {
      GST_DEBUG_OBJECT (self, "eos");
      gst_pad_push_event (self->srcpad, gst_event_new_eos ());
    } else {
      GST_WARNING_OBJECT (self, "pull_range flow: %s", gst_flow_get_name (ret));
    }
    goto pause_task;
  }

push_failed:
  {
    GST_DEBUG_OBJECT (self, "push flow: %s", gst_flow_get_name (ret));
    if (ret == GST_FLOW_EOS) {
      GST_DEBUG_OBJECT (self, "eos");
      gst_pad_push_event (self->srcpad, gst_event_new_eos ());
    } else if (ret < GST_FLOW_EOS || ret == GST_FLOW_NOT_LINKED) {
      GST_ELEMENT_ERROR (self, STREAM, FAILED,
          ("Internal data stream error."),
          ("streaming stopped, reason: %s", gst_flow_get_name (ret)));
    }
    goto pause_task;
  }

bogus_minmax:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS,
        ("The minimum buffer size is smaller than the maximum buffer size."),
        ("buffer sizes: max=%d, min=%d", self->min, self->max));
    goto pause_task;
  }
}
コード例 #12
0
static void
gst_amc_audio_dec_loop (GstAmcAudioDec * self)
{
  GstFlowReturn flow_ret = GST_FLOW_OK;
  gboolean is_eos;
  GstAmcBuffer *buf;
  GstAmcBufferInfo buffer_info;
  gint idx;
  GError *err = NULL;

  GST_AUDIO_DECODER_STREAM_LOCK (self);

retry:
  /*if (self->input_caps_changed) {
     idx = INFO_OUTPUT_FORMAT_CHANGED;
     } else { */
  GST_DEBUG_OBJECT (self, "Waiting for available output buffer");
  GST_AUDIO_DECODER_STREAM_UNLOCK (self);
  /* Wait at most 100ms here, some codecs don't fail dequeueing if
   * the codec is flushing, causing deadlocks during shutdown */
  idx =
      gst_amc_codec_dequeue_output_buffer (self->codec, &buffer_info, 100000,
      &err);
  GST_AUDIO_DECODER_STREAM_LOCK (self);
  /*} */

  if (idx < 0) {
    if (self->flushing) {
      g_clear_error (&err);
      goto flushing;
    }

    switch (idx) {
      case INFO_OUTPUT_BUFFERS_CHANGED:
        /* Handled internally */
        g_assert_not_reached ();
        break;
      case INFO_OUTPUT_FORMAT_CHANGED:{
        GstAmcFormat *format;
        gchar *format_string;

        GST_DEBUG_OBJECT (self, "Output format has changed");

        format = gst_amc_codec_get_output_format (self->codec, &err);
        if (!format)
          goto format_error;

        format_string = gst_amc_format_to_string (format, &err);
        if (err) {
          gst_amc_format_free (format);
          goto format_error;
        }
        GST_DEBUG_OBJECT (self, "Got new output format: %s", format_string);
        g_free (format_string);

        if (!gst_amc_audio_dec_set_src_caps (self, format)) {
          gst_amc_format_free (format);
          goto format_error;
        }
        gst_amc_format_free (format);

        goto retry;

      }
      case INFO_TRY_AGAIN_LATER:
        GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out");
        goto retry;

      case G_MININT:
        GST_ERROR_OBJECT (self, "Failure dequeueing output buffer");
        goto dequeue_error;

      default:
        g_assert_not_reached ();
        break;
    }

    goto retry;
  }

  GST_DEBUG_OBJECT (self,
      "Got output buffer at index %d: offset %d size %d time %" G_GINT64_FORMAT
      " flags 0x%08x", idx, buffer_info.offset, buffer_info.size,
      buffer_info.presentation_time_us, buffer_info.flags);

  is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM);

  buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err);
  if (!buf)
    goto failed_to_get_output_buffer;

  if (buffer_info.size > 0) {
    GstBuffer *outbuf;
    GstMapInfo minfo;

    /* This sometimes happens at EOS or if the input is not properly framed,
     * let's handle it gracefully by allocating a new buffer for the current
     * caps and filling it
     */

    if (buffer_info.size % self->info.bpf != 0)
      goto invalid_buffer_size;

    outbuf =
        gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self),
        buffer_info.size);
    if (!outbuf)
      goto failed_allocate;

    gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE);
    if (self->needs_reorder) {
      gint i, n_samples, c, n_channels;
      gint *reorder_map = self->reorder_map;
      gint16 *dest, *source;

      dest = (gint16 *) minfo.data;
      source = (gint16 *) (buf->data + buffer_info.offset);
      n_samples = buffer_info.size / self->info.bpf;
      n_channels = self->info.channels;

      for (i = 0; i < n_samples; i++) {
        for (c = 0; c < n_channels; c++) {
          dest[i * n_channels + reorder_map[c]] = source[i * n_channels + c];
        }
      }
    } else {
      orc_memcpy (minfo.data, buf->data + buffer_info.offset, buffer_info.size);
    }
    gst_buffer_unmap (outbuf, &minfo);

    if (self->spf != -1) {
      gst_adapter_push (self->output_adapter, outbuf);
    } else {
      flow_ret =
          gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, 1);
    }
  }

  gst_amc_buffer_free (buf);
  buf = NULL;

  if (self->spf != -1) {
    GstBuffer *outbuf;
    guint avail = gst_adapter_available (self->output_adapter);
    guint nframes;

    /* On EOS we take the complete adapter content, no matter
     * if it is a multiple of the codec frame size or not.
     * Otherwise we take a multiple of codec frames and push
     * them downstream
     */
    avail /= self->info.bpf;
    if (!is_eos) {
      nframes = avail / self->spf;
      avail = nframes * self->spf;
    } else {
      nframes = (avail + self->spf - 1) / self->spf;
    }
    avail *= self->info.bpf;

    if (avail > 0) {
      outbuf = gst_adapter_take_buffer (self->output_adapter, avail);
      flow_ret =
          gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf,
          nframes);
    }
  }

  if (!gst_amc_codec_release_output_buffer (self->codec, idx, &err)) {
    if (self->flushing) {
      g_clear_error (&err);
      goto flushing;
    }
    goto failed_release;
  }

  if (is_eos || flow_ret == GST_FLOW_EOS) {
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    if (self->draining) {
      GST_DEBUG_OBJECT (self, "Drained");
      self->draining = FALSE;
      g_cond_broadcast (&self->drain_cond);
    } else if (flow_ret == GST_FLOW_OK) {
      GST_DEBUG_OBJECT (self, "Component signalled EOS");
      flow_ret = GST_FLOW_EOS;
    }
    g_mutex_unlock (&self->drain_lock);
    GST_AUDIO_DECODER_STREAM_LOCK (self);
  } else {
    GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
  }

  self->downstream_flow_ret = flow_ret;

  if (flow_ret != GST_FLOW_OK)
    goto flow_error;

  GST_AUDIO_DECODER_STREAM_UNLOCK (self);

  return;

dequeue_error:
  {
    GST_ELEMENT_ERROR_FROM_ERROR (self, err);
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    self->draining = FALSE;
    g_cond_broadcast (&self->drain_cond);
    g_mutex_unlock (&self->drain_lock);
    return;
  }

format_error:
  {
    if (err)
      GST_ELEMENT_ERROR_FROM_ERROR (self, err);
    else
      GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
          ("Failed to handle format"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    self->draining = FALSE;
    g_cond_broadcast (&self->drain_cond);
    g_mutex_unlock (&self->drain_lock);
    return;
  }
failed_release:
  {
    GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err);
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    self->draining = FALSE;
    g_cond_broadcast (&self->drain_cond);
    g_mutex_unlock (&self->drain_lock);
    return;
  }
flushing:
  {
    GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_FLUSHING;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

flow_error:
  {
    if (flow_ret == GST_FLOW_EOS) {
      GST_DEBUG_OBJECT (self, "EOS");
      gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    } else if (flow_ret < GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (self, STREAM, FAILED,
          ("Internal data stream error."), ("stream stopped, reason %s",
              gst_flow_get_name (flow_ret)));
      gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    } else if (flow_ret == GST_FLOW_FLUSHING) {
      GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    }
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    self->draining = FALSE;
    g_cond_broadcast (&self->drain_cond);
    g_mutex_unlock (&self->drain_lock);
    return;
  }

failed_to_get_output_buffer:
  {
    GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err);
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    self->draining = FALSE;
    g_cond_broadcast (&self->drain_cond);
    g_mutex_unlock (&self->drain_lock);
    return;
  }
invalid_buffer_size:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("Invalid buffer size %u (bfp %d)", buffer_info.size, self->info.bpf));
    gst_amc_codec_release_output_buffer (self->codec, idx, &err);
    if (err && !self->flushing)
      GST_ELEMENT_WARNING_FROM_ERROR (self, err);
    g_clear_error (&err);
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    self->draining = FALSE;
    g_cond_broadcast (&self->drain_cond);
    g_mutex_unlock (&self->drain_lock);
    return;
  }

failed_allocate:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
        ("Failed to allocate output buffer"));
    gst_amc_codec_release_output_buffer (self->codec, idx, &err);
    if (err && !self->flushing)
      GST_ELEMENT_WARNING_FROM_ERROR (self, err);
    g_clear_error (&err);
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    self->draining = FALSE;
    g_cond_broadcast (&self->drain_cond);
    g_mutex_unlock (&self->drain_lock);
    return;
  }
}
コード例 #13
0
static void
gst_asf_parse_loop (GstPad * pad)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstAsfParse *asfparse = GST_ASF_PARSE_CAST (GST_OBJECT_PARENT (pad));

  GST_LOG_OBJECT (asfparse, "Processing data in loop function");
  switch (asfparse->parse_state) {
    case ASF_PARSING_HEADERS:
      GST_INFO_OBJECT (asfparse, "Starting to parse headers");
      ret = gst_asf_parse_pull_headers (asfparse);
      if (ret != GST_FLOW_OK)
        goto pause;
      asfparse->parse_state = ASF_PARSING_DATA;

    case ASF_PARSING_DATA:
      GST_INFO_OBJECT (asfparse, "Parsing data object headers");
      ret = gst_asf_parse_pull_data_header (asfparse);
      if (ret != GST_FLOW_OK)
        goto pause;
      asfparse->parse_state = ASF_PARSING_PACKETS;

    case ASF_PARSING_PACKETS:
      GST_INFO_OBJECT (asfparse, "Starting packet parsing");
      GST_INFO_OBJECT (asfparse, "Broadcast mode %s",
          asfparse->asfinfo->broadcast ? "on" : "off");
      ret = gst_asf_parse_pull_packets (asfparse);
      if (ret != GST_FLOW_OK)
        goto pause;

      /* test if all packets have been processed */
      if (!asfparse->asfinfo->broadcast &&
          asfparse->parsed_packets == asfparse->asfinfo->packets_count) {
        GST_INFO_OBJECT (asfparse,
            "All %" G_GUINT64_FORMAT " packets processed",
            asfparse->parsed_packets);
        asfparse->parse_state = ASF_PARSING_INDEXES;
      }

    case ASF_PARSING_INDEXES:
      /* we currently don't care about indexes, so just push them forward */
      GST_INFO_OBJECT (asfparse, "Starting indexes parsing");
      ret = gst_asf_parse_pull_indexes (asfparse);
      if (ret != GST_FLOW_OK)
        goto pause;
    default:
      break;
  }

pause:
  {
    const gchar *reason = gst_flow_get_name (ret);

    GST_INFO_OBJECT (asfparse, "Pausing sinkpad task");
    gst_pad_pause_task (pad);

    if (ret == GST_FLOW_EOS) {
      gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ());
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (asfparse, STREAM, FAILED,
          (NULL), ("streaming task paused, reason %s (%d)", reason, ret));
      gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ());
    }
  }
}
コード例 #14
0
static void
gst_type_find_element_loop (GstPad * pad)
{
  GstTypeFindElement *typefind;
  GstFlowReturn ret = GST_FLOW_OK;

  typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));

  if (typefind->need_stream_start) {
    gchar *stream_id;
    GstEvent *event;

    stream_id = gst_pad_create_stream_id (typefind->src,
        GST_ELEMENT_CAST (typefind), NULL);

    GST_DEBUG_OBJECT (typefind, "Pushing STREAM_START");
    event = gst_event_new_stream_start (stream_id);
    gst_event_set_group_id (event, gst_util_group_id_next ());
    gst_pad_push_event (typefind->src, event);

    typefind->need_stream_start = FALSE;
    g_free (stream_id);
  }

  if (typefind->mode == MODE_TYPEFIND) {
    GstPad *peer = NULL;
    GstCaps *found_caps = NULL;
    GstTypeFindProbability probability = GST_TYPE_FIND_NONE;

    GST_DEBUG_OBJECT (typefind, "find type in pull mode");

    GST_OBJECT_LOCK (typefind);
    if (typefind->force_caps) {
      found_caps = gst_caps_ref (typefind->force_caps);
      probability = GST_TYPE_FIND_MAXIMUM;
    }
    GST_OBJECT_UNLOCK (typefind);

    if (!found_caps) {
      peer = gst_pad_get_peer (pad);
      if (peer) {
        gint64 size;
        gchar *ext;

        if (!gst_pad_query_duration (peer, GST_FORMAT_BYTES, &size)) {
          GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
          gst_object_unref (peer);

          ret = GST_FLOW_ERROR;
          goto pause;
        }

        /* the size if 0, we cannot continue */
        if (size == 0) {
          /* keep message in sync with message in sink event handler */
          GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
              (_("Stream contains no data.")), ("Can't typefind empty stream"));
          gst_object_unref (peer);
          ret = GST_FLOW_ERROR;
          goto pause;
        }
        ext = gst_type_find_get_extension (typefind, pad);

        found_caps =
            gst_type_find_helper_get_range (GST_OBJECT_CAST (peer),
            GST_OBJECT_PARENT (peer),
            (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
            (guint64) size, ext, &probability);
        g_free (ext);

        GST_DEBUG ("Found caps %" GST_PTR_FORMAT, found_caps);

        gst_object_unref (peer);
      }
    }

    if (!found_caps || probability < typefind->min_probability) {
      GST_DEBUG ("Trying to guess using extension");
      gst_caps_replace (&found_caps, NULL);
      found_caps =
          gst_type_find_guess_by_extension (typefind, pad, &probability);
    }

    if (!found_caps || probability < typefind->min_probability) {
      GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
      gst_caps_replace (&found_caps, NULL);
      ret = GST_FLOW_ERROR;
      goto pause;
    }

    GST_DEBUG ("Emiting found caps %" GST_PTR_FORMAT, found_caps);
    gst_type_find_element_emit_have_type (typefind, probability, found_caps);
    typefind->mode = MODE_NORMAL;
    gst_caps_unref (found_caps);
  } else if (typefind->mode == MODE_NORMAL) {
    GstBuffer *outbuf = NULL;

    if (typefind->need_segment) {
      typefind->need_segment = FALSE;
      gst_pad_push_event (typefind->src,
          gst_event_new_segment (&typefind->segment));
    }

    /* Pull 4k blocks and send downstream */
    ret = gst_pad_pull_range (typefind->sink, typefind->offset, 4096, &outbuf);
    if (ret != GST_FLOW_OK)
      goto pause;

    typefind->offset += gst_buffer_get_size (outbuf);

    ret = gst_pad_push (typefind->src, outbuf);
    if (ret != GST_FLOW_OK)
      goto pause;
  } else {
    /* Error out */
    ret = GST_FLOW_ERROR;
    goto pause;
  }

  return;

pause:
  {
    const gchar *reason = gst_flow_get_name (ret);
    gboolean push_eos = FALSE;

    GST_LOG_OBJECT (typefind, "pausing task, reason %s", reason);
    gst_pad_pause_task (typefind->sink);

    if (ret == GST_FLOW_EOS) {
      /* perform EOS logic */

      if (typefind->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
        gint64 stop;

        /* for segment playback we need to post when (in stream time)
         * we stopped, this is either stop (when set) or the duration. */
        if ((stop = typefind->segment.stop) == -1)
          stop = typefind->offset;

        GST_LOG_OBJECT (typefind, "Sending segment done, at end of segment");
        gst_element_post_message (GST_ELEMENT (typefind),
            gst_message_new_segment_done (GST_OBJECT (typefind),
                GST_FORMAT_BYTES, stop));
        gst_pad_push_event (typefind->src,
            gst_event_new_segment_done (GST_FORMAT_BYTES, stop));
      } else {
        push_eos = TRUE;
      }
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      /* for fatal errors we post an error message */
      GST_ELEMENT_ERROR (typefind, STREAM, FAILED, (NULL),
          ("stream stopped, reason %s", reason));
      push_eos = TRUE;
    }
    if (push_eos) {
      /* send EOS, and prevent hanging if no streams yet */
      GST_LOG_OBJECT (typefind, "Sending EOS, at end of stream");
      gst_pad_push_event (typefind->src, gst_event_new_eos ());
    }
    return;
  }
}
コード例 #15
0
static gboolean
gst_type_find_element_seek (GstTypeFindElement * typefind, GstEvent * event)
{
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  GstFormat format;
  gboolean flush;
  gdouble rate;
  gint64 start, stop;
  GstSegment seeksegment = { 0, };

  gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
      &stop_type, &stop);

  /* we can only seek on bytes */
  if (format != GST_FORMAT_BYTES) {
    GST_DEBUG_OBJECT (typefind, "Can only seek on BYTES");
    return FALSE;
  }

  /* copy segment, we need this because we still need the old
   * segment when we close the current segment. */
  memcpy (&seeksegment, &typefind->segment, sizeof (GstSegment));

  GST_DEBUG_OBJECT (typefind, "configuring seek");
  gst_segment_do_seek (&seeksegment, rate, format, flags,
      start_type, start, stop_type, stop, NULL);

  flush = ! !(flags & GST_SEEK_FLAG_FLUSH);

  GST_DEBUG_OBJECT (typefind, "New segment %" GST_SEGMENT_FORMAT, &seeksegment);

  if (flush) {
    GST_DEBUG_OBJECT (typefind, "Starting flush");
    gst_pad_push_event (typefind->sink, gst_event_new_flush_start ());
    gst_pad_push_event (typefind->src, gst_event_new_flush_start ());
  } else {
    GST_DEBUG_OBJECT (typefind, "Non-flushing seek, pausing task");
    gst_pad_pause_task (typefind->sink);
  }

  /* now grab the stream lock so that streaming cannot continue, for
   * non flushing seeks when the element is in PAUSED this could block
   * forever. */
  GST_DEBUG_OBJECT (typefind, "Waiting for streaming to stop");
  GST_PAD_STREAM_LOCK (typefind->sink);

  if (flush) {
    GST_DEBUG_OBJECT (typefind, "Stopping flush");
    gst_pad_push_event (typefind->sink, gst_event_new_flush_stop (TRUE));
    gst_pad_push_event (typefind->src, gst_event_new_flush_stop (TRUE));
  }

  /* now update the real segment info */
  GST_DEBUG_OBJECT (typefind, "Committing new seek segment");
  memcpy (&typefind->segment, &seeksegment, sizeof (GstSegment));
  typefind->offset = typefind->segment.start;

  /* notify start of new segment */
  if (typefind->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
    GstMessage *msg;

    msg = gst_message_new_segment_start (GST_OBJECT (typefind),
        GST_FORMAT_BYTES, typefind->segment.start);
    gst_element_post_message (GST_ELEMENT (typefind), msg);
  }

  typefind->need_segment = TRUE;

  /* restart our task since it might have been stopped when we did the
   * flush. */
  gst_pad_start_task (typefind->sink,
      (GstTaskFunction) gst_type_find_element_loop, typefind->sink, NULL);

  /* streaming can continue now */
  GST_PAD_STREAM_UNLOCK (typefind->sink);

  return TRUE;
}
コード例 #16
0
ファイル: gsttimidity.c プロジェクト: jonasl/gst-svtplayer
static void
gst_timidity_loop (GstPad * sinkpad)
{
  GstTimidity *timidity = GST_TIMIDITY (GST_PAD_PARENT (sinkpad));
  GstBuffer *out;
  GstFlowReturn ret;

  if (timidity->mididata_size == 0) {
    if (!gst_timidity_get_upstream_size (timidity, &timidity->mididata_size)) {
      GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL),
          ("Unable to get song length"));
      goto paused;
    }

    if (timidity->mididata)
      g_free (timidity->mididata);

    timidity->mididata = g_malloc (timidity->mididata_size);
    timidity->mididata_offset = 0;
    return;
  }

  if (timidity->mididata_offset < timidity->mididata_size) {
    GstBuffer *buffer;
    gint64 size;

    GST_DEBUG_OBJECT (timidity, "loading song");

    ret =
        gst_pad_pull_range (timidity->sinkpad, timidity->mididata_offset,
        -1, &buffer);
    if (ret != GST_FLOW_OK) {
      GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL),
          ("Unable to load song"));
      goto paused;
    }

    size = timidity->mididata_size - timidity->mididata_offset;
    if (GST_BUFFER_SIZE (buffer) < size)
      size = GST_BUFFER_SIZE (buffer);

    memmove (timidity->mididata + timidity->mididata_offset,
        GST_BUFFER_DATA (buffer), size);
    gst_buffer_unref (buffer);

    timidity->mididata_offset += size;
    GST_DEBUG_OBJECT (timidity, "Song loaded");
    return;
  }

  if (!timidity->song) {
    MidIStream *stream;
    GstTagList *tags = NULL;
    gchar *text;

    GST_DEBUG_OBJECT (timidity, "Parsing song");

    stream =
        mid_istream_open_mem (timidity->mididata, timidity->mididata_size, 0);

    timidity->song = mid_song_load (stream, timidity->song_options);
    mid_istream_close (stream);

    if (!timidity->song) {
      GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL),
          ("Unable to parse midi"));
      goto paused;
    }

    mid_song_start (timidity->song);
    timidity->o_len = (GST_MSECOND *
        (GstClockTime) mid_song_get_total_time (timidity->song)) /
        timidity->time_per_frame;
    gst_segment_set_newsegment (timidity->o_segment, FALSE, 1.0,
        GST_FORMAT_DEFAULT, 0, GST_CLOCK_TIME_NONE, 0);


    gst_pad_push_event (timidity->srcpad,
        gst_timidity_get_new_segment_event (timidity, GST_FORMAT_TIME, FALSE));

    /* extract tags */
    text = mid_song_get_meta (timidity->song, MID_SONG_TEXT);
    if (text) {
      tags = gst_tag_list_new ();
      gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, text, NULL);

      //g_free (text);
    }

    text = mid_song_get_meta (timidity->song, MID_SONG_COPYRIGHT);
    if (text) {
      if (tags == NULL)
        tags = gst_tag_list_new ();
      gst_tag_list_add (tags, GST_TAG_MERGE_APPEND,
          GST_TAG_COPYRIGHT, text, NULL);

      //g_free (text);
    }

    if (tags) {
      gst_element_found_tags (GST_ELEMENT (timidity), tags);
    }

    GST_DEBUG_OBJECT (timidity, "Parsing song done");
    return;
  }

  if (timidity->o_segment_changed) {
    GstSegment *segment = gst_timidity_get_segment (timidity, GST_FORMAT_TIME,
        !timidity->o_new_segment);

    GST_LOG_OBJECT (timidity,
        "sending newsegment from %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT
        ", pos=%" GST_TIME_FORMAT, GST_TIME_ARGS ((guint64) segment->start),
        GST_TIME_ARGS ((guint64) segment->stop),
        GST_TIME_ARGS ((guint64) segment->time));

    if (timidity->o_segment->flags & GST_SEEK_FLAG_SEGMENT) {
      gst_element_post_message (GST_ELEMENT (timidity),
          gst_message_new_segment_start (GST_OBJECT (timidity),
              segment->format, segment->start));
    }

    gst_segment_free (segment);
    timidity->o_segment_changed = FALSE;
    return;
  }

  if (timidity->o_seek) {
    /* perform a seek internally */
    timidity->o_segment->last_stop = timidity->o_segment->time;
    mid_song_seek (timidity->song,
        (timidity->o_segment->last_stop * timidity->time_per_frame) /
        GST_MSECOND);
  }

  out = gst_timidity_get_buffer (timidity);
  if (!out) {
    GST_LOG_OBJECT (timidity, "Song ended, generating eos");
    gst_pad_push_event (timidity->srcpad, gst_event_new_eos ());
    timidity->o_seek = FALSE;
    goto paused;
  }

  if (timidity->o_seek) {
    GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT);
    timidity->o_seek = FALSE;
  }

  gst_buffer_set_caps (out, timidity->out_caps);
  ret = gst_pad_push (timidity->srcpad, out);

  if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED)
    goto error;

  return;

paused:
  {
    GST_DEBUG_OBJECT (timidity, "pausing task");
    gst_pad_pause_task (timidity->sinkpad);
    return;
  }
error:
  {
    GST_ELEMENT_ERROR (timidity, STREAM, FAILED,
        ("Internal data stream error"),
        ("Streaming stopped, reason %s", gst_flow_get_name (ret)));
    gst_pad_push_event (timidity->srcpad, gst_event_new_eos ());
    goto paused;
  }
}
コード例 #17
0
ファイル: rademux.c プロジェクト: dalleau/gst-plugins-ugly
static void
gst_real_audio_demux_loop (GstRealAudioDemux * demux)
{
  GstFlowReturn ret;
  GstBuffer *buf;
  guint bytes_needed;

  /* check how much data we need */
  switch (demux->state) {
    case REAL_AUDIO_DEMUX_STATE_MARKER:
      bytes_needed = 6 + 16;    /* 16 are beginning of header */
      break;
    case REAL_AUDIO_DEMUX_STATE_HEADER:
      if (!gst_real_audio_demux_get_data_offset_from_header (demux))
        goto parse_header_error;
      bytes_needed = demux->data_offset - (6 + 16);
      break;
    case REAL_AUDIO_DEMUX_STATE_DATA:
      if (demux->packet_size > 0) {
        /* TODO: should probably take into account width/height as well? */
        bytes_needed = demux->packet_size;
      } else {
        bytes_needed = 1024;
      }
      break;
    default:
      g_return_if_reached ();
  }

  /* now get the data */
  GST_LOG_OBJECT (demux, "getting data: %5u bytes @ %8" G_GINT64_MODIFIER "u",
      bytes_needed, demux->offset);

  if (demux->upstream_size > 0 && demux->offset >= demux->upstream_size)
    goto eos;

  ret = gst_pad_pull_range (demux->sinkpad, demux->offset, bytes_needed, &buf);

  if (ret != GST_FLOW_OK)
    goto pull_range_error;

  if (GST_BUFFER_SIZE (buf) != bytes_needed)
    goto pull_range_short_read;

  ret = gst_real_audio_demux_handle_buffer (demux, buf);
  if (ret != GST_FLOW_OK)
    goto handle_flow_error;

  /* TODO: increase this in chain function too (for timestamps)? */
  demux->offset += bytes_needed;

  /* check for the end of the segment */
  if (demux->segment.stop != -1 && demux->segment.last_stop != -1 &&
      demux->segment.last_stop > demux->segment.stop) {
    GST_DEBUG_OBJECT (demux, "reached end of segment");
    goto eos;
  }

  return;

/* ERRORS */
parse_header_error:
  {
    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), (NULL));
    goto pause_task;
  }
handle_flow_error:
  {
    GST_WARNING_OBJECT (demux, "handle_buf flow: %s", gst_flow_get_name (ret));
    goto pause_task;
  }
pull_range_error:
  {
    GST_WARNING_OBJECT (demux, "pull range flow: %s", gst_flow_get_name (ret));
    goto pause_task;
  }
pull_range_short_read:
  {
    GST_WARNING_OBJECT (demux, "pull range short read: wanted %u bytes, but "
        "got only %u bytes", bytes_needed, GST_BUFFER_SIZE (buf));
    gst_buffer_unref (buf);
    goto eos;
  }
eos:
  {
    if (demux->state != REAL_AUDIO_DEMUX_STATE_DATA) {
      GST_WARNING_OBJECT (demux, "reached EOS before finished parsing header");
      goto parse_header_error;
    }
    GST_INFO_OBJECT (demux, "EOS");
    if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) != 0) {
      gint64 stop;

      /* for segment playback we need to post when (in stream time)
       * we stopped, this is either stop (when set) or the duration. */
      if ((stop = demux->segment.stop) == -1)
        stop = demux->segment.duration;

      GST_DEBUG_OBJECT (demux, "sending segment done, at end of segment");
      gst_element_post_message (GST_ELEMENT (demux),
          gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
              stop));
    } else {
      /* normal playback, send EOS event downstream */
      GST_DEBUG_OBJECT (demux, "sending EOS event, at end of stream");
      gst_pad_push_event (demux->srcpad, gst_event_new_eos ());
    }
    goto pause_task;
  }
pause_task:
  {
    demux->segment_running = FALSE;
    gst_pad_pause_task (demux->sinkpad);
    GST_DEBUG_OBJECT (demux, "pausing task");
    return;
  }
}
コード例 #18
0
ファイル: aiffparse.c プロジェクト: PeterXu/gst-mobile
static void
gst_aiff_parse_loop (GstPad * pad)
{
  GstFlowReturn ret;
  GstAiffParse *aiff = GST_AIFF_PARSE (GST_PAD_PARENT (pad));

  GST_LOG_OBJECT (aiff, "process data");

  switch (aiff->state) {
    case AIFF_PARSE_START:
      GST_INFO_OBJECT (aiff, "AIFF_PARSE_START");
      if ((ret = gst_aiff_parse_stream_init (aiff)) != GST_FLOW_OK)
        goto pause;

      aiff->state = AIFF_PARSE_HEADER;
      /* fall-through */

    case AIFF_PARSE_HEADER:
      GST_INFO_OBJECT (aiff, "AIFF_PARSE_HEADER");
      if ((ret = gst_aiff_parse_stream_headers (aiff)) != GST_FLOW_OK)
        goto pause;

      aiff->state = AIFF_PARSE_DATA;
      GST_INFO_OBJECT (aiff, "AIFF_PARSE_DATA");
      /* fall-through */

    case AIFF_PARSE_DATA:
      if ((ret = gst_aiff_parse_stream_data (aiff)) != GST_FLOW_OK)
        goto pause;
      break;
    default:
      g_assert_not_reached ();
  }
  return;

  /* ERRORS */
pause:
  {
    const gchar *reason = gst_flow_get_name (ret);

    GST_DEBUG_OBJECT (aiff, "pausing task, reason %s", reason);
    aiff->segment_running = FALSE;
    gst_pad_pause_task (pad);

    if (ret == GST_FLOW_UNEXPECTED) {
      /* perform EOS logic */
      if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) {
        GstClockTime stop;

        if ((stop = aiff->segment.stop) == -1)
          stop = aiff->segment.duration;

        gst_element_post_message (GST_ELEMENT_CAST (aiff),
            gst_message_new_segment_done (GST_OBJECT_CAST (aiff),
                aiff->segment.format, stop));
      } else {
        gst_pad_push_event (aiff->srcpad, gst_event_new_eos ());
      }
    } else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED) {
      /* for fatal errors we post an error message, post the error
       * first so the app knows about the error first. */
      GST_ELEMENT_ERROR (aiff, STREAM, FAILED,
          (_("Internal data flow error.")),
          ("streaming task paused, reason %s (%d)", reason, ret));
      gst_pad_push_event (aiff->srcpad, gst_event_new_eos ());
    }
    return;
  }
}
コード例 #19
0
ファイル: rademux.c プロジェクト: dalleau/gst-plugins-ugly
static gboolean
gst_real_audio_demux_handle_seek (GstRealAudioDemux * demux, GstEvent * event)
{
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType cur_type, stop_type;
  gboolean flush, update;
  gdouble rate;
  guint64 seek_pos;
  gint64 cur, stop;

  if (!demux->seekable)
    goto not_seekable;

  if (demux->byterate_num == 0 || demux->byterate_denom == 0)
    goto no_bitrate;

  gst_event_parse_seek (event, &rate, &format, &flags,
      &cur_type, &cur, &stop_type, &stop);

  if (format != GST_FORMAT_TIME)
    goto only_time_format_supported;

  if (rate <= 0.0)
    goto cannot_do_backwards_playback;

  flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);

  GST_DEBUG_OBJECT (demux, "flush=%d, rate=%g", flush, rate);

  /* unlock streaming thread and make streaming stop */
  if (flush) {
    gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
    gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (demux->sinkpad);
  }

  GST_PAD_STREAM_LOCK (demux->sinkpad);

  if (demux->segment_running && !flush) {
    GstEvent *newseg;

    newseg = gst_event_new_new_segment_full (TRUE, demux->segment.rate,
        demux->segment.applied_rate, GST_FORMAT_TIME, demux->segment.start,
        demux->segment.last_stop, demux->segment.time);

    GST_DEBUG_OBJECT (demux, "sending NEWSEGMENT event to close the current "
        "segment: %" GST_PTR_FORMAT, newseg);

    gst_pad_push_event (demux->srcpad, newseg);
  }

  gst_segment_set_seek (&demux->segment, rate, format, flags,
      cur_type, cur, stop_type, stop, &update);

  GST_DEBUG_OBJECT (demux, "segment: %" GST_SEGMENT_FORMAT, &demux->segment);

  seek_pos = gst_util_uint64_scale (demux->segment.start,
      demux->byterate_num, demux->byterate_denom * GST_SECOND);
  if (demux->packet_size > 0) {
    seek_pos -= seek_pos % demux->packet_size;
  }
  seek_pos += demux->data_offset;

  GST_DEBUG_OBJECT (demux, "seek_pos = %" G_GUINT64_FORMAT, seek_pos);

  /* stop flushing */
  gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
  gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ());

  demux->offset = seek_pos;
  demux->need_newsegment = TRUE;

  /* notify start of new segment */
  if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
    gst_element_post_message (GST_ELEMENT (demux),
        gst_message_new_segment_start (GST_OBJECT (demux),
            GST_FORMAT_TIME, demux->segment.last_stop));
  }

  demux->segment_running = TRUE;
  /* restart our task since it might have been stopped when we did the flush */
  gst_pad_start_task (demux->sinkpad,
      (GstTaskFunction) gst_real_audio_demux_loop, demux);

  /* streaming can continue now */
  GST_PAD_STREAM_UNLOCK (demux->sinkpad);

  return TRUE;

/* ERRORS */
not_seekable:
  {
    GST_DEBUG_OBJECT (demux, "seek failed: cannot seek in streaming mode");
    return FALSE;
  }
no_bitrate:
  {
    GST_DEBUG_OBJECT (demux, "seek failed: bitrate unknown");
    return FALSE;
  }
only_time_format_supported:
  {
    GST_DEBUG_OBJECT (demux, "can only seek in TIME format");
    return FALSE;
  }
cannot_do_backwards_playback:
  {
    GST_DEBUG_OBJECT (demux, "can only seek with positive rate, not %lf", rate);
    return FALSE;
  }
}
コード例 #20
0
static gboolean
gst_musepackdec_handle_seek_event (GstMusepackDec * dec, GstEvent * event)
{
  GstSeekType start_type, stop_type;
  GstSeekFlags flags;
  GstSegment segment;
  GstFormat format;
  gboolean flush;
  gdouble rate;
  gint64 start, stop;
  gint samplerate;

  gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
      &stop_type, &stop);

  if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
    GST_DEBUG_OBJECT (dec, "seek failed: only TIME or DEFAULT format allowed");
    return FALSE;
  }

  samplerate = g_atomic_int_get (&dec->rate);

  if (format == GST_FORMAT_TIME) {
    if (start_type != GST_SEEK_TYPE_NONE)
      start = gst_util_uint64_scale_int (start, samplerate, GST_SECOND);
    if (stop_type != GST_SEEK_TYPE_NONE)
      stop = gst_util_uint64_scale_int (stop, samplerate, GST_SECOND);
  }

  flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);

  if (flush)
    gst_pad_push_event (dec->srcpad, gst_event_new_flush_start ());
  else
    gst_pad_pause_task (dec->sinkpad);  /* not _stop_task()? */

  GST_PAD_STREAM_LOCK (dec->sinkpad);

  /* operate on segment copy until we know the seek worked */
  segment = dec->segment;

  gst_segment_do_seek (&segment, rate, GST_FORMAT_DEFAULT,
      flags, start_type, start, stop_type, stop, NULL);

  gst_pad_push_event (dec->sinkpad, gst_event_new_flush_stop (TRUE));

  GST_DEBUG_OBJECT (dec, "segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
      "] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]",
      segment.start, segment.stop,
      GST_TIME_ARGS (segment.start * GST_SECOND / dec->rate),
      GST_TIME_ARGS (segment.stop * GST_SECOND / dec->rate));

  GST_DEBUG_OBJECT (dec, "performing seek to sample %" G_GINT64_FORMAT,
      segment.start);

  if (segment.start >= segment.duration) {
    GST_WARNING_OBJECT (dec, "seek out of bounds");
    goto failed;
  }
  if (mpc_demux_seek_sample (dec->d, segment.start) != MPC_STATUS_OK)
    goto failed;

  if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) {
    GST_DEBUG_OBJECT (dec, "posting SEGMENT_START message");

    gst_element_post_message (GST_ELEMENT (dec),
        gst_message_new_segment_start (GST_OBJECT (dec), GST_FORMAT_TIME,
            gst_util_uint64_scale_int (segment.start, GST_SECOND, dec->rate)));
  }

  if (flush) {
    gst_pad_push_event (dec->srcpad, gst_event_new_flush_stop (TRUE));
  }

  segment.position = segment.start;
  dec->segment = segment;
  gst_musepackdec_send_newsegment (dec);

  GST_DEBUG_OBJECT (dec, "seek successful");

  gst_pad_start_task (dec->sinkpad,
      (GstTaskFunction) gst_musepackdec_loop, dec->sinkpad, NULL);

  GST_PAD_STREAM_UNLOCK (dec->sinkpad);

  return TRUE;

failed:
  {
    GST_WARNING_OBJECT (dec, "seek failed");
    GST_PAD_STREAM_UNLOCK (dec->sinkpad);
    return FALSE;
  }
}
コード例 #21
0
ファイル: gstpngdec.c プロジェクト: JJCG/gst-plugins-good
static void
gst_pngdec_task (GstPad * pad)
{
  GstPngDec *pngdec;
  GstBuffer *buffer = NULL;
  size_t buffer_size = 0;
  gint i = 0;
  png_bytep *rows, inp;
  png_uint_32 rowbytes;
  GstFlowReturn ret = GST_FLOW_OK;

  pngdec = GST_PNGDEC (GST_OBJECT_PARENT (pad));

  GST_LOG_OBJECT (pngdec, "read frame");

  /* Let libpng come back here on error */
  if (setjmp (png_jmpbuf (pngdec->png))) {
    ret = GST_FLOW_ERROR;
    goto pause;
  }

  /* Set reading callback */
  png_set_read_fn (pngdec->png, pngdec, user_read_data);

  /* Read info */
  png_read_info (pngdec->png, pngdec->info);

  /* Generate the caps and configure */
  ret = gst_pngdec_caps_create_and_set (pngdec);
  if (ret != GST_FLOW_OK) {
    goto pause;
  }

  /* Allocate output buffer */
  rowbytes = png_get_rowbytes (pngdec->png, pngdec->info);
  if (rowbytes > (G_MAXUINT32 - 3) || pngdec->height > G_MAXUINT32 / rowbytes) {
    ret = GST_FLOW_ERROR;
    goto pause;
  }
  rowbytes = GST_ROUND_UP_4 (rowbytes);
  buffer_size = pngdec->height * rowbytes;
  ret =
      gst_pad_alloc_buffer_and_set_caps (pngdec->srcpad, GST_BUFFER_OFFSET_NONE,
      buffer_size, GST_PAD_CAPS (pngdec->srcpad), &buffer);
  if (ret != GST_FLOW_OK)
    goto pause;

  rows = (png_bytep *) g_malloc (sizeof (png_bytep) * pngdec->height);

  inp = GST_BUFFER_DATA (buffer);

  for (i = 0; i < pngdec->height; i++) {
    rows[i] = inp;
    inp += rowbytes;
  }

  /* Read the actual picture */
  png_read_image (pngdec->png, rows);
  g_free (rows);

  /* Push the raw RGB frame */
  ret = gst_pad_push (pngdec->srcpad, buffer);
  if (ret != GST_FLOW_OK)
    goto pause;

  /* And we are done */
  gst_pad_pause_task (pngdec->sinkpad);
  gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
  return;

pause:
  {
    GST_INFO_OBJECT (pngdec, "pausing task, reason %s",
        gst_flow_get_name (ret));
    gst_pad_pause_task (pngdec->sinkpad);
    if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
      GST_ELEMENT_ERROR (pngdec, STREAM, FAILED,
          (_("Internal data stream error.")),
          ("stream stopped, reason %s", gst_flow_get_name (ret)));
      gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
    }
  }
}
コード例 #22
0
static gboolean
gst_raw_parse_handle_seek_pull (GstRawParse * rp, GstEvent * event)
{
  gdouble rate;
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  gint64 last_stop;
  gboolean ret = FALSE;
  gboolean flush;
  GstSegment seeksegment;

  if (event) {
    gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
        &stop_type, &stop);

    /* convert input offsets to time */
    ret = gst_raw_parse_convert (rp, format, start, GST_FORMAT_TIME, &start);
    ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_TIME, &stop);
    if (!ret)
      goto convert_failed;

    GST_DEBUG_OBJECT (rp, "converted start - stop to time");

    format = GST_FORMAT_TIME;

    gst_event_unref (event);
  } else {
    format = GST_FORMAT_TIME;
    flags = 0;
  }

  flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);

  /* start flushing up and downstream so that the loop function pauses and we
   * can acquire the STREAM_LOCK. */
  if (flush) {
    GST_LOG_OBJECT (rp, "flushing");
    gst_pad_push_event (rp->sinkpad, gst_event_new_flush_start ());
    gst_pad_push_event (rp->srcpad, gst_event_new_flush_start ());
  } else {
    GST_LOG_OBJECT (rp, "pause task");
    gst_pad_pause_task (rp->sinkpad);
  }

  GST_PAD_STREAM_LOCK (rp->sinkpad);

  memcpy (&seeksegment, &rp->segment, sizeof (GstSegment));

  if (event) {
    /* configure the seek values */
    gst_segment_do_seek (&seeksegment, rate, format, flags,
        start_type, start, stop_type, stop, NULL);
  }

  /* get the desired position */
  last_stop = seeksegment.position;

  GST_LOG_OBJECT (rp, "seeking to %" GST_TIME_FORMAT,
      GST_TIME_ARGS (last_stop));

  /* convert the desired position to bytes */
  ret =
      gst_raw_parse_convert (rp, format, last_stop, GST_FORMAT_BYTES,
      &last_stop);

  /* prepare for streaming */
  if (flush) {
    GST_LOG_OBJECT (rp, "stop flush");
    gst_pad_push_event (rp->sinkpad, gst_event_new_flush_stop (TRUE));
    gst_pad_push_event (rp->srcpad, gst_event_new_flush_stop (TRUE));
  }

  if (ret) {
    /* seek done */

    /* Seek on a frame boundary */
    last_stop -= last_stop % rp->framesize;

    rp->offset = last_stop;
    rp->n_frames = last_stop / rp->framesize;

    GST_LOG_OBJECT (rp, "seeking to bytes %" G_GINT64_FORMAT, last_stop);

    memcpy (&rp->segment, &seeksegment, sizeof (GstSegment));

    if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) {
      gst_element_post_message (GST_ELEMENT_CAST (rp),
          gst_message_new_segment_start (GST_OBJECT_CAST (rp),
              rp->segment.format, rp->segment.position));
    }

    /* for deriving a stop position for the playback segment from the seek
     * segment, we must take the duration when the stop is not set */
    if ((stop = rp->segment.stop) == -1)
      stop = rp->segment.duration;

    GST_DEBUG_OBJECT (rp, "preparing newsegment from %" G_GINT64_FORMAT
        " to %" G_GINT64_FORMAT, rp->segment.start, stop);

    /* now replace the old segment so that we send it in the stream thread the
     * next time it is scheduled. */
    if (rp->start_segment)
      gst_event_unref (rp->start_segment);
    rp->start_segment = gst_event_new_segment (&rp->segment);
  }
  rp->discont = TRUE;

  GST_LOG_OBJECT (rp, "start streaming");
  gst_pad_start_task (rp->sinkpad, (GstTaskFunction) gst_raw_parse_loop, rp,
      NULL);

  GST_PAD_STREAM_UNLOCK (rp->sinkpad);

  return ret;

  /* ERRORS */
convert_failed:
  {
    GST_DEBUG_OBJECT (rp, "Seek failed: couldn't convert to byte positions");
    return FALSE;
  }
}
コード例 #23
0
static void
gst_raw_parse_loop (GstElement * element)
{
  GstRawParse *rp = GST_RAW_PARSE (element);
  GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp);
  GstFlowReturn ret;
  GstBuffer *buffer;
  gint size;

  if (!gst_raw_parse_set_src_caps (rp))
    goto no_caps;

  if (rp->start_segment) {
    GST_DEBUG_OBJECT (rp, "sending start segment");
    gst_pad_push_event (rp->srcpad, rp->start_segment);
    rp->start_segment = NULL;
  }

  if (rp_class->multiple_frames_per_buffer && rp->framesize < 4096)
    size = 4096 - (4096 % rp->framesize);
  else
    size = rp->framesize;

  if (rp->segment.rate >= 0) {
    if (rp->offset + size > rp->upstream_length) {
      GstFormat fmt = GST_FORMAT_BYTES;

      if (!gst_pad_peer_query_duration (rp->sinkpad, fmt, &rp->upstream_length)) {
        GST_WARNING_OBJECT (rp,
            "Could not get upstream duration, trying to pull frame by frame");
        size = rp->framesize;
      } else if (rp->upstream_length < rp->offset + rp->framesize) {
        ret = GST_FLOW_EOS;
        goto pause;
      } else if (rp->offset + size > rp->upstream_length) {
        size = rp->upstream_length - rp->offset;
        size -= size % rp->framesize;
      }
    }
  } else {
    if (rp->offset == 0) {
      ret = GST_FLOW_EOS;
      goto pause;
    } else if (rp->offset < size) {
      size -= rp->offset;
    }
    rp->offset -= size;
  }

  buffer = NULL;
  ret = gst_pad_pull_range (rp->sinkpad, rp->offset, size, &buffer);

  if (ret != GST_FLOW_OK) {
    GST_DEBUG_OBJECT (rp, "pull_range (%" G_GINT64_FORMAT ", %u) "
        "failed, flow: %s", rp->offset, size, gst_flow_get_name (ret));
    buffer = NULL;
    goto pause;
  }

  if (gst_buffer_get_size (buffer) < size) {
    GST_DEBUG_OBJECT (rp, "Short read at offset %" G_GINT64_FORMAT
        ", got only %" G_GSIZE_FORMAT " of %u bytes", rp->offset,
        gst_buffer_get_size (buffer), size);

    if (size > rp->framesize) {
      gst_buffer_set_size (buffer, gst_buffer_get_size (buffer) -
          gst_buffer_get_size (buffer) % rp->framesize);
    } else {
      gst_buffer_unref (buffer);
      buffer = NULL;
      ret = GST_FLOW_EOS;
      goto pause;
    }
  }

  ret = gst_raw_parse_push_buffer (rp, buffer);
  if (ret != GST_FLOW_OK)
    goto pause;

  return;

  /* ERRORS */
no_caps:
  {
    GST_ERROR_OBJECT (rp, "could not negotiate caps");
    ret = GST_FLOW_NOT_NEGOTIATED;
    goto pause;
  }
pause:
  {
    const gchar *reason = gst_flow_get_name (ret);

    GST_LOG_OBJECT (rp, "pausing task, reason %s", reason);
    gst_pad_pause_task (rp->sinkpad);

    if (ret == GST_FLOW_EOS) {
      if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) {
        GstClockTime stop;

        GST_LOG_OBJECT (rp, "Sending segment done");

        if ((stop = rp->segment.stop) == -1)
          stop = rp->segment.duration;

        gst_element_post_message (GST_ELEMENT_CAST (rp),
            gst_message_new_segment_done (GST_OBJECT_CAST (rp),
                rp->segment.format, stop));
        gst_pad_push_event (rp->srcpad,
            gst_event_new_segment_done (rp->segment.format, stop));
      } else {
        GST_LOG_OBJECT (rp, "Sending EOS, at end of stream");
        gst_pad_push_event (rp->srcpad, gst_event_new_eos ());
      }
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (rp, STREAM, FAILED,
          ("Internal data stream error."),
          ("stream stopped, reason %s", reason));
      gst_pad_push_event (rp->srcpad, gst_event_new_eos ());
    }
    return;
  }
}
コード例 #24
0
static void
gst_musepackdec_loop (GstPad * sinkpad)
{
    GstMusepackDec *musepackdec;
    GstFlowReturn flow;
    GstBuffer *out;

#ifdef MPC_IS_OLD_API
    guint32 update_acc, update_bits;
#else
    mpc_frame_info frame;
    mpc_status err;
#endif
    gint num_samples, samplerate, bitspersample;

    musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad));

    samplerate = g_atomic_int_get (&musepackdec->rate);

    if (samplerate == 0) {
        if (!gst_musepack_stream_init (musepackdec))
            goto pause_task;

        gst_musepackdec_send_newsegment (musepackdec);
        samplerate = g_atomic_int_get (&musepackdec->rate);
    }

    bitspersample = g_atomic_int_get (&musepackdec->bps);

    flow = gst_pad_alloc_buffer_and_set_caps (musepackdec->srcpad, -1,
            MPC_DECODER_BUFFER_LENGTH * 4, GST_PAD_CAPS (musepackdec->srcpad), &out);

    if (flow != GST_FLOW_OK) {
        GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow));
        goto pause_task;
    }
#ifdef MPC_IS_OLD_API
    num_samples = mpc_decoder_decode (musepackdec->d,
                                      (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out), &update_acc, &update_bits);

    if (num_samples < 0) {
        GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
        GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL));
        goto pause_task;
    } else if (num_samples == 0) {
        goto eos_and_pause;
    }
#else
    frame.buffer = (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out);
    err = mpc_demux_decode (musepackdec->d, &frame);

    if (err != MPC_STATUS_OK) {
        GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
        GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL));
        goto pause_task;
    } else if (frame.bits == -1) {
        goto eos_and_pause;
    }

    num_samples = frame.samples;
#endif

    GST_BUFFER_SIZE (out) = num_samples * bitspersample;

    GST_BUFFER_OFFSET (out) = musepackdec->segment.last_stop;
    GST_BUFFER_TIMESTAMP (out) =
        gst_util_uint64_scale_int (musepackdec->segment.last_stop,
                                   GST_SECOND, samplerate);
    GST_BUFFER_DURATION (out) =
        gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate);

    musepackdec->segment.last_stop += num_samples;

    GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT,
                    GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));

    flow = gst_pad_push (musepackdec->srcpad, out);
    if (flow != GST_FLOW_OK) {
        GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow));
        goto pause_task;
    }

    /* check if we're at the end of a configured segment */
    if (musepackdec->segment.stop != -1 &&
            musepackdec->segment.last_stop >= musepackdec->segment.stop) {
        gint64 stop_time;

        GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment");

        if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0)
            goto eos_and_pause;

        GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message");

        stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop,
                                               GST_SECOND, samplerate);

        gst_element_post_message (GST_ELEMENT (musepackdec),
                                  gst_message_new_segment_done (GST_OBJECT (musepackdec),
                                          GST_FORMAT_TIME, stop_time));

        goto pause_task;
    }

    return;

eos_and_pause:
    {
        GST_DEBUG_OBJECT (musepackdec, "sending EOS event");
        gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ());
        /* fall through to pause */
    }

pause_task:
    {
        GST_DEBUG_OBJECT (musepackdec, "Pausing task");
        gst_pad_pause_task (sinkpad);
        return;
    }
}
コード例 #25
0
/* push packets from the queue to the downstream demuxer */
static void
gst_rdt_manager_loop (GstPad * pad)
{
  GstRDTManager *rdtmanager;
  GstRDTManagerSession *session;
  GstBuffer *buffer;
  GstFlowReturn result;

  rdtmanager = GST_RDT_MANAGER (GST_PAD_PARENT (pad));

  session = gst_pad_get_element_private (pad);

  JBUF_LOCK_CHECK (session, flushing);
  GST_DEBUG_OBJECT (rdtmanager, "Peeking item");
  while (TRUE) {
    /* always wait if we are blocked */
    if (!session->blocked) {
      /* if we have a packet, we can exit the loop and grab it */
      if (rdt_jitter_buffer_num_packets (session->jbuf) > 0)
        break;
      /* no packets but we are EOS, do eos logic */
      if (session->eos)
        goto do_eos;
    }
    /* underrun, wait for packets or flushing now */
    session->waiting = TRUE;
    JBUF_WAIT_CHECK (session, flushing);
    session->waiting = FALSE;
  }

  buffer = rdt_jitter_buffer_pop (session->jbuf);

  GST_DEBUG_OBJECT (rdtmanager, "Got item %p", buffer);

  if (session->discont) {
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
    session->discont = FALSE;
  }

  JBUF_UNLOCK (session);

  result = gst_pad_push (session->recv_rtp_src, buffer);
  if (result != GST_FLOW_OK)
    goto pause;

  return;

  /* ERRORS */
flushing:
  {
    GST_DEBUG_OBJECT (rdtmanager, "we are flushing");
    gst_pad_pause_task (session->recv_rtp_src);
    JBUF_UNLOCK (session);
    return;
  }
do_eos:
  {
    /* store result, we are flushing now */
    GST_DEBUG_OBJECT (rdtmanager, "We are EOS, pushing EOS downstream");
    session->srcresult = GST_FLOW_EOS;
    gst_pad_pause_task (session->recv_rtp_src);
    gst_pad_push_event (session->recv_rtp_src, gst_event_new_eos ());
    JBUF_UNLOCK (session);
    return;
  }
pause:
  {
    GST_DEBUG_OBJECT (rdtmanager, "pausing task, reason %s",
        gst_flow_get_name (result));

    JBUF_LOCK (session);
    /* store result */
    session->srcresult = result;
    /* we don't post errors or anything because upstream will do that for us
     * when we pass the return value upstream. */
    gst_pad_pause_task (session->recv_rtp_src);
    JBUF_UNLOCK (session);
    return;
  }
}
コード例 #26
0
ファイル: gsttcpmixsrc.c プロジェクト: duzy/gst-switch
static void
gst_tcp_mix_src_loop (GstTCPMixSrcPad * pad)
{
  GstTCPMixSrc *src = GST_TCP_MIX_SRC (GST_PAD_PARENT (pad));
  GstBuffer *buffer = NULL;
  GstFlowReturn ret;

  /*
     INFO ("%p, %s", g_thread_self (), GST_PAD_NAME (pad));
   */

  if (!pad->running) {
    gst_tcp_mix_src_pad_wait_for_client (pad);
    pad->running = TRUE;
  }

  ret = gst_tcp_mix_src_pad_read (pad, &buffer);
  if (ret != GST_FLOW_OK)
    goto error_read_pad;

  ret = gst_pad_push (GST_PAD (pad), buffer);
  if (ret != GST_FLOW_OK)
    goto error_push_buffer;

  return;

  /* Handling Errors */
error_read_pad:
  {
    GST_ERROR_OBJECT (src, "Can't read from %s:%s",
        GST_ELEMENT_NAME (src), GST_PAD_NAME (pad));
    goto pause;
  }

error_push_buffer:
  {
    GST_ERROR_OBJECT (src, "Can't push buffer to %s:%s",
        GST_ELEMENT_NAME (src), GST_PAD_NAME (pad));
    goto pause;
  }

pause:
  {
    if (src->mode == MODE_LOOP)
      goto loop;

    GstEvent *event;

    if (ret == GST_FLOW_EOS) {
      event = gst_event_new_eos ();
      gst_pad_push_event (GST_PAD (pad), event);
    } else if (ret == GST_FLOW_NOT_LINKED || ret <= GST_FLOW_EOS) {
      event = gst_event_new_eos ();

      GST_ELEMENT_ERROR (src, STREAM, FAILED,
          ("Internal data flow error."),
          ("streaming task paused (%s (%d))", gst_flow_get_name (ret), ret));

      gst_pad_push_event (GST_PAD (pad), event);
    }

    /*
       GST_DEBUG_OBJECT (pad, "Paused %s.%s (%s)",
       GST_ELEMENT_NAME (src), GST_PAD_NAME (pad),
       gst_flow_get_name (ret));
     */

    gst_pad_pause_task (GST_PAD (pad));
    return;
  }

loop:
  {
    if (ret == GST_FLOW_NOT_LINKED || ret <= GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (src, STREAM, FAILED,
          ("Internal data flow error."),
          ("streaming task paused (%s (%d))", gst_flow_get_name (ret), ret));
    }
    return;
  }
}
コード例 #27
0
static void
gst_musepackdec_loop (GstPad * sinkpad)
{
  GstMusepackDec *musepackdec;
  GstFlowReturn flow;
  GstBuffer *out;
  GstMapInfo info;
  mpc_frame_info frame;
  mpc_status err;
  gint num_samples, samplerate, bitspersample;

  musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad));

  samplerate = g_atomic_int_get (&musepackdec->rate);

  if (samplerate == 0) {
    if (!gst_musepack_stream_init (musepackdec))
      goto pause_task;

    gst_musepackdec_send_newsegment (musepackdec);
    samplerate = g_atomic_int_get (&musepackdec->rate);
  }

  bitspersample = g_atomic_int_get (&musepackdec->bps);

  out = gst_buffer_new_allocate (NULL, MPC_DECODER_BUFFER_LENGTH * 4, NULL);

  gst_buffer_map (out, &info, GST_MAP_READWRITE);
  frame.buffer = (MPC_SAMPLE_FORMAT *) info.data;
  err = mpc_demux_decode (musepackdec->d, &frame);
  gst_buffer_unmap (out, &info);

  if (err != MPC_STATUS_OK) {
    GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
    GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL));
    goto pause_task;
  } else if (frame.bits == -1) {
    goto eos_and_pause;
  }

  num_samples = frame.samples;

  gst_buffer_set_size (out, num_samples * bitspersample);

  GST_BUFFER_OFFSET (out) = musepackdec->segment.position;
  GST_BUFFER_PTS (out) =
      gst_util_uint64_scale_int (musepackdec->segment.position,
      GST_SECOND, samplerate);
  GST_BUFFER_DURATION (out) =
      gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate);

  musepackdec->segment.position += num_samples;

  GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));

  flow = gst_pad_push (musepackdec->srcpad, out);
  if (flow != GST_FLOW_OK) {
    GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow));
    goto pause_task;
  }

  /* check if we're at the end of a configured segment */
  if (musepackdec->segment.stop != -1 &&
      musepackdec->segment.position >= musepackdec->segment.stop) {
    gint64 stop_time;

    GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment");

    if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0)
      goto eos_and_pause;

    GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message");

    stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop,
        GST_SECOND, samplerate);

    gst_element_post_message (GST_ELEMENT (musepackdec),
        gst_message_new_segment_done (GST_OBJECT (musepackdec),
            GST_FORMAT_TIME, stop_time));
    gst_pad_push_event (musepackdec->srcpad,
        gst_event_new_segment_done (GST_FORMAT_TIME, stop_time));

    goto pause_task;
  }

  return;

eos_and_pause:
  {
    GST_DEBUG_OBJECT (musepackdec, "sending EOS event");
    gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ());
    /* fall through to pause */
  }

pause_task:
  {
    GST_DEBUG_OBJECT (musepackdec, "Pausing task");
    gst_pad_pause_task (sinkpad);
    return;
  }
}
コード例 #28
0
static void
gst_wildmidi_loop (GstPad * sinkpad)
{
  GstWildmidi *wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad));
  GstFlowReturn ret;

  switch (wildmidi->state) {
    case GST_WILDMIDI_STATE_LOAD:
    {
      GstBuffer *buffer = NULL;

      GST_DEBUG_OBJECT (wildmidi, "loading song");

      ret =
          gst_pad_pull_range (wildmidi->sinkpad, wildmidi->offset, -1, &buffer);

      if (ret == GST_FLOW_EOS) {
        GST_DEBUG_OBJECT (wildmidi, "Song loaded");
        wildmidi->state = GST_WILDMIDI_STATE_PARSE;
      } else if (ret != GST_FLOW_OK) {
        GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
            ("Unable to read song"));
        goto pause;
      } else {
        GST_DEBUG_OBJECT (wildmidi, "pushing buffer");
        gst_adapter_push (wildmidi->adapter, buffer);
        wildmidi->offset += gst_buffer_get_size (buffer);
      }
      break;
    }
    case GST_WILDMIDI_STATE_PARSE:
      ret = gst_wildmidi_parse_song (wildmidi);
      if (ret != GST_FLOW_OK)
        goto pause;
      wildmidi->state = GST_WILDMIDI_STATE_PLAY;
      break;
    case GST_WILDMIDI_STATE_PLAY:
      ret = gst_wildmidi_do_play (wildmidi);
      if (ret != GST_FLOW_OK)
        goto pause;
      break;
    default:
      break;
  }
  return;

pause:
  {
    const gchar *reason = gst_flow_get_name (ret);
    GstEvent *event;

    GST_DEBUG_OBJECT (wildmidi, "pausing task, reason %s", reason);
    gst_pad_pause_task (sinkpad);
    if (ret == GST_FLOW_EOS) {
      /* perform EOS logic */
      event = gst_event_new_eos ();
      gst_pad_push_event (wildmidi->srcpad, event);
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      event = gst_event_new_eos ();
      /* for fatal errors we post an error message, post the error
       * first so the app knows about the error first. */
      GST_ELEMENT_ERROR (wildmidi, STREAM, FAILED,
          ("Internal data flow error."),
          ("streaming task paused, reason %s (%d)", reason, ret));
      gst_pad_push_event (wildmidi->srcpad, event);
    }
  }
}
コード例 #29
0
ファイル: aiffparse.c プロジェクト: PeterXu/gst-mobile
/* This function is used to perform seeks on the element in
 * pull mode.
 *
 * It also works when event is NULL, in which case it will just
 * start from the last configured segment. This technique is
 * used when activating the element and to perform the seek in
 * READY.
 */
static gboolean
gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
{
  gboolean res;
  gdouble rate;
  GstFormat format, bformat;
  GstSeekFlags flags;
  GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
  gint64 cur, stop, upstream_size;
  gboolean flush;
  gboolean update;
  GstSegment seeksegment = { 0, };
  gint64 last_stop;

  if (event) {
    GST_DEBUG_OBJECT (aiff, "doing seek with event");

    gst_event_parse_seek (event, &rate, &format, &flags,
        &cur_type, &cur, &stop_type, &stop);

    /* no negative rates yet */
    if (rate < 0.0)
      goto negative_rate;

    if (format != aiff->segment.format) {
      GST_INFO_OBJECT (aiff, "converting seek-event from %s to %s",
          gst_format_get_name (format),
          gst_format_get_name (aiff->segment.format));
      res = TRUE;
      if (cur_type != GST_SEEK_TYPE_NONE)
        res =
            gst_pad_query_convert (aiff->srcpad, format, cur,
            &aiff->segment.format, &cur);
      if (res && stop_type != GST_SEEK_TYPE_NONE)
        res =
            gst_pad_query_convert (aiff->srcpad, format, stop,
            &aiff->segment.format, &stop);
      if (!res)
        goto no_format;

      format = aiff->segment.format;
    }
  } else {
    GST_DEBUG_OBJECT (aiff, "doing seek without event");
    flags = 0;
    rate = 1.0;
    cur_type = GST_SEEK_TYPE_SET;
    stop_type = GST_SEEK_TYPE_SET;
  }

  /* get flush flag */
  flush = flags & GST_SEEK_FLAG_FLUSH;

  /* now we need to make sure the streaming thread is stopped. We do this by
   * either sending a FLUSH_START event downstream which will cause the
   * streaming thread to stop with a WRONG_STATE.
   * For a non-flushing seek we simply pause the task, which will happen as soon
   * as it completes one iteration (and thus might block when the sink is
   * blocking in preroll). */
  if (flush) {
    GST_DEBUG_OBJECT (aiff, "sending flush start");
    gst_pad_push_event (aiff->srcpad, gst_event_new_flush_start ());
  } else {
    gst_pad_pause_task (aiff->sinkpad);
  }

  /* we should now be able to grab the streaming thread because we stopped it
   * with the above flush/pause code */
  GST_PAD_STREAM_LOCK (aiff->sinkpad);

  /* save current position */
  last_stop = aiff->segment.last_stop;

  GST_DEBUG_OBJECT (aiff, "stopped streaming at %" G_GINT64_FORMAT, last_stop);

  /* copy segment, we need this because we still need the old
   * segment when we close the current segment. */
  memcpy (&seeksegment, &aiff->segment, sizeof (GstSegment));

  /* configure the seek parameters in the seeksegment. We will then have the
   * right values in the segment to perform the seek */
  if (event) {
    GST_DEBUG_OBJECT (aiff, "configuring seek");
    gst_segment_set_seek (&seeksegment, rate, format, flags,
        cur_type, cur, stop_type, stop, &update);
  }

  /* figure out the last position we need to play. If it's configured (stop !=
   * -1), use that, else we play until the total duration of the file */
  if ((stop = seeksegment.stop) == -1)
    stop = seeksegment.duration;

  GST_DEBUG_OBJECT (aiff, "cur_type =%d", cur_type);
  if ((cur_type != GST_SEEK_TYPE_NONE)) {
    /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
     * we can just copy the last_stop. If not, we use the bps to convert TIME to
     * bytes. */
    if (aiff->bps > 0)
      aiff->offset =
          uint64_ceiling_scale (seeksegment.last_stop, (guint64) aiff->bps,
          GST_SECOND);
    else
      aiff->offset = seeksegment.last_stop;
    GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
    aiff->offset -= (aiff->offset % aiff->bytes_per_sample);
    GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
    aiff->offset += aiff->datastart;
    GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
  } else {
    GST_LOG_OBJECT (aiff, "continue from offset=%" G_GUINT64_FORMAT,
        aiff->offset);
  }

  if (stop_type != GST_SEEK_TYPE_NONE) {
    if (aiff->bps > 0)
      aiff->end_offset =
          uint64_ceiling_scale (stop, (guint64) aiff->bps, GST_SECOND);
    else
      aiff->end_offset = stop;
    GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
    aiff->end_offset -= (aiff->end_offset % aiff->bytes_per_sample);
    GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
    aiff->end_offset += aiff->datastart;
    GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
  } else {
    GST_LOG_OBJECT (aiff, "continue to end_offset=%" G_GUINT64_FORMAT,
        aiff->end_offset);
  }

  /* make sure filesize is not exceeded due to rounding errors or so,
   * same precaution as in _stream_headers */
  bformat = GST_FORMAT_BYTES;
  if (gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size))
    aiff->end_offset = MIN (aiff->end_offset, upstream_size);

  /* this is the range of bytes we will use for playback */
  aiff->offset = MIN (aiff->offset, aiff->end_offset);
  aiff->dataleft = aiff->end_offset - aiff->offset;

  GST_DEBUG_OBJECT (aiff,
      "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
      ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, aiff->offset,
      aiff->end_offset, GST_TIME_ARGS (seeksegment.start),
      GST_TIME_ARGS (stop));

  /* prepare for streaming again */
  if (flush) {
    /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
    GST_DEBUG_OBJECT (aiff, "sending flush stop");
    gst_pad_push_event (aiff->srcpad, gst_event_new_flush_stop ());
  } else if (aiff->segment_running) {
    /* we are running the current segment and doing a non-flushing seek,
     * close the segment first based on the previous last_stop. */
    GST_DEBUG_OBJECT (aiff, "closing running segment %" G_GINT64_FORMAT
        " to %" G_GINT64_FORMAT, aiff->segment.accum, aiff->segment.last_stop);

    /* queue the segment for sending in the stream thread */
    if (aiff->close_segment)
      gst_event_unref (aiff->close_segment);
    aiff->close_segment = gst_event_new_new_segment (TRUE,
        aiff->segment.rate, aiff->segment.format,
        aiff->segment.accum, aiff->segment.last_stop, aiff->segment.accum);

    /* keep track of our last_stop */
    seeksegment.accum = aiff->segment.last_stop;
  }

  /* now we did the seek and can activate the new segment values */
  memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment));

  /* if we're doing a segment seek, post a SEGMENT_START message */
  if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) {
    gst_element_post_message (GST_ELEMENT_CAST (aiff),
        gst_message_new_segment_start (GST_OBJECT_CAST (aiff),
            aiff->segment.format, aiff->segment.last_stop));
  }

  /* now create the newsegment */
  GST_DEBUG_OBJECT (aiff, "Creating newsegment from %" G_GINT64_FORMAT
      " to %" G_GINT64_FORMAT, aiff->segment.last_stop, stop);

  /* store the newsegment event so it can be sent from the streaming thread. */
  if (aiff->start_segment)
    gst_event_unref (aiff->start_segment);
  aiff->start_segment =
      gst_event_new_new_segment (FALSE, aiff->segment.rate,
      aiff->segment.format, aiff->segment.last_stop, stop,
      aiff->segment.last_stop);

  /* mark discont if we are going to stream from another position. */
  if (last_stop != aiff->segment.last_stop) {
    GST_DEBUG_OBJECT (aiff, "mark DISCONT, we did a seek to another position");
    aiff->discont = TRUE;
  }

  /* and start the streaming task again */
  aiff->segment_running = TRUE;
  if (!aiff->streaming) {
    gst_pad_start_task (aiff->sinkpad, (GstTaskFunction) gst_aiff_parse_loop,
        aiff->sinkpad);
  }

  GST_PAD_STREAM_UNLOCK (aiff->sinkpad);

  return TRUE;

  /* ERRORS */
negative_rate:
  {
    GST_DEBUG_OBJECT (aiff, "negative playback rates are not supported yet.");
    return FALSE;
  }
no_format:
  {
    GST_DEBUG_OBJECT (aiff, "unsupported format given, seek aborted.");
    return FALSE;
  }
}
コード例 #30
0
static void
gst_amc_audio_dec_loop (GstAmcAudioDec * self)
{
  GstFlowReturn flow_ret = GST_FLOW_OK;
  gboolean is_eos;
  GstAmcBufferInfo buffer_info;
  gint idx;

  GST_AUDIO_DECODER_STREAM_LOCK (self);

retry:
  /*if (self->input_caps_changed) {
     idx = INFO_OUTPUT_FORMAT_CHANGED;
     } else { */
  GST_DEBUG_OBJECT (self, "Waiting for available output buffer");
  GST_AUDIO_DECODER_STREAM_UNLOCK (self);
  /* Wait at most 100ms here, some codecs don't fail dequeueing if
   * the codec is flushing, causing deadlocks during shutdown */
  idx = gst_amc_codec_dequeue_output_buffer (self->codec, &buffer_info, 100000);
  GST_AUDIO_DECODER_STREAM_LOCK (self);
  /*} */

  if (idx < 0) {
    if (self->flushing)
      goto flushing;

    switch (idx) {
      case INFO_OUTPUT_BUFFERS_CHANGED:{
        GST_DEBUG_OBJECT (self, "Output buffers have changed");
        if (self->output_buffers)
          gst_amc_codec_free_buffers (self->output_buffers,
              self->n_output_buffers);
        self->output_buffers =
            gst_amc_codec_get_output_buffers (self->codec,
            &self->n_output_buffers);
        if (!self->output_buffers)
          goto get_output_buffers_error;
        break;
      }
      case INFO_OUTPUT_FORMAT_CHANGED:{
        GstAmcFormat *format;
        gchar *format_string;

        GST_DEBUG_OBJECT (self, "Output format has changed");

        format = gst_amc_codec_get_output_format (self->codec);
        if (!format)
          goto format_error;

        format_string = gst_amc_format_to_string (format);
        GST_DEBUG_OBJECT (self, "Got new output format: %s", format_string);
        g_free (format_string);

        if (!gst_amc_audio_dec_set_src_caps (self, format)) {
          gst_amc_format_free (format);
          goto format_error;
        }
        gst_amc_format_free (format);

        if (self->output_buffers)
          gst_amc_codec_free_buffers (self->output_buffers,
              self->n_output_buffers);
        self->output_buffers =
            gst_amc_codec_get_output_buffers (self->codec,
            &self->n_output_buffers);
        if (!self->output_buffers)
          goto get_output_buffers_error;

        goto retry;
        break;
      }
      case INFO_TRY_AGAIN_LATER:
        GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out");
        goto retry;
        break;
      case G_MININT:
        GST_ERROR_OBJECT (self, "Failure dequeueing output buffer");
        goto dequeue_error;
        break;
      default:
        g_assert_not_reached ();
        break;
    }

    goto retry;
  }

  GST_DEBUG_OBJECT (self,
      "Got output buffer at index %d: size %d time %" G_GINT64_FORMAT
      " flags 0x%08x", idx, buffer_info.size, buffer_info.presentation_time_us,
      buffer_info.flags);

  is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM);
  self->n_buffers++;

  if (buffer_info.size > 0) {
    GstAmcAudioDecClass *klass = GST_AMC_AUDIO_DEC_GET_CLASS (self);
    GstBuffer *outbuf;
    GstAmcBuffer *buf;
    GstMapInfo minfo;

    /* This sometimes happens at EOS or if the input is not properly framed,
     * let's handle it gracefully by allocating a new buffer for the current
     * caps and filling it
     */
    if (idx >= self->n_output_buffers)
      goto invalid_buffer_index;

    if (strcmp (klass->codec_info->name, "OMX.google.mp3.decoder") == 0) {
      /* Google's MP3 decoder outputs garbage in the first output buffer
       * so we just drop it here */
      if (self->n_buffers == 1) {
        GST_DEBUG_OBJECT (self,
            "Skipping first buffer of Google MP3 decoder output");
        goto done;
      }
    }

    outbuf =
        gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self),
        buffer_info.size);
    if (!outbuf)
      goto failed_allocate;

    gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE);
    buf = &self->output_buffers[idx];
    if (self->needs_reorder) {
      gint i, n_samples, c, n_channels;
      gint *reorder_map = self->reorder_map;
      gint16 *dest, *source;

      dest = (gint16 *) minfo.data;
      source = (gint16 *) (buf->data + buffer_info.offset);
      n_samples = buffer_info.size / self->info.bpf;
      n_channels = self->info.channels;

      for (i = 0; i < n_samples; i++) {
        for (c = 0; c < n_channels; c++) {
          dest[i * n_channels + reorder_map[c]] = source[i * n_channels + c];
        }
      }
    } else {
      orc_memcpy (minfo.data, buf->data + buffer_info.offset, buffer_info.size);
    }
    gst_buffer_unmap (outbuf, &minfo);

    /* FIXME: We should get one decoded input frame here for
     * every buffer. If this is not the case somewhere, we will
     * error out at some point and will need to add workarounds
     */
    flow_ret =
        gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, 1);
  }

done:
  if (!gst_amc_codec_release_output_buffer (self->codec, idx))
    goto failed_release;

  if (is_eos || flow_ret == GST_FLOW_EOS) {
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    g_mutex_lock (&self->drain_lock);
    if (self->draining) {
      GST_DEBUG_OBJECT (self, "Drained");
      self->draining = FALSE;
      g_cond_broadcast (&self->drain_cond);
    } else if (flow_ret == GST_FLOW_OK) {
      GST_DEBUG_OBJECT (self, "Component signalled EOS");
      flow_ret = GST_FLOW_EOS;
    }
    g_mutex_unlock (&self->drain_lock);
    GST_AUDIO_DECODER_STREAM_LOCK (self);
  } else {
    GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
  }

  self->downstream_flow_ret = flow_ret;

  if (flow_ret != GST_FLOW_OK)
    goto flow_error;

  GST_AUDIO_DECODER_STREAM_UNLOCK (self);

  return;

dequeue_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("Failed to dequeue output buffer"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

get_output_buffers_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("Failed to get output buffers"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

format_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("Failed to handle format"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }
failed_release:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("Failed to release output buffer index %d", idx));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }
flushing:
  {
    GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_FLUSHING;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

flow_error:
  {
    if (flow_ret == GST_FLOW_EOS) {
      GST_DEBUG_OBJECT (self, "EOS");
      gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (self, STREAM, FAILED,
          ("Internal data stream error."), ("stream stopped, reason %s",
              gst_flow_get_name (flow_ret)));
      gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    }
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

invalid_buffer_index:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("Invalid input buffer index %d of %d", idx, self->n_input_buffers));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

failed_allocate:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
        ("Failed to allocate output buffer"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }
}