Esempio n. 1
0
static GstStateChangeReturn
gst_musepackdec_change_state (GstElement * element, GstStateChange transition)
{
    GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (element);
    GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;

    switch (transition) {
    case GST_STATE_CHANGE_READY_TO_PAUSED:
        gst_segment_init (&musepackdec->segment, GST_FORMAT_DEFAULT);
        gst_segment_set_last_stop (&musepackdec->segment, GST_FORMAT_DEFAULT, 0);
        break;
    default:
        break;
    }

    if (GST_ELEMENT_CLASS (parent_class)->change_state)
        ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

    switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
        gst_segment_init (&musepackdec->segment, GST_FORMAT_UNDEFINED);
        musepackdec->offset = 0;
        musepackdec->rate = 0;
        musepackdec->bps = 0;
        break;
    default:
        break;
    }

    return ret;

}
Esempio n. 2
0
static GstFlowReturn
gst_real_audio_demux_parse_data (GstRealAudioDemux * demux)
{
  GstFlowReturn ret = GST_FLOW_OK;
  guint avail, unit_size;

  avail = gst_adapter_available (demux->adapter);

  if (demux->packet_size > 0)
    unit_size = demux->packet_size;
  else
    unit_size = avail & 0xfffffff0;     /* round down to next multiple of 16 */

  GST_LOG_OBJECT (demux, "available = %u, unit_size = %u", avail, unit_size);

  while (ret == GST_FLOW_OK && unit_size > 0 && avail >= unit_size) {
    GstClockTime ts;
    const guint8 *data;
    GstBuffer *buf = NULL;

    buf = gst_buffer_new_and_alloc (unit_size);
    gst_buffer_set_caps (buf, GST_PAD_CAPS (demux->srcpad));

    data = gst_adapter_peek (demux->adapter, unit_size);
    memcpy (GST_BUFFER_DATA (buf), data, unit_size);
    gst_adapter_flush (demux->adapter, unit_size);
    avail -= unit_size;

    if (demux->need_newsegment) {
      gst_pad_push_event (demux->srcpad,
          gst_event_new_new_segment_full (FALSE, demux->segment.rate,
              demux->segment.applied_rate, GST_FORMAT_TIME,
              demux->segment.start, demux->segment.stop, demux->segment.time));
      demux->need_newsegment = FALSE;
    }

    if (demux->pending_tags) {
      gst_element_found_tags_for_pad (GST_ELEMENT (demux), demux->srcpad,
          demux->pending_tags);
      demux->pending_tags = NULL;
    }

    if (demux->fourcc == GST_RM_AUD_DNET) {
      buf = gst_rm_utils_descramble_dnet_buffer (buf);
    }

    ts = gst_real_demux_get_timestamp_from_offset (demux, demux->offset);
    GST_BUFFER_TIMESTAMP (buf) = ts;

    gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME, ts);

    ret = gst_pad_push (demux->srcpad, buf);
  }

  return ret;
}
void QGstreamerPlayerSession::processNewBuffer(GstBuffer *buf)
{
    GstClockTime last_stop, duration;
    last_stop = GST_BUFFER_TIMESTAMP (buf);
    if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
        duration = GST_BUFFER_DURATION (buf);
        if (GST_CLOCK_TIME_IS_VALID (duration)) {
            last_stop += duration;
        }
        gst_segment_set_last_stop(&m_segment, m_segment.format, last_stop);
    }
}
static GstFlowReturn
gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
{
  RsnStreamSelector *sel;
  GstFlowReturn res;
  GstPad *active_sinkpad;
  RsnSelectorPad *selpad;
  GstClockTime timestamp;
  GstSegment *seg;

  sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
  selpad = GST_SELECTOR_PAD_CAST (pad);
  seg = &selpad->segment;

  active_sinkpad = rsn_stream_selector_get_active (sel, pad);

  timestamp = GST_BUFFER_TIMESTAMP (buf);
  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
    GST_DEBUG_OBJECT (sel, "received timestamp %" GST_TIME_FORMAT,
        GST_TIME_ARGS (timestamp));
    gst_segment_set_last_stop (seg, seg->format, timestamp);
  }

  /* Ignore buffers from pads except the selected one */
  if (pad != active_sinkpad)
    goto ignore;

  /* if we have a pending segment, push it out now */
  if (selpad->segment_pending) {
    gst_pad_push_event (sel->srcpad, gst_event_new_new_segment_full (FALSE,
            seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop,
            seg->time));

    selpad->segment_pending = FALSE;
  }

  /* forward */
  GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s:%s", buf,
      GST_DEBUG_PAD_NAME (pad));
  res = gst_pad_push (sel->srcpad, buf);
done:
  gst_object_unref (sel);
  return res;
  /* dropped buffers */
ignore:
  {
    GST_DEBUG_OBJECT (sel, "Ignoring buffer %p from pad %s:%s",
        buf, GST_DEBUG_PAD_NAME (pad));
    gst_buffer_unref (buf);
    res = GST_FLOW_NOT_LINKED;
    goto done;
  }
}
Esempio n. 5
0
GstFlowReturn
gst_vdp_mpeg_dec_push_video_buffer (GstVdpMpegDec * mpeg_dec,
                                    GstVdpVideoBuffer * buffer)
{
    gint64 byterate;

    if (GST_BUFFER_TIMESTAMP (buffer) == GST_CLOCK_TIME_NONE
            && GST_CLOCK_TIME_IS_VALID (mpeg_dec->next_timestamp)) {
        GST_BUFFER_TIMESTAMP (buffer) = mpeg_dec->next_timestamp;
    } else if (GST_BUFFER_TIMESTAMP (buffer) == GST_CLOCK_TIME_NONE) {
        GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (mpeg_dec->frame_nr,
                                        GST_SECOND * mpeg_dec->fps_d, mpeg_dec->fps_n);
    }

    if (mpeg_dec->seeking) {
        GstEvent *event;

        event = gst_event_new_new_segment (FALSE,
                                           mpeg_dec->segment.rate, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer),
                                           mpeg_dec->segment.stop, GST_BUFFER_TIMESTAMP (buffer));

        gst_pad_push_event (mpeg_dec->src, event);

        mpeg_dec->seeking = FALSE;
    }

    mpeg_dec->next_timestamp = GST_BUFFER_TIMESTAMP (buffer) +
                               GST_BUFFER_DURATION (buffer);

    gst_segment_set_last_stop (&mpeg_dec->segment, GST_FORMAT_TIME,
                               GST_BUFFER_TIMESTAMP (buffer));

    mpeg_dec->accumulated_duration += GST_BUFFER_DURATION (buffer);
    mpeg_dec->accumulated_size += GST_BUFFER_SIZE (buffer);
    byterate = gst_util_uint64_scale (mpeg_dec->accumulated_size, GST_SECOND,
                                      mpeg_dec->accumulated_duration);
    GST_DEBUG ("byterate: %" G_GINT64_FORMAT, mpeg_dec->byterate);

    mpeg_dec->byterate = (mpeg_dec->byterate + byterate) / 2;

    gst_buffer_set_caps (GST_BUFFER (buffer), GST_PAD_CAPS (mpeg_dec->src));

    GST_DEBUG_OBJECT (mpeg_dec,
                      "Pushing buffer with timestamp: %" GST_TIME_FORMAT
                      " frame_nr: %" G_GINT64_FORMAT,
                      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
                      GST_BUFFER_OFFSET (buffer));

    return gst_pad_push (mpeg_dec->src, GST_BUFFER (buffer));
}
Esempio n. 6
0
gboolean
gst_kate_util_decoder_base_update_segment (GstKateDecoderBase * decoder,
    GstElement * element, GstBuffer * buf)
{
  gint64 clip_start = 0, clip_stop = 0;
  gboolean in_seg;

  if (decoder->kate_flushing) {
    GST_LOG_OBJECT (element, "Kate pad flushing, buffer ignored");
    return FALSE;
  }

  if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
    GstClockTime stop;

    if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf)))
      stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
    else
      stop = GST_CLOCK_TIME_NONE;

    in_seg = gst_segment_clip (&decoder->kate_segment, GST_FORMAT_TIME,
        GST_BUFFER_TIMESTAMP (buf), stop, &clip_start, &clip_stop);
  } else {
    in_seg = TRUE;
  }

  if (in_seg) {
    if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
      gst_segment_set_last_stop (&decoder->kate_segment, GST_FORMAT_TIME,
          clip_start);
    }
  } else {
    GST_INFO_OBJECT (element, "Kate buffer not in segment, ignored");
  }

  return in_seg;
}
Esempio n. 7
0
static GstFlowReturn
gst_aiff_parse_stream_data (GstAiffParse * aiff)
{
  GstBuffer *buf = NULL;
  GstFlowReturn res = GST_FLOW_OK;
  guint64 desired, obtained;
  GstClockTime timestamp, next_timestamp, duration;
  guint64 pos, nextpos;

iterate_adapter:
  GST_LOG_OBJECT (aiff,
      "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %"
      G_GINT64_FORMAT, aiff->offset, aiff->end_offset, aiff->dataleft);

  /* Get the next n bytes and output them */
  if (aiff->dataleft == 0 || aiff->dataleft < aiff->bytes_per_sample)
    goto found_eos;

  /* scale the amount of data by the segment rate so we get equal
   * amounts of data regardless of the playback rate */
  desired =
      MIN (gst_guint64_to_gdouble (aiff->dataleft),
      MAX_BUFFER_SIZE * aiff->segment.abs_rate);

  if (desired >= aiff->bytes_per_sample && aiff->bytes_per_sample > 0)
    desired -= (desired % aiff->bytes_per_sample);

  GST_LOG_OBJECT (aiff, "Fetching %" G_GINT64_FORMAT " bytes of data "
      "from the sinkpad", desired);

  if (aiff->streaming) {
    guint avail = gst_adapter_available (aiff->adapter);

    if (avail < desired) {
      GST_LOG_OBJECT (aiff, "Got only %d bytes of data from the sinkpad",
          avail);
      return GST_FLOW_OK;
    }

    buf = gst_adapter_take_buffer (aiff->adapter, desired);
  } else {
    if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset,
                desired, &buf)) != GST_FLOW_OK)
      goto pull_error;
  }

  /* If we have a pending close/start segment, send it now. */
  if (G_UNLIKELY (aiff->close_segment != NULL)) {
    gst_pad_push_event (aiff->srcpad, aiff->close_segment);
    aiff->close_segment = NULL;
  }
  if (G_UNLIKELY (aiff->start_segment != NULL)) {
    gst_pad_push_event (aiff->srcpad, aiff->start_segment);
    aiff->start_segment = NULL;
  }

  obtained = GST_BUFFER_SIZE (buf);

  /* our positions in bytes */
  pos = aiff->offset - aiff->datastart;
  nextpos = pos + obtained;

  /* update offsets, does not overflow. */
  GST_BUFFER_OFFSET (buf) = pos / aiff->bytes_per_sample;
  GST_BUFFER_OFFSET_END (buf) = nextpos / aiff->bytes_per_sample;

  if (aiff->bps > 0) {
    /* and timestamps if we have a bitrate, be careful for overflows */
    timestamp = uint64_ceiling_scale (pos, GST_SECOND, (guint64) aiff->bps);
    next_timestamp =
        uint64_ceiling_scale (nextpos, GST_SECOND, (guint64) aiff->bps);
    duration = next_timestamp - timestamp;

    /* update current running segment position */
    gst_segment_set_last_stop (&aiff->segment, GST_FORMAT_TIME, next_timestamp);
  } else {
    /* no bitrate, all we know is that the first sample has timestamp 0, all
     * other positions and durations have unknown timestamp. */
    if (pos == 0)
      timestamp = 0;
    else
      timestamp = GST_CLOCK_TIME_NONE;
    duration = GST_CLOCK_TIME_NONE;
    /* update current running segment position with byte offset */
    gst_segment_set_last_stop (&aiff->segment, GST_FORMAT_BYTES, nextpos);
  }
  if (aiff->discont) {
    GST_DEBUG_OBJECT (aiff, "marking DISCONT");
    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
    aiff->discont = FALSE;
  }

  GST_BUFFER_TIMESTAMP (buf) = timestamp;
  GST_BUFFER_DURATION (buf) = duration;
  gst_buffer_set_caps (buf, aiff->caps);

  GST_LOG_OBJECT (aiff,
      "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT
      ", size:%u", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration),
      GST_BUFFER_SIZE (buf));

  if ((res = gst_pad_push (aiff->srcpad, buf)) != GST_FLOW_OK)
    goto push_error;

  if (obtained < aiff->dataleft) {
    aiff->offset += obtained;
    aiff->dataleft -= obtained;
  } else {
    aiff->offset += aiff->dataleft;
    aiff->dataleft = 0;
  }

  /* Iterate until need more data, so adapter size won't grow */
  if (aiff->streaming) {
    GST_LOG_OBJECT (aiff,
        "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, aiff->offset,
        aiff->end_offset);
    goto iterate_adapter;
  }
  return res;

  /* ERROR */
found_eos:
  {
    GST_DEBUG_OBJECT (aiff, "found EOS");
    return GST_FLOW_UNEXPECTED;
  }
pull_error:
  {
    /* check if we got EOS */
    if (res == GST_FLOW_UNEXPECTED)
      goto found_eos;

    GST_WARNING_OBJECT (aiff,
        "Error getting %" G_GINT64_FORMAT " bytes from the "
        "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, aiff->dataleft);
    return res;
  }
push_error:
  {
    GST_INFO_OBJECT (aiff,
        "Error pushing on srcpad %s:%s, reason %s, is linked? = %d",
        GST_DEBUG_PAD_NAME (aiff->srcpad), gst_flow_get_name (res),
        gst_pad_is_linked (aiff->srcpad));
    return res;
  }
}
Esempio n. 8
0
static GstFlowReturn
gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
{
  GstAudioRate *audiorate;
  GstClockTime in_time, in_duration, in_stop, run_time;
  guint64 in_offset, in_offset_end, in_samples;
  guint in_size;
  GstFlowReturn ret = GST_FLOW_OK;

  audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));

  /* need to be negotiated now */
  if (audiorate->bytes_per_sample == 0)
    goto not_negotiated;

  /* we have a new pending segment */
  if (audiorate->next_offset == -1) {
    gint64 pos;

    /* update the TIME segment */
    gst_audio_rate_convert_segments (audiorate);

    /* first buffer, we are negotiated and we have a segment, calculate the
     * current expected offsets based on the segment.start, which is the first
     * media time of the segment and should match the media time of the first
     * buffer in that segment, which is the offset expressed in DEFAULT units.
     */
    /* convert first timestamp of segment to sample position */
    pos = gst_util_uint64_scale_int (audiorate->src_segment.start,
        audiorate->rate, GST_SECOND);

    GST_DEBUG_OBJECT (audiorate, "resync to offset %" G_GINT64_FORMAT, pos);

    audiorate->next_offset = pos;
    audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset,
        GST_SECOND, audiorate->rate);
  }

  audiorate->in++;

  in_time = GST_BUFFER_TIMESTAMP (buf);
  if (in_time == GST_CLOCK_TIME_NONE) {
    GST_DEBUG_OBJECT (audiorate, "no timestamp, using expected next time");
    in_time = audiorate->next_ts;
  }

  in_size = GST_BUFFER_SIZE (buf);
  in_samples = in_size / audiorate->bytes_per_sample;
  /* get duration from the size because we can and it's more accurate */
  in_duration =
      gst_util_uint64_scale_int (in_samples, GST_SECOND, audiorate->rate);
  in_stop = in_time + in_duration;

  /* Figure out the total accumulated segment time. */
  run_time = in_time + audiorate->src_segment.accum;

  /* calculate the buffer offset */
  in_offset = gst_util_uint64_scale_int (run_time, audiorate->rate, GST_SECOND);
  in_offset_end = in_offset + in_samples;

  GST_LOG_OBJECT (audiorate,
      "in_time:%" GST_TIME_FORMAT ", run_time:%" GST_TIME_FORMAT
      ", in_duration:%" GST_TIME_FORMAT
      ", in_size:%u, in_offset:%lld, in_offset_end:%lld" ", ->next_offset:%lld",
      GST_TIME_ARGS (in_time), GST_TIME_ARGS (run_time),
      GST_TIME_ARGS (in_duration), in_size, in_offset, in_offset_end,
      audiorate->next_offset);

  /* do we need to insert samples */
  if (in_offset > audiorate->next_offset) {
    GstBuffer *fill;
    gint fillsize;
    guint64 fillsamples;

    /* We don't want to allocate a single unreasonably huge buffer - it might
       be hundreds of megabytes. So, limit each output buffer to one second of
       audio */
    fillsamples = in_offset - audiorate->next_offset;

    while (fillsamples > 0) {
      guint64 cursamples = MIN (fillsamples, audiorate->rate);

      fillsamples -= cursamples;
      fillsize = cursamples * audiorate->bytes_per_sample;

      fill = gst_buffer_new_and_alloc (fillsize);
      /* FIXME, 0 might not be the silence byte for the negotiated format. */
      memset (GST_BUFFER_DATA (fill), 0, fillsize);

      GST_DEBUG_OBJECT (audiorate, "inserting %lld samples", cursamples);

      GST_BUFFER_OFFSET (fill) = audiorate->next_offset;
      audiorate->next_offset += cursamples;
      GST_BUFFER_OFFSET_END (fill) = audiorate->next_offset;

      /* Use next timestamp, then calculate following timestamp based on 
       * offset to get duration. Neccesary complexity to get 'perfect' 
       * streams */
      GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts;
      audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset,
          GST_SECOND, audiorate->rate);
      GST_BUFFER_DURATION (fill) = audiorate->next_ts -
          GST_BUFFER_TIMESTAMP (fill);

      /* we created this buffer to fill a gap */
      GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_GAP);
      /* set discont if it's pending, this is mostly done for the first buffer 
       * and after a flushing seek */
      if (audiorate->discont) {
        GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_DISCONT);
        audiorate->discont = FALSE;
      }
      gst_buffer_set_caps (fill, GST_PAD_CAPS (audiorate->srcpad));

      ret = gst_pad_push (audiorate->srcpad, fill);
      if (ret != GST_FLOW_OK)
        goto beach;
      audiorate->out++;
      audiorate->add += cursamples;

      if (!audiorate->silent)
        g_object_notify (G_OBJECT (audiorate), "add");
    }

  } else if (in_offset < audiorate->next_offset) {
    /* need to remove samples */
    if (in_offset_end <= audiorate->next_offset) {
      guint64 drop = in_size / audiorate->bytes_per_sample;

      audiorate->drop += drop;

      GST_DEBUG_OBJECT (audiorate, "dropping %lld samples", drop);

      /* we can drop the buffer completely */
      gst_buffer_unref (buf);

      if (!audiorate->silent)
        g_object_notify (G_OBJECT (audiorate), "drop");

      goto beach;
    } else {
      guint64 truncsamples;
      guint truncsize, leftsize;
      GstBuffer *trunc;

      /* truncate buffer */
      truncsamples = audiorate->next_offset - in_offset;
      truncsize = truncsamples * audiorate->bytes_per_sample;
      leftsize = in_size - truncsize;

      trunc = gst_buffer_create_sub (buf, truncsize, leftsize);

      gst_buffer_unref (buf);
      buf = trunc;

      gst_buffer_set_caps (buf, GST_PAD_CAPS (audiorate->srcpad));

      audiorate->drop += truncsamples;
    }
  }

  /* Now calculate parameters for whichever buffer (either the original
   * or truncated one) we're pushing. */
  GST_BUFFER_OFFSET (buf) = audiorate->next_offset;
  GST_BUFFER_OFFSET_END (buf) = in_offset_end;

  GST_BUFFER_TIMESTAMP (buf) = audiorate->next_ts;
  audiorate->next_ts = gst_util_uint64_scale_int (in_offset_end,
      GST_SECOND, audiorate->rate);
  GST_BUFFER_DURATION (buf) = audiorate->next_ts - GST_BUFFER_TIMESTAMP (buf);

  if (audiorate->discont) {
    /* we need to output a discont buffer, do so now */
    GST_DEBUG_OBJECT (audiorate, "marking DISCONT on output buffer");
    buf = gst_buffer_make_metadata_writable (buf);
    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
    audiorate->discont = FALSE;
  } else if (GST_BUFFER_IS_DISCONT (buf)) {
    /* else we make everything continuous so we can safely remove the DISCONT
     * flag from the buffer if there was one */
    GST_DEBUG_OBJECT (audiorate, "removing DISCONT from buffer");
    buf = gst_buffer_make_metadata_writable (buf);
    GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
  }

  /* set last_stop on segment */
  gst_segment_set_last_stop (&audiorate->src_segment, GST_FORMAT_TIME,
      GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf));

  ret = gst_pad_push (audiorate->srcpad, buf);
  audiorate->out++;

  audiorate->next_offset = in_offset_end;
beach:

  gst_object_unref (audiorate);

  return ret;

  /* ERRORS */
not_negotiated:
  {
    GST_ELEMENT_ERROR (audiorate, STREAM, FORMAT,
        (NULL), ("pipeline error, format was not negotiated"));
    return GST_FLOW_NOT_NEGOTIATED;
  }
}
Esempio n. 9
0
static gboolean
gst_musepack_stream_init (GstMusepackDec * musepackdec)
{
    mpc_streaminfo i;
    GstTagList *tags;
    GstCaps *caps;

    /* set up reading */
    gst_musepack_init_reader (musepackdec->r, musepackdec);

#ifdef MPC_IS_OLD_API
    /* streaminfo */
    mpc_streaminfo_init (&i);
    if (mpc_streaminfo_read (&i, musepackdec->r) < 0) {
        GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL));
        return FALSE;
    }

    /* decoding */
    mpc_decoder_setup (musepackdec->d, musepackdec->r);
    mpc_decoder_scale_output (musepackdec->d, 1.0);
    if (!mpc_decoder_initialize (musepackdec->d, &i)) {
        GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL));
        return FALSE;
    }
#else
    musepackdec->d = mpc_demux_init (musepackdec->r);
    if (!musepackdec->d) {
        GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL));
        return FALSE;
    }

    mpc_demux_get_info (musepackdec->d, &i);
#endif

    /* capsnego */
    caps = gst_caps_from_string (BASE_CAPS);
    gst_caps_set_simple (caps,
                         "endianness", G_TYPE_INT, G_BYTE_ORDER,
                         "channels", G_TYPE_INT, i.channels,
                         "rate", G_TYPE_INT, i.sample_freq, NULL);
    gst_pad_use_fixed_caps (musepackdec->srcpad);
    if (!gst_pad_set_caps (musepackdec->srcpad, caps)) {
        GST_ELEMENT_ERROR (musepackdec, CORE, NEGOTIATION, (NULL), (NULL));
        return FALSE;
    }

    g_atomic_int_set (&musepackdec->bps, 4 * i.channels);
    g_atomic_int_set (&musepackdec->rate, i.sample_freq);

    gst_segment_set_last_stop (&musepackdec->segment, GST_FORMAT_DEFAULT, 0);
    gst_segment_set_duration (&musepackdec->segment, GST_FORMAT_DEFAULT,
                              mpc_streaminfo_get_length_samples (&i));

    /* send basic tags */
    tags = gst_tag_list_new ();
    gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
                      GST_TAG_AUDIO_CODEC, "Musepack", NULL);

    if (i.encoder[0] != '\0' && i.encoder_version > 0) {
        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
                          GST_TAG_ENCODER, i.encoder,
                          GST_TAG_ENCODER_VERSION, i.encoder_version, NULL);
    }

    if (i.bitrate > 0) {
        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
                          GST_TAG_BITRATE, i.bitrate, NULL);
    } else if (i.average_bitrate > 0.0) {
        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
                          GST_TAG_BITRATE, (guint) i.average_bitrate, NULL);
    }

    if (i.gain_title != 0 || i.gain_album != 0) {
        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
                          GST_TAG_TRACK_GAIN, (gdouble) i.gain_title / 100.0,
                          GST_TAG_ALBUM_GAIN, (gdouble) i.gain_album / 100.0, NULL);
    }

    if (i.peak_title != 0 && i.peak_title != 32767 &&
            i.peak_album != 0 && i.peak_album != 32767) {
        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
                          GST_TAG_TRACK_PEAK, (gdouble) i.peak_title / 32767.0,
                          GST_TAG_ALBUM_PEAK, (gdouble) i.peak_album / 32767.0, NULL);
    }

    GST_LOG_OBJECT (musepackdec, "Posting tags: %" GST_PTR_FORMAT, tags);
    gst_element_found_tags (GST_ELEMENT (musepackdec), tags);

    return TRUE;
}
Esempio n. 10
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_set_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 ());

    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 < 0 || segment.start >= segment.duration) {
        GST_WARNING_OBJECT (dec, "seek out of bounds");
        goto failed;
    }
#ifdef MPC_IS_OLD_API
    if (!mpc_decoder_seek_sample (dec->d, segment.start))
        goto failed;
#else
    if (mpc_demux_seek_sample (dec->d, segment.start) != MPC_STATUS_OK)
        goto failed;
#endif

    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 ());
    }

    gst_segment_set_last_stop (&segment, GST_FORMAT_DEFAULT, 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);

    GST_PAD_STREAM_UNLOCK (dec->sinkpad);

    return TRUE;

failed:
    {
        GST_WARNING_OBJECT (dec, "seek failed");
        GST_PAD_STREAM_UNLOCK (dec->sinkpad);
        return FALSE;
    }
}
Esempio n. 11
0
static GstFlowReturn
gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
{
  GstInputSelector *sel;
  GstFlowReturn res;
  GstPad *active_sinkpad;
  GstPad *prev_active_sinkpad;
  GstSelectorPad *selpad;
  GstClockTime start_time;
  GstSegment *seg;
  GstEvent *close_event = NULL, *start_event = NULL;
  GstCaps *caps;

  sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
  selpad = GST_SELECTOR_PAD_CAST (pad);
  seg = &selpad->segment;

  GST_INPUT_SELECTOR_LOCK (sel);
  /* wait or check for flushing */
  if (gst_input_selector_wait (sel, pad))
    goto flushing;

  GST_LOG_OBJECT (pad, "getting active pad");

  prev_active_sinkpad = sel->active_sinkpad;
  active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);

  /* update the segment on the srcpad */
  start_time = GST_BUFFER_TIMESTAMP (buf);
  if (GST_CLOCK_TIME_IS_VALID (start_time)) {
    GST_LOG_OBJECT (pad, "received start time %" GST_TIME_FORMAT,
        GST_TIME_ARGS (start_time));
    if (GST_BUFFER_DURATION_IS_VALID (buf))
      GST_LOG_OBJECT (pad, "received end time %" GST_TIME_FORMAT,
          GST_TIME_ARGS (start_time + GST_BUFFER_DURATION (buf)));

    GST_OBJECT_LOCK (pad);
    gst_segment_set_last_stop (seg, seg->format, start_time);
    GST_OBJECT_UNLOCK (pad);
  }

  /* Ignore buffers from pads except the selected one */
  if (pad != active_sinkpad)
    goto ignore;

  if (G_UNLIKELY (sel->pending_close)) {
    GstSegment *cseg = &sel->segment;

    GST_DEBUG_OBJECT (sel,
        "pushing close NEWSEGMENT update %d, rate %lf, applied rate %lf, "
        "format %d, "
        "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
        G_GINT64_FORMAT, TRUE, cseg->rate, cseg->applied_rate, cseg->format,
        cseg->start, cseg->stop, cseg->time);

    /* create update segment */
    close_event = gst_event_new_new_segment_full (TRUE, cseg->rate,
        cseg->applied_rate, cseg->format, cseg->start, cseg->stop, cseg->time);

    sel->pending_close = FALSE;
  }
  /* if we have a pending segment, push it out now */
  if (G_UNLIKELY (selpad->segment_pending)) {
    GST_DEBUG_OBJECT (pad,
        "pushing pending NEWSEGMENT update %d, rate %lf, applied rate %lf, "
        "format %d, "
        "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
        G_GINT64_FORMAT, FALSE, seg->rate, seg->applied_rate, seg->format,
        seg->start, seg->stop, seg->time);

    start_event = gst_event_new_new_segment_full (FALSE, seg->rate,
        seg->applied_rate, seg->format, seg->start, seg->stop, seg->time);

    selpad->segment_pending = FALSE;
  }
  GST_INPUT_SELECTOR_UNLOCK (sel);

  if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
    g_object_notify (G_OBJECT (sel), "active-pad");

  if (close_event)
    gst_pad_push_event (sel->srcpad, close_event);

  if (start_event)
    gst_pad_push_event (sel->srcpad, start_event);

  if (selpad->discont) {
    buf = gst_buffer_make_metadata_writable (buf);

    GST_DEBUG_OBJECT (pad, "Marking discont buffer %p", buf);
    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
    selpad->discont = FALSE;
  }

  /* forward */
  GST_LOG_OBJECT (pad, "Forwarding buffer %p", buf);

  if ((caps = GST_BUFFER_CAPS (buf))) {
    if (GST_PAD_CAPS (sel->srcpad) != caps)
      gst_pad_set_caps (sel->srcpad, caps);
  }

  res = gst_pad_push (sel->srcpad, buf);

done:
  gst_object_unref (sel);
  return res;

  /* dropped buffers */
ignore:
  {
    GST_DEBUG_OBJECT (pad, "Pad not active, discard buffer %p", buf);
    /* when we drop a buffer, we're creating a discont on this pad */
    selpad->discont = TRUE;
    GST_INPUT_SELECTOR_UNLOCK (sel);
    gst_buffer_unref (buf);

    /* figure out what to return upstream */
    GST_OBJECT_LOCK (selpad);
    if (selpad->always_ok)
      res = GST_FLOW_OK;
    else
      res = GST_FLOW_NOT_LINKED;
    GST_OBJECT_UNLOCK (selpad);

    goto done;
  }
flushing:
  {
    GST_DEBUG_OBJECT (pad, "We are flushing, discard buffer %p", buf);
    GST_INPUT_SELECTOR_UNLOCK (sel);
    gst_buffer_unref (buf);
    res = GST_FLOW_WRONG_STATE;
    goto done;
  }
}
Esempio n. 12
0
static GstFlowReturn
fs_funnel_chain (GstPad * pad, GstBuffer * buffer)
{
  GstFlowReturn res;
  FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad));
  FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
  GstEvent *event = NULL;
  GstClockTime newts;
  GstCaps *padcaps;

  GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer);

  GST_OBJECT_LOCK (funnel);
  if (priv->segment.format == GST_FORMAT_UNDEFINED) {
    GST_WARNING_OBJECT (funnel, "Got buffer without segment,"
        " setting segment [0,inf[");
     gst_segment_set_newsegment_full (&priv->segment, FALSE, 1.0, 1.0,
         GST_FORMAT_TIME, 0, -1, 0);
  }

  if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)))
    gst_segment_set_last_stop (&priv->segment, priv->segment.format,
        GST_BUFFER_TIMESTAMP (buffer));

  newts = gst_segment_to_running_time (&priv->segment,
      priv->segment.format, GST_BUFFER_TIMESTAMP (buffer));
  if (newts != GST_BUFFER_TIMESTAMP (buffer)) {
    buffer = gst_buffer_make_metadata_writable (buffer);
    GST_BUFFER_TIMESTAMP (buffer) = newts;
  }

  if (!funnel->has_segment)
  {
    event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME,
        0, -1, 0);
    funnel->has_segment = TRUE;
  }
  GST_OBJECT_UNLOCK (funnel);

  if (event) {
    if (!gst_pad_push_event (funnel->srcpad, event))
      GST_WARNING_OBJECT (funnel, "Could not push out newsegment event");
  }


  GST_OBJECT_LOCK (pad);
  padcaps = GST_PAD_CAPS (funnel->srcpad);
  GST_OBJECT_UNLOCK (pad);

  if (GST_BUFFER_CAPS (buffer) && GST_BUFFER_CAPS (buffer) != padcaps) {
    if (!gst_pad_set_caps (funnel->srcpad, GST_BUFFER_CAPS (buffer))) {
      res = GST_FLOW_NOT_NEGOTIATED;
      goto out;
    }
  }

  res = gst_pad_push (funnel->srcpad, buffer);

  GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res));

 out:
  gst_object_unref (funnel);

  return res;
}
Esempio n. 13
0
static GstFlowReturn
handle_buffer (GstSubParse * self, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstCaps *caps = NULL;
  gchar *line, *subtitle;

  feed_textbuf (self, buf);

  /* make sure we know the format */
  if (G_UNLIKELY (self->parser_type == GST_SUB_PARSE_FORMAT_UNKNOWN)) {
    if (!(caps = gst_sub_parse_format_autodetect (self))) {
      return GST_FLOW_UNEXPECTED;
    }
    if (!gst_pad_set_caps (self->srcpad, caps)) {
      gst_caps_unref (caps);
      return GST_FLOW_UNEXPECTED;
    }
    gst_caps_unref (caps);
  }

  while ((line = get_next_line (self)) && !self->flushing) {
    /* Set segment on our parser state machine */
    self->state.segment = &self->segment;
    /* Now parse the line, out of segment lines will just return NULL */
    GST_LOG_OBJECT (self, "Parsing line '%s'", line);
    subtitle = self->parse_line (&self->state, line);
    g_free (line);

    if (subtitle) {
      guint subtitle_len = strlen (subtitle);

      /* +1 for terminating NUL character */
      ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
          GST_BUFFER_OFFSET_NONE, subtitle_len + 1,
          GST_PAD_CAPS (self->srcpad), &buf);

      if (ret == GST_FLOW_OK) {
        /* copy terminating NUL character as well */
        memcpy (GST_BUFFER_DATA (buf), subtitle, subtitle_len + 1);
        GST_BUFFER_SIZE (buf) = subtitle_len;
        GST_BUFFER_TIMESTAMP (buf) = self->state.start_time;
        GST_BUFFER_DURATION (buf) = self->state.duration;

        /* in some cases (e.g. tmplayer) we can only determine the duration
         * of a text chunk from the timestamp of the next text chunk; in those
         * cases, we probably want to limit the duration to something
         * reasonable, so we don't end up showing some text for e.g. 40 seconds
         * just because nothing else is being said during that time */
        if (self->state.max_duration > 0 && GST_BUFFER_DURATION_IS_VALID (buf)) {
          if (GST_BUFFER_DURATION (buf) > self->state.max_duration)
            GST_BUFFER_DURATION (buf) = self->state.max_duration;
        }

        gst_segment_set_last_stop (&self->segment, GST_FORMAT_TIME,
            self->state.start_time);

        GST_DEBUG_OBJECT (self, "Sending text '%s', %" GST_TIME_FORMAT " + %"
            GST_TIME_FORMAT, subtitle, GST_TIME_ARGS (self->state.start_time),
            GST_TIME_ARGS (self->state.duration));

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

      /* move this forward (the tmplayer parser needs this) */
      if (self->state.duration != GST_CLOCK_TIME_NONE)
        self->state.start_time += self->state.duration;

      g_free (subtitle);
      subtitle = NULL;

      if (ret != GST_FLOW_OK) {
        GST_DEBUG_OBJECT (self, "flow: %s", gst_flow_get_name (ret));
        break;
      }
    }
  }

  return ret;
}
Esempio n. 14
0
/* For each buffer we receive we check if our collected condition is reached
 * and if so we call the collected function. When this is done we check if
 * data has been unqueued. If data is still queued we wait holding the stream
 * lock to make sure no EOS event can happen while we are ready to be
 * collected 
 */
static GstFlowReturn
gst_collect_pads_chain (GstPad * pad, GstBuffer * buffer)
{
  GstCollectData *data;
  GstCollectPads *pads;
  GstCollectPadsPrivate *priv;
  GstFlowReturn ret;

  GST_DEBUG ("Got buffer for pad %s:%s", GST_DEBUG_PAD_NAME (pad));

  /* some magic to get the managing collect_pads */
  GST_OBJECT_LOCK (pad);
  data = (GstCollectData *) gst_pad_get_element_private (pad);
  if (G_UNLIKELY (data == NULL))
    goto no_data;
  ref_data (data);
  GST_OBJECT_UNLOCK (pad);

  pads = data->collect;
  priv = pads->abidata.ABI.priv;

  GST_OBJECT_LOCK (pads);
  /* if not started, bail out */
  if (G_UNLIKELY (!pads->started))
    goto not_started;
  /* check if this pad is flushing */
  if (G_UNLIKELY (data->abidata.ABI.flushing))
    goto flushing;
  /* pad was EOS, we can refuse this data */
  if (G_UNLIKELY (data->abidata.ABI.eos))
    goto unexpected;

  /* see if we need to clip */
  if (priv->clipfunc) {
    buffer = priv->clipfunc (pads, data, buffer, priv->clipfunc_user_data);

    if (G_UNLIKELY (buffer == NULL))
      goto clipped;
  }

  GST_DEBUG ("Queuing buffer %p for pad %s:%s", buffer,
      GST_DEBUG_PAD_NAME (pad));

  /* One more pad has data queued */
  pads->queuedpads++;
  /* take ownership of the buffer */
  if (data->buffer)
    gst_buffer_unref (data->buffer);
  data->buffer = buffer;
  buffer = NULL;

  /* update segment last position if in TIME */
  if (G_LIKELY (data->segment.format == GST_FORMAT_TIME)) {
    GstClockTime timestamp = GST_BUFFER_TIMESTAMP (data->buffer);

    if (GST_CLOCK_TIME_IS_VALID (timestamp))
      gst_segment_set_last_stop (&data->segment, GST_FORMAT_TIME, timestamp);
  }

  /* While we have data queued on this pad try to collect stuff */
  do {
    GST_DEBUG ("Pad %s:%s checking", GST_DEBUG_PAD_NAME (pad));
    /* Check if our collected condition is matched and call the collected function
     * if it is */
    ret = gst_collect_pads_check_collected (pads);
    /* when an error occurs, we want to report this back to the caller ASAP
     * without having to block if the buffer was not popped */
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      goto error;

    /* data was consumed, we can exit and accept new data */
    if (data->buffer == NULL)
      break;

    /* Check if we got removed in the mean time, FIXME, this is racy.
     * Between this check and the _WAIT, the pad could be removed which will
     * makes us hang in the _WAIT. */
    GST_OBJECT_LOCK (pad);
    if (G_UNLIKELY (gst_pad_get_element_private (pad) == NULL))
      goto pad_removed;
    GST_OBJECT_UNLOCK (pad);

    GST_DEBUG ("Pad %s:%s has a buffer queued, waiting",
        GST_DEBUG_PAD_NAME (pad));

    /* wait to be collected, this must happen from another thread triggered
     * by the _chain function of another pad. We release the lock so we
     * can get stopped or flushed as well. We can however not get EOS
     * because we still hold the STREAM_LOCK. 
     */
    GST_COLLECT_PADS_WAIT (pads);

    GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad));

    /* after a signal, we could be stopped */
    if (G_UNLIKELY (!pads->started))
      goto not_started;
    /* check if this pad is flushing */
    if (G_UNLIKELY (data->abidata.ABI.flushing))
      goto flushing;
  }
  while (data->buffer != NULL);

unlock_done:
  GST_DEBUG ("Pad %s:%s done", GST_DEBUG_PAD_NAME (pad));
  GST_OBJECT_UNLOCK (pads);
  unref_data (data);
  if (buffer)
    gst_buffer_unref (buffer);
  return ret;

pad_removed:
  {
    GST_WARNING ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
    GST_OBJECT_UNLOCK (pad);
    ret = GST_FLOW_NOT_LINKED;
    goto unlock_done;
  }
  /* ERRORS */
no_data:
  {
    GST_DEBUG ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
    GST_OBJECT_UNLOCK (pad);
    gst_buffer_unref (buffer);
    return GST_FLOW_NOT_LINKED;
  }
not_started:
  {
    GST_DEBUG ("not started");
    gst_collect_pads_clear (pads, data);
    ret = GST_FLOW_WRONG_STATE;
    goto unlock_done;
  }
flushing:
  {
    GST_DEBUG ("pad %s:%s is flushing", GST_DEBUG_PAD_NAME (pad));
    gst_collect_pads_clear (pads, data);
    ret = GST_FLOW_WRONG_STATE;
    goto unlock_done;
  }
unexpected:
  {
    /* we should not post an error for this, just inform upstream that
     * we don't expect anything anymore */
    GST_DEBUG ("pad %s:%s is eos", GST_DEBUG_PAD_NAME (pad));
    ret = GST_FLOW_UNEXPECTED;
    goto unlock_done;
  }
clipped:
  {
    GST_DEBUG ("clipped buffer on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
    ret = GST_FLOW_OK;
    goto unlock_done;
  }
error:
  {
    /* we print the error, the element should post a reasonable error
     * message for fatal errors */
    GST_DEBUG ("collect failed, reason %d (%s)", ret, gst_flow_get_name (ret));
    gst_collect_pads_clear (pads, data);
    goto unlock_done;
  }
}