Exemplo n.º 1
0
static gboolean
vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
{
  gboolean ret = FALSE;
  GstVorbisDec *dec;

  dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));

  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_EOS:
      if (dec->segment.rate < 0.0)
        vorbis_dec_chain_reverse (dec, TRUE, NULL);
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
    case GST_EVENT_FLUSH_START:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
    case GST_EVENT_FLUSH_STOP:
      /* here we must clean any state in the decoder */
#ifdef HAVE_VORBIS_SYNTHESIS_RESTART
      vorbis_synthesis_restart (&dec->vd);
#endif
      gst_vorbis_dec_reset (dec);
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
    case GST_EVENT_NEWSEGMENT:
    {
      GstFormat format;
      gdouble rate, arate;
      gint64 start, stop, time;
      gboolean update;

      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
          &start, &stop, &time);

      /* we need time for now */
      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

      GST_DEBUG_OBJECT (dec,
          "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
          ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
          update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
          GST_TIME_ARGS (time));

      /* now configure the values */
      gst_segment_set_newsegment_full (&dec->segment, update,
          rate, arate, format, start, stop, time);
      dec->seqnum = gst_event_get_seqnum (event);

      if (dec->initialized)
        /* and forward */
        ret = gst_pad_push_event (dec->srcpad, event);
      else {
        /* store it to send once we're initialized */
        dec->pendingevents = g_list_append (dec->pendingevents, event);
        ret = TRUE;
      }
      break;
    }
    case GST_EVENT_TAG:
    {
      if (dec->initialized)
        /* and forward */
        ret = gst_pad_push_event (dec->srcpad, event);
      else {
        /* store it to send once we're initialized */
        dec->pendingevents = g_list_append (dec->pendingevents, event);
        ret = TRUE;
      }
      break;
    }
    default:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
  }
done:
  gst_object_unref (dec);

  return ret;

  /* ERRORS */
newseg_wrong_format:
  {
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
    goto done;
  }
}
Exemplo n.º 2
0
static gboolean
dxr3videosink_handle_event (GstPad * pad, GstEvent * event)
{
  GstEventType type;
  Dxr3VideoSink *sink;

  sink = DXR3VIDEOSINK (gst_pad_get_parent (pad));

  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;

  switch (type) {
    case GST_EVENT_EMPTY:
      //fprintf (stderr, "++++++ Video empty event\n");
    {
      /* FIXME: Handle this with a discontinuity or something. */
      /* Write an MPEG2 sequence end code, to ensure that the card
         actually displays the last picture.  Apparently some DVDs are
         encoded without proper sequence end codes. */
      static const guint8 sec[4] = { 0x00, 0x00, 0x01, 0xb7 };

      if (sink->cur_buf != NULL) {
        dxr3videosink_write_data (sink, 0);
      }

      write (sink->video_fd, &sec, 4);
    }
      break;

    case GST_EVENT_DISCONTINUOUS:
      //fprintf (stderr, "++++++ Video discont event\n");
    {
      gint64 time;
      gboolean has_time;
      unsigned cur_scr, mpeg_scr, diff;

      has_time = gst_event_discont_get_value (event, GST_FORMAT_TIME, &time);
      if (has_time) {
/*         fprintf (stderr, "^^^^^^ Discontinuous event has time %.4f\n", */
/*                  (double) time / GST_SECOND); */

        /* If the SCR in the card is way off, fix it. */
        ioctl (sink->control_fd, EM8300_IOCTL_SCR_GET, &cur_scr);
        mpeg_scr = MPEGTIME_TO_DXRTIME (GSTTIME_TO_MPEGTIME (time));

        diff = cur_scr > mpeg_scr ? cur_scr - mpeg_scr : mpeg_scr - cur_scr;
        if (diff > 1800) {
          unsigned zero = 0;

/*           fprintf (stderr, "====== Adjusting SCR from video\n"); */

          ioctl (sink->control_fd, EM8300_IOCTL_SCR_SET, &zero);
          ioctl (sink->control_fd, EM8300_IOCTL_SCR_SET, &mpeg_scr);
        }
      } else {
/*         fprintf (stderr, "^^^^^^ Discontinuous event has no time\n"); */
      }
    }
      break;

    case GST_EVENT_FLUSH:
      dxr3videosink_reset_parser (sink);
      break;

    default:
      gst_pad_event_default (pad, event);
      break;
  }

  return TRUE;
}
static GstPadProbeReturn
handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
{
  GstSplitMuxSink *splitmux = ctx->splitmux;
  GstBuffer *buf;
  MqStreamBuf *buf_info = NULL;
  GstClockTime ts;
  gboolean loop_again;
  gboolean keyframe = FALSE;

  GST_LOG_OBJECT (pad, "Fired probe type 0x%x\n", info->type);

  /* FIXME: Handle buffer lists, until then make it clear they won't work */
  if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
    g_warning ("Buffer list handling not implemented");
    return GST_PAD_PROBE_DROP;
  }
  if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
    GstEvent *event = gst_pad_probe_info_get_event (info);
    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_SEGMENT:
        gst_event_copy_segment (event, &ctx->in_segment);
        break;
      case GST_EVENT_FLUSH_STOP:
        GST_SPLITMUX_LOCK (splitmux);
        gst_segment_init (&ctx->in_segment, GST_FORMAT_UNDEFINED);
        ctx->in_eos = FALSE;
        ctx->in_bytes = 0;
        ctx->in_running_time = 0;
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_EOS:
        GST_SPLITMUX_LOCK (splitmux);
        ctx->in_eos = TRUE;

        if (splitmux->state == SPLITMUX_STATE_STOPPED)
          goto beach;

        if (ctx->is_video) {
          GST_INFO_OBJECT (splitmux, "Got Video EOS. Finishing up");
          /* Act as if this is a new keyframe with infinite timestamp */
          splitmux->max_in_running_time = GST_CLOCK_TIME_NONE;
          splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE;
          /* Wake up other input pads to collect this GOP */
          GST_SPLITMUX_BROADCAST (splitmux);
          check_completed_gop (splitmux, ctx);
        } else if (splitmux->state == SPLITMUX_STATE_WAITING_GOP_COMPLETE) {
          /* If we are waiting for a GOP to be completed (ie, for aux
           * pads to catch up), then this pad is complete, so check
           * if the whole GOP is.
           */
          check_completed_gop (splitmux, ctx);
        }
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      default:
        break;
    }
    return GST_PAD_PROBE_PASS;
  }

  buf = gst_pad_probe_info_get_buffer (info);
  ctx->in_running_time = gst_segment_to_running_time (&ctx->in_segment,
      GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));
  buf_info = mq_stream_buf_new ();

  if (GST_BUFFER_PTS_IS_VALID (buf))
    ts = GST_BUFFER_PTS (buf);
  else
    ts = GST_BUFFER_DTS (buf);

  GST_SPLITMUX_LOCK (splitmux);

  if (splitmux->state == SPLITMUX_STATE_STOPPED)
    goto beach;

  /* If this buffer has a timestamp, advance the input timestamp of the
   * stream */
  if (GST_CLOCK_TIME_IS_VALID (ts)) {
    GstClockTime running_time =
        gst_segment_to_running_time (&ctx->in_segment, GST_FORMAT_TIME,
        GST_BUFFER_TIMESTAMP (buf));

    if (GST_CLOCK_TIME_IS_VALID (running_time) &&
        (ctx->in_running_time == GST_CLOCK_TIME_NONE
            || running_time > ctx->in_running_time))
      ctx->in_running_time = running_time;
  }

  /* Try to make sure we have a valid running time */
  if (!GST_CLOCK_TIME_IS_VALID (ctx->in_running_time)) {
    ctx->in_running_time =
        gst_segment_to_running_time (&ctx->in_segment, GST_FORMAT_TIME,
        ctx->in_segment.start);
  }

  buf_info->run_ts = ctx->in_running_time;
  buf_info->buf_size = gst_buffer_get_size (buf);

  /* Update total input byte counter for overflow detect */
  ctx->in_bytes += buf_info->buf_size;

  GST_DEBUG_OBJECT (pad, "Buf TS %" GST_TIME_FORMAT
      " total in_bytes %" G_GSIZE_FORMAT,
      GST_TIME_ARGS (buf_info->run_ts), ctx->in_bytes);

  loop_again = TRUE;
  do {
    if (ctx->flushing)
      break;

    switch (splitmux->state) {
      case SPLITMUX_STATE_COLLECTING_GOP_START:
        if (ctx->is_video) {
          /* If a keyframe, we have a complete GOP */
          if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ||
              !GST_CLOCK_TIME_IS_VALID (ctx->in_running_time) ||
              splitmux->max_in_running_time >= ctx->in_running_time) {
            /* Pass this buffer through */
            loop_again = FALSE;
            break;
          }
          GST_INFO_OBJECT (pad,
              "Have keyframe with running time %" GST_TIME_FORMAT,
              GST_TIME_ARGS (ctx->in_running_time));
          keyframe = TRUE;
          splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE;
          splitmux->max_in_running_time = ctx->in_running_time;
          /* Wake up other input pads to collect this GOP */
          GST_SPLITMUX_BROADCAST (splitmux);
          check_completed_gop (splitmux, ctx);
        } else {
          /* We're still waiting for a keyframe on the video pad, sleep */
          GST_LOG_OBJECT (pad, "Sleeping for GOP start");
          GST_SPLITMUX_WAIT (splitmux);
          GST_LOG_OBJECT (pad, "Done sleeping for GOP start state now %d",
              splitmux->state);
        }
        break;
      case SPLITMUX_STATE_WAITING_GOP_COMPLETE:
        /* After a GOP start is found, this buffer might complete the GOP */
        /* If we overran the target timestamp, it might be time to process
         * the GOP, otherwise bail out for more data
         */
        GST_LOG_OBJECT (pad,
            "Checking TS %" GST_TIME_FORMAT " against max %" GST_TIME_FORMAT,
            GST_TIME_ARGS (ctx->in_running_time),
            GST_TIME_ARGS (splitmux->max_in_running_time));

        if (ctx->in_running_time < splitmux->max_in_running_time) {
          loop_again = FALSE;
          break;
        }

        GST_LOG_OBJECT (pad,
            "Collected last packet of GOP. Checking other pads");
        check_completed_gop (splitmux, ctx);
        break;
      case SPLITMUX_STATE_ENDING_FILE:
      case SPLITMUX_STATE_START_NEXT_FRAGMENT:
        /* A fragment is ending, wait until that's done before continuing */
        GST_DEBUG_OBJECT (pad, "Sleeping for fragment restart");
        GST_SPLITMUX_WAIT (splitmux);
        GST_DEBUG_OBJECT (pad,
            "Done sleeping for fragment restart state now %d", splitmux->state);
        break;
      default:
        loop_again = FALSE;
        break;
    }
  } while (loop_again);

  if (keyframe) {
    splitmux->queued_gops++;
    buf_info->keyframe = TRUE;
  }

  /* Now add this buffer to the queue just before returning */
  g_queue_push_head (&ctx->queued_bufs, buf_info);

  /* Check the buffer will fit in the mq */
  check_queue_length (splitmux, ctx);

  GST_LOG_OBJECT (pad, "Returning to queue buffer %" GST_PTR_FORMAT
      " run ts %" GST_TIME_FORMAT, buf, GST_TIME_ARGS (ctx->in_running_time));

  GST_SPLITMUX_UNLOCK (splitmux);
  return GST_PAD_PROBE_PASS;

beach:
  GST_SPLITMUX_UNLOCK (splitmux);
  if (buf_info)
    mq_stream_buf_free (buf_info);
  return GST_PAD_PROBE_PASS;
}
Exemplo n.º 4
0
static gboolean
pad_event (GstPad *pad,
           GstEvent *event)
{
    GstOmxBaseFilter *self;
    GOmxCore *gomx;
    GOmxPort *in_port;
    gboolean ret = TRUE;

    self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
    gomx = self->gomx;
    in_port = self->in_port;

    GST_LOG_OBJECT (self, "begin");

    GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));

    switch (GST_EVENT_TYPE (event))
    {
        case GST_EVENT_EOS:
            /* if we are init'ed, and there is a running loop; then
             * if we get a buffer to inform it of EOS, let it handle the rest
             * in any other case, we send EOS */
            if (self->ready && self->last_pad_push_return == GST_FLOW_OK)
            {
                /* send buffer with eos flag */
                /** @todo move to util */
                {
                    OMX_BUFFERHEADERTYPE *omx_buffer;

                    GST_LOG_OBJECT (self, "request buffer");
                    omx_buffer = g_omx_port_request_buffer (in_port);

                    if (G_LIKELY (omx_buffer))
                    {
                        omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;

                        GST_LOG_OBJECT (self, "release_buffer");
                        /* foo_buffer_untaint (omx_buffer); */
                        g_omx_port_release_buffer (in_port, omx_buffer);
                        /* loop handles EOS, eat it here */
                        gst_event_unref (event);
                        break;
                    }
                }
            }

            /* we tried, but it's up to us here */
            ret = gst_pad_push_event (self->srcpad, event);
            break;

        case GST_EVENT_FLUSH_START:
            gst_pad_push_event (self->srcpad, event);
            self->last_pad_push_return = GST_FLOW_WRONG_STATE;

            g_omx_core_flush_start (gomx);

            gst_pad_pause_task (self->srcpad);

            ret = TRUE;
            break;

        case GST_EVENT_FLUSH_STOP:
            gst_pad_push_event (self->srcpad, event);
            self->last_pad_push_return = GST_FLOW_OK;

            g_omx_core_flush_stop (gomx);

            if (self->ready)
                gst_pad_start_task (self->srcpad, output_loop, self->srcpad);

            ret = TRUE;
            break;

        case GST_EVENT_NEWSEGMENT:
            ret = gst_pad_push_event (self->srcpad, event);
            break;

        default:
            ret = gst_pad_push_event (self->srcpad, event);
            break;
    }

    GST_LOG_OBJECT (self, "end");

    return ret;
}
Exemplo n.º 5
0
static gboolean
celt_dec_sink_event (GstPad * pad, GstEvent * event)
{
  GstCeltDec *dec;
  gboolean ret = FALSE;

  dec = GST_CELT_DEC (gst_pad_get_parent (pad));

  GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NEWSEGMENT:{
      GstFormat format;
      gdouble rate, arate;
      gint64 start, stop, time;
      gboolean update;

      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
          &start, &stop, &time);

      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

      if (rate <= 0.0)
        goto newseg_wrong_rate;

      if (update) {
        /* time progressed without data, see if we can fill the gap with
         * some concealment data */
        if (dec->segment.last_stop < start) {
          GstClockTime duration;

          duration = start - dec->segment.last_stop;
          celt_dec_chain_parse_data (dec, NULL, dec->segment.last_stop,
              duration);
        }
      }

      /* now configure the values */
      gst_segment_set_newsegment_full (&dec->segment, update,
          rate, arate, GST_FORMAT_TIME, start, stop, time);

      dec->granulepos = -1;

      GST_DEBUG_OBJECT (dec, "segment now: cur = %" GST_TIME_FORMAT " [%"
          GST_TIME_FORMAT " - %" GST_TIME_FORMAT "]",
          GST_TIME_ARGS (dec->segment.last_stop),
          GST_TIME_ARGS (dec->segment.start),
          GST_TIME_ARGS (dec->segment.stop));

      ret = gst_pad_push_event (dec->srcpad, event);
      break;
    }
    default:
      ret = gst_pad_event_default (pad, event);
      break;
  }

  gst_object_unref (dec);
  return ret;

  /* ERRORS */
newseg_wrong_format:
  {
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
    gst_object_unref (dec);
    return FALSE;
  }
newseg_wrong_rate:
  {
    GST_DEBUG_OBJECT (dec, "negative rates not supported yet");
    gst_object_unref (dec);
    return FALSE;
  }
}
Exemplo n.º 6
0
static gboolean
rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
{
  gboolean ret = FALSE;
  RsnAudioMunge *munge = RSN_AUDIOMUNGE (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:
      rsn_audiomunge_reset (munge);
      ret = gst_pad_push_event (munge->srcpad, event);
      break;
    case GST_EVENT_NEWSEGMENT:
    {
      GstSegment *segment;
      gboolean update;
      GstFormat format;
      gdouble rate, arate;
      gint64 start, stop, time;

      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
          &start, &stop, &time);

      /* we need TIME format */
      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

      /* now configure the values */
      segment = &munge->sink_segment;

      gst_segment_set_newsegment_full (segment, update,
          rate, arate, format, start, stop, time);

      if (munge->have_audio) {
        ret = gst_pad_push_event (munge->srcpad, event);
        break;
      }

      /*
       * FIXME:
       * If the accum >= threshold or we're in a still frame and there's been
       * no audio received, then we need to generate some audio data.
       * If caused by a segment start update (time advancing in a gap) adjust
       * the new-segment and send the buffer.
       *
       * Otherwise, send the buffer before the newsegment, so that it appears
       * in the closing segment.
       */
      if (!update) {
        GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT
            " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT,
            GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
            GST_TIME_ARGS (segment->accum));

        ret = gst_pad_push_event (munge->srcpad, event);
      }

      if (segment->accum >= AUDIO_FILL_THRESHOLD || munge->in_still) {
        g_print ("***********  Sending audio fill: accum = %" GST_TIME_FORMAT
            " still-state=%d\n", GST_TIME_ARGS (segment->accum),
            munge->in_still);

        /* Just generate a 100ms silence buffer for now. FIXME: Fill the gap */
        if (rsn_audiomunge_make_audio (munge, segment->start,
                GST_SECOND / 10) == GST_FLOW_OK)
          munge->have_audio = TRUE;
      } else {
        GST_LOG_OBJECT (munge, "Not sending audio fill buffer: "
            "segment accum below thresh: accum = %" GST_TIME_FORMAT,
            GST_TIME_ARGS (segment->accum));
      }

      if (update) {
        GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT
            " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT,
            GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
            GST_TIME_ARGS (segment->accum));

        ret = gst_pad_push_event (munge->srcpad, event);
      }

      break;
    }
    case GST_EVENT_CUSTOM_DOWNSTREAM:
    {
      const GstStructure *s = gst_event_get_structure (event);

      if (s && gst_structure_has_name (s, "application/x-gst-dvd"))
        rsn_audiomunge_handle_dvd_event (munge, event);

      ret = gst_pad_push_event (munge->srcpad, event);
      break;
    }
    default:
      ret = gst_pad_push_event (munge->srcpad, event);
      break;
  }

  return ret;

newseg_wrong_format:

  GST_DEBUG_OBJECT (munge, "received non TIME newsegment");
  gst_event_unref (event);
  gst_object_unref (munge);
  return FALSE;
}
Exemplo n.º 7
0
static gboolean
gst_base_video_codec_src_event (GstPad * pad, GstEvent * event)
{
  GstBaseVideoCodec *base_video_codec;
  gboolean res = FALSE;

  base_video_codec = GST_BASE_VIDEO_CODEC (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      GstFormat format, tformat;
      gdouble rate;
      GstEvent *real_seek;
      GstSeekFlags flags;
      GstSeekType cur_type, stop_type;
      gint64 cur, stop;
      gint64 tcur, tstop;

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

      tformat = GST_FORMAT_TIME;
      res = gst_base_video_encoded_video_convert (&base_video_codec->state,
          format, cur, &tformat, &tcur);
      if (!res)
        goto convert_error;
      res = gst_base_video_encoded_video_convert (&base_video_codec->state,
          format, stop, &tformat, &tstop);
      if (!res)
        goto convert_error;

      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);

      res = gst_pad_push_event (base_video_codec->sinkpad, real_seek);

      break;
    }
#if 0
    case GST_EVENT_QOS:
    {
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;

      gst_event_parse_qos (event, &proportion, &diff, &timestamp);

      GST_OBJECT_LOCK (base_video_codec);
      base_video_codec->proportion = proportion;
      base_video_codec->earliest_time = timestamp + diff;
      GST_OBJECT_UNLOCK (base_video_codec);

      GST_DEBUG_OBJECT (base_video_codec,
          "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
          GST_TIME_ARGS (timestamp), diff);

      res = gst_pad_push_event (base_video_codec->sinkpad, event);
      break;
    }
#endif
    default:
      res = gst_pad_push_event (base_video_codec->sinkpad, event);
      break;
  }
done:
  gst_object_unref (base_video_codec);
  return res;

convert_error:
  GST_DEBUG_OBJECT (base_video_codec, "could not convert format");
  goto done;
}
Exemplo n.º 8
0
static gboolean
gst_interlace_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  gboolean ret;
  GstInterlace *interlace;

  interlace = GST_INTERLACE (parent);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
      GST_DEBUG_OBJECT (interlace, "handling FLUSH_START");
      ret = gst_pad_push_event (interlace->srcpad, event);
      break;
    case GST_EVENT_FLUSH_STOP:
      GST_DEBUG_OBJECT (interlace, "handling FLUSH_STOP");
      gst_interlace_reset (interlace);
      ret = gst_pad_push_event (interlace->srcpad, event);
      break;
    case GST_EVENT_EOS:
#if 0
      /* FIXME revive this when we output ONEFIELD and RFF buffers */
    {
      gint num_fields;
      const PulldownFormat *format = &formats[interlace->pattern];

      num_fields =
          format->n_fields[interlace->phase_index] -
          interlace->stored_fields_pushed;
      interlace->stored_fields_pushed = 0;

      /* on EOS we want to push as many sane frames as are left */
      while (num_fields > 1) {
        GstBuffer *output_buffer;

        /* make metadata writable before editing it */
        interlace->stored_frame =
            gst_buffer_make_metadata_writable (interlace->stored_frame);
        num_fields -= 2;

        gst_interlace_decorate_buffer (interlace, interlace->stored_frame,
            n_fields, FALSE);

        /* ref output_buffer/stored frame because we want to keep it for now
         * and pushing gives away a ref */
        output_buffer = gst_buffer_ref (interlace->stored_frame);
        if (gst_pad_push (interlace->srcpad, output_buffer)) {
          GST_DEBUG_OBJECT (interlace, "Failed to push buffer %p",
              output_buffer);
          return FALSE;
        }
        output_buffer = NULL;

        if (num_fields <= 1) {
          gst_buffer_unref (interlace->stored_frame);
          interlace->stored_frame = NULL;
          break;
        }
      }

      /* increment the phase index */
      interlace->phase_index++;
      if (!format->n_fields[interlace->phase_index]) {
        interlace->phase_index = 0;
      }
    }
#endif

      ret = gst_pad_push_event (interlace->srcpad, event);
      break;
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      ret = gst_interlace_setcaps (interlace, caps);
      gst_event_unref (event);
      break;
    }
    default:
      ret = gst_pad_push_event (interlace->srcpad, event);
      break;
  }

  return ret;
}
Exemplo n.º 9
0
/* GstAggregator vmethods default implementations */
static gboolean
_sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event)
{
  gboolean res = TRUE;
  GstPad *pad = GST_PAD (aggpad);
  GstAggregatorPrivate *priv = self->priv;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
    {
      _flush_start (self, aggpad, event);
      /* We forward only in one case: right after flush_seeking */
      event = NULL;
      goto eat;
    }
    case GST_EVENT_FLUSH_STOP:
    {
      GST_DEBUG_OBJECT (aggpad, "Got FLUSH_STOP");

      _aggpad_flush (aggpad, self);
      if (g_atomic_int_get (&priv->flush_seeking)) {
        g_atomic_int_set (&aggpad->priv->pending_flush_stop, FALSE);

        if (g_atomic_int_get (&priv->flush_seeking)) {
          if (_all_flush_stop_received (self)) {
            /* That means we received FLUSH_STOP/FLUSH_STOP on
             * all sinkpads -- Seeking is Done... sending FLUSH_STOP */
            _flush (self);
            gst_pad_push_event (self->srcpad, event);
            priv->send_eos = TRUE;
            event = NULL;
            QUEUE_PUSH (self);

            GST_INFO_OBJECT (self, "Releasing source pad STREAM_LOCK");
            GST_PAD_STREAM_UNLOCK (self->srcpad);
            _start_srcpad_task (self);
          }
        }
      }

      /* We never forward the event */
      goto eat;
    }
    case GST_EVENT_EOS:
    {
      GST_DEBUG_OBJECT (aggpad, "EOS");

      /* We still have a buffer, and we don't want the subclass to have to
       * check for it. Mark pending_eos, eos will be set when steal_buffer is
       * called
       */
      PAD_LOCK_EVENT (aggpad);
      if (!aggpad->buffer) {
        aggpad->eos = TRUE;
      } else {
        aggpad->priv->pending_eos = TRUE;
      }
      PAD_UNLOCK_EVENT (aggpad);

      QUEUE_PUSH (self);
      goto eat;
    }
    case GST_EVENT_SEGMENT:
    {
      PAD_LOCK_EVENT (aggpad);
      gst_event_copy_segment (event, &aggpad->segment);
      self->priv->seqnum = gst_event_get_seqnum (event);
      PAD_UNLOCK_EVENT (aggpad);
      goto eat;
    }
    case GST_EVENT_STREAM_START:
    {
      goto eat;
    }
    case GST_EVENT_TAG:
    {
      GstTagList *tags;

      gst_event_parse_tag (event, &tags);

      if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) {
        gst_aggregator_merge_tags (self, tags, GST_TAG_MERGE_REPLACE);
        gst_event_unref (event);
        event = NULL;
        goto eat;
      }
      break;
    }
    default:
    {
      break;
    }
  }

  GST_DEBUG_OBJECT (pad, "Forwarding event: %" GST_PTR_FORMAT, event);
  return gst_pad_event_default (pad, GST_OBJECT (self), event);

eat:
  GST_DEBUG_OBJECT (pad, "Eating event: %" GST_PTR_FORMAT, event);
  if (event)
    gst_event_unref (event);

  return res;
}
Exemplo n.º 10
0
static gboolean
gst_merger_event_srcv (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstMerger *merger = GST_MERGER (parent);
  gboolean ret;

  GST_DEBUG_OBJECT (pad, "got source event %s", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {

    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);

      GST_DEBUG_OBJECT (pad, "event caps are %" GST_PTR_FORMAT, caps);

      break;
    }

    case GST_EVENT_EOS:
      process_eos (merger);
      gst_event_unref (event);
      ret = TRUE;
      break;
    case GST_EVENT_SEGMENT:
      gst_event_copy_segment (event, &merger->s_segment);
      GST_DEBUG_OBJECT (merger, "segment: %" GST_SEGMENT_FORMAT,
          &merger->s_segment);
      break;
    case GST_EVENT_QOS:
    {
      GstQOSType type;
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;
      gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);

      if (type == GST_QOS_TYPE_UNDERFLOW) {
        GST_INFO_OBJECT (pad,
            "got QOS event UNDERFLOW proportion %f diff %" PRIu64 " ts %"
            PRIu64, proportion, diff, timestamp);
        GST_OBJECT_LOCK (merger);

        gint num, den;
        {
          GstCaps *caps = gst_pad_get_current_caps (merger->srcv_pad);
          GstStructure *s = gst_caps_get_structure (caps, 0);
          gst_structure_get_fraction (s, "framerate", &num, &den);
          gst_caps_unref (caps);
        }

        int nb_bufs = 0.5 + diff / (1e9 * den / num);
        GST_WARNING_OBJECT (merger, "Discarding %d buffers", nb_bufs);
        g_queue_pop_head (&merger->bufs_l);
        g_queue_pop_head (&merger->bufs_r);
        GST_OBJECT_UNLOCK (merger);
      } else {
        GST_WARNING_OBJECT (pad, "QOS type %d not implemented", type);
        ret = gst_pad_event_default (pad, parent, event);
      }
    }
      break;

    default:
      GST_INFO_OBJECT (pad, "got source event %s", GST_EVENT_TYPE_NAME (event));
      ret = gst_pad_event_default (pad, parent, event);
      break;
  }
  return ret;
}
Exemplo n.º 11
0
static gboolean
gst_gme_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstGmeDec *gme = GST_GME_DEC (parent);
  gboolean result = FALSE;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      gdouble rate;
      GstFormat format;
      GstSeekFlags flags;
      GstSeekType start_type, stop_type;
      gint64 start, stop;
      gboolean flush;

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

      gst_event_unref (event);

      if (format != GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (gme, "seeking is only supported in TIME format");
        break;
      }

      if (start_type != GST_SEEK_TYPE_SET || stop_type != GST_SEEK_TYPE_NONE) {
        GST_DEBUG_OBJECT (gme, "unsupported seek type");
        break;
      }

      if (stop_type == GST_SEEK_TYPE_NONE)
        stop = GST_CLOCK_TIME_NONE;

      if (start_type == GST_SEEK_TYPE_SET) {
        GstSegment seg;
        guint64 cur = gme_tell (gme->player) * GST_MSECOND;
        guint64 dest = (guint64) start;

        if (gme->total_duration != GST_CLOCK_TIME_NONE)
          dest = CLAMP (dest, 0, gme->total_duration);
        else
          dest = MAX (0, dest);

        if (dest == cur)
          break;

        flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;

        if (flush) {
          gst_pad_push_event (gme->srcpad, gst_event_new_flush_start ());
        } else {
          gst_pad_stop_task (gme->srcpad);
        }

        GST_PAD_STREAM_LOCK (gme->srcpad);

        if (flags & GST_SEEK_FLAG_SEGMENT) {
          gst_element_post_message (GST_ELEMENT (gme),
              gst_message_new_segment_start (GST_OBJECT (gme), format, cur));
        }

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

        if (stop == GST_CLOCK_TIME_NONE
            && gme->total_duration != GST_CLOCK_TIME_NONE)
          stop = gme->total_duration;

        gst_segment_init (&seg, GST_FORMAT_TIME);
        seg.rate = rate;
        seg.start = dest;
        seg.stop = stop;
        seg.time = dest;
        gst_pad_push_event (gme->srcpad, gst_event_new_segment (&seg));

        gme->seekpoint = dest / GST_MSECOND;    /* nsecs to msecs */
        gme->seeking = TRUE;

        gst_pad_start_task (gme->srcpad, (GstTaskFunction) gst_gme_play,
            gme->srcpad, NULL);

        GST_PAD_STREAM_UNLOCK (gme->srcpad);
        result = TRUE;
      }
      break;
    }
    default:
      result = gst_pad_push_event (gme->sinkpad, event);
      break;
  }

  return result;
}
Exemplo n.º 12
0
static gboolean
gst_two_lame_sink_event (GstPad * pad, GstEvent * event)
{
  gboolean ret;
  GstTwoLame *twolame;

  twolame = GST_TWO_LAME (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_EOS:{
      GST_DEBUG_OBJECT (twolame, "handling EOS event");

      if (twolame->glopts != NULL) {
        GstBuffer *buf;
        gint size;

        buf = gst_buffer_new_and_alloc (16384);
        size =
            twolame_encode_flush (twolame->glopts, GST_BUFFER_DATA (buf),
            16394);

        if (size > 0 && twolame->last_flow == GST_FLOW_OK) {
          gint64 duration;

          duration = gst_util_uint64_scale (size, 8 * GST_SECOND,
              1000 * twolame->bitrate);

          if (twolame->last_ts == GST_CLOCK_TIME_NONE) {
            twolame->last_ts = twolame->eos_ts;
            twolame->last_duration = duration;
          } else {
            twolame->last_duration += duration;
          }

          GST_BUFFER_TIMESTAMP (buf) = twolame->last_ts;
          GST_BUFFER_DURATION (buf) = twolame->last_duration;
          twolame->last_ts = GST_CLOCK_TIME_NONE;
          GST_BUFFER_SIZE (buf) = size;
          GST_DEBUG_OBJECT (twolame, "pushing final packet of %u bytes", size);
          gst_buffer_set_caps (buf, GST_PAD_CAPS (twolame->srcpad));
          gst_pad_push (twolame->srcpad, buf);
        } else {
          GST_DEBUG_OBJECT (twolame, "no final packet (size=%d, last_flow=%s)",
              size, gst_flow_get_name (twolame->last_flow));
          gst_buffer_unref (buf);
        }
      }

      ret = gst_pad_event_default (pad, event);
      break;
    }
    case GST_EVENT_FLUSH_START:
      GST_DEBUG_OBJECT (twolame, "handling FLUSH start event");
      /* forward event */
      ret = gst_pad_push_event (twolame->srcpad, event);
      break;
    case GST_EVENT_FLUSH_STOP:
    {
      guchar *mp3_data = NULL;
      gint mp3_buffer_size, mp3_size = 0;

      GST_DEBUG_OBJECT (twolame, "handling FLUSH stop event");

      /* clear buffers */
      mp3_buffer_size = 16384;
      mp3_data = g_malloc (mp3_buffer_size);
      mp3_size =
          twolame_encode_flush (twolame->glopts, mp3_data, mp3_buffer_size);

      ret = gst_pad_push_event (twolame->srcpad, event);

      g_free (mp3_data);
      break;
    }
    default:
      ret = gst_pad_event_default (pad, event);
      break;
  }
  gst_object_unref (twolame);

  return ret;
}
Exemplo n.º 13
0
static gboolean
gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event)
{
  GstIdentity *identity;
  gboolean ret = TRUE;

  identity = GST_IDENTITY (trans);

  if (!identity->silent) {
    const GstStructure *s;
    const gchar *tstr;
    gchar *sstr;

    GST_OBJECT_LOCK (identity);
    g_free (identity->last_message);

    tstr = gst_event_type_get_name (GST_EVENT_TYPE (event));
    if ((s = gst_event_get_structure (event)))
      sstr = gst_structure_to_string (s);
    else
      sstr = g_strdup ("");

    identity->last_message =
        g_strdup_printf ("event   ******* (%s:%s) E (type: %s (%d), %s) %p",
        GST_DEBUG_PAD_NAME (trans->sinkpad), tstr, GST_EVENT_TYPE (event),
        sstr, event);
    g_free (sstr);
    GST_OBJECT_UNLOCK (identity);

    gst_identity_notify_last_message (identity);
  }

  if (identity->single_segment && (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT)) {
    if (!trans->have_segment) {
      GstEvent *news;
      GstSegment segment;

      gst_event_copy_segment (event, &segment);
      gst_event_copy_segment (event, &trans->segment);
      trans->have_segment = TRUE;

      /* This is the first segment, send out a (0, -1) segment */
      gst_segment_init (&segment, segment.format);
      news = gst_event_new_segment (&segment);

      gst_pad_event_default (trans->sinkpad, GST_OBJECT_CAST (trans), news);
    } else {
      /* need to track segment for proper running time */
      gst_event_copy_segment (event, &trans->segment);
    }
  }

  if (GST_EVENT_TYPE (event) == GST_EVENT_GAP &&
      trans->have_segment && trans->segment.format == GST_FORMAT_TIME) {
    GstClockTime start, dur;

    gst_event_parse_gap (event, &start, &dur);
    if (GST_CLOCK_TIME_IS_VALID (start)) {
      start = gst_segment_to_running_time (&trans->segment,
          GST_FORMAT_TIME, start);

      gst_identity_do_sync (identity, start);

      /* also transform GAP timestamp similar to buffer timestamps */
      if (identity->single_segment) {
        gst_event_unref (event);
        event = gst_event_new_gap (start, dur);
      }
    }
  }

  /* Reset previous timestamp, duration and offsets on SEGMENT
   * to prevent false warnings when checking for perfect streams */
  if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
    identity->prev_timestamp = identity->prev_duration = GST_CLOCK_TIME_NONE;
    identity->prev_offset = identity->prev_offset_end = GST_BUFFER_OFFSET_NONE;
  }

  if (identity->single_segment && GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
    /* eat up segments */
    gst_event_unref (event);
    ret = TRUE;
  } else {
    if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) {
      GST_OBJECT_LOCK (identity);
      if (identity->clock_id) {
        GST_DEBUG_OBJECT (identity, "unlock clock wait");
        gst_clock_id_unschedule (identity->clock_id);
        gst_clock_id_unref (identity->clock_id);
        identity->clock_id = NULL;
      }
      GST_OBJECT_UNLOCK (identity);
    }

    ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
  }

  return ret;
}
Exemplo n.º 14
0
static gboolean
gst_vdp_mpeg_dec_sink_event (GstPad * pad, GstEvent * event)
{
    GstVdpMpegDec *mpeg_dec = GST_VDP_MPEG_DEC (gst_pad_get_parent (pad));
    gboolean res;

    switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:
    {
        GST_DEBUG_OBJECT (mpeg_dec, "flush stop");

        gst_vdp_mpeg_dec_flush (mpeg_dec);
        res = gst_pad_push_event (mpeg_dec->src, event);

        break;
    }
    case GST_EVENT_NEWSEGMENT:
    {
        gboolean update;
        gdouble rate;
        GstFormat format;
        gint64 start;
        gint64 stop;
        gint64 position;

        gst_event_parse_new_segment (event, &update, &rate, &format,
                                     &start, &stop, &position);

        if (format != GST_FORMAT_TIME) {
            if (!gst_vdp_mpeg_dec_convert (mpeg_dec, format, start,
                                           GST_FORMAT_TIME, &start))
                goto convert_error;
            if (!gst_vdp_mpeg_dec_convert (mpeg_dec, format, stop,
                                           GST_FORMAT_TIME, &stop))
                goto convert_error;
            if (!gst_vdp_mpeg_dec_convert (mpeg_dec, format, position,
                                           GST_FORMAT_TIME, &position))
                goto convert_error;

            gst_event_unref (event);
            event = gst_event_new_new_segment (update, rate, GST_FORMAT_TIME, start,
                                               stop, position);
        }

        g_mutex_lock (mpeg_dec->mutex);
        /* if we seek ourselves we don't push out a newsegment now since we
         * use the calculated timestamp of the first frame for this */
        if (mpeg_dec->seeking) {
            gst_event_unref (event);
            res = TRUE;
            g_mutex_unlock (mpeg_dec->mutex);
            goto done;
        }
        g_mutex_unlock (mpeg_dec->mutex);

        GST_DEBUG_OBJECT (mpeg_dec,
                          "Pushing new segment update %d format %d start %"
                          GST_TIME_FORMAT " stop %" GST_TIME_FORMAT " position %"
                          GST_TIME_FORMAT, update, format, GST_TIME_ARGS (start),
                          GST_TIME_ARGS (stop), GST_TIME_ARGS (position));
convert_error:
        res = gst_pad_push_event (mpeg_dec->src, event);

        break;
    }
    default:
        res = gst_pad_event_default (pad, event);
    }

done:
    gst_object_unref (mpeg_dec);

    return res;
}
static GstFlowReturn
xing_mp3_encoder_chain(GstPad *pad, GstBuffer *buf)
{
    XingMp3Encoder *encoder;
    GstFlowReturn ret = GST_FLOW_OK;
  
    g_return_val_if_fail(pad != NULL, GST_FLOW_ERROR);
    g_return_val_if_fail(GST_IS_PAD(pad), GST_FLOW_ERROR);
    g_return_val_if_fail(buf != NULL, GST_FLOW_ERROR);

    encoder = XING_MP3_ENCODER(gst_pad_get_parent(pad));

    if(GST_IS_EVENT(buf)) {
        GstEvent *event = GST_EVENT(buf);

        switch(GST_EVENT_TYPE(event)) {
            case GST_EVENT_EOS:
                encoder->at_end_of_stream = TRUE;
                gst_event_unref(event);
                break;

            default:
                gst_pad_event_default(pad, event);
                return ret;
        }
    } else {
        guchar *data;
        gulong size;
        gulong i, j;
        float **buffer;
        gint buf_size;
        gint buf_pos;

        if(!encoder->is_initialized) {
            gst_buffer_unref(buf);
            GST_ELEMENT_ERROR(encoder, CORE, NEGOTIATION, (NULL), ("Encoder not initialized"));
            return GST_FLOW_UNEXPECTED;
        }

        if(!encoder->header_sent) {
            E_CONTROL control;
            MPEG_HEAD head;
            guchar output_buffer[OUTPUT_BUFFER_SIZE];
            gint buf_len;

            if(!encoder->use_cbr) {
                GstFlowReturn push_ret;
                
                hx_mp3enc_l3_info_ec(encoder->xing_encoder, &control);
                hx_mp3enc_l3_info_head(encoder->xing_encoder, &head);

                buf_len = XingHeader(control.samprate, head.mode, control.cr_bit, control.original,
                    VBR_SCALE_FLAG /* FRAMES_FLAG | BYTES_FLAG | TOC_FLAG */, 0, 0,
                    control.vbr_flag ? control.vbr_mnr : -1, NULL,
                    output_buffer, 0, 0, 0);
            
                if((push_ret = xing_mp3_encoder_push_buffer(encoder, output_buffer,
                    buf_len)) != GST_FLOW_OK) {
                    gst_buffer_unref(buf);
                    return push_ret;
                }
            }
            
            encoder->header_sent = TRUE;
        }

        data = (guchar *)GST_BUFFER_DATA(buf);
        buf_size = GST_BUFFER_SIZE(buf);
        buf_pos = 0;

        /* Transfer incoming data to internal buffer.
         * TODO: Use a ring buffer, avoid memmove () */

        while(buf_pos < buf_size) {
            gint gulp = MIN(buf_size - buf_pos, INPUT_BUFFER_SIZE - encoder->input_buffer_pos);

            memcpy(encoder->input_buffer + encoder->input_buffer_pos, data + buf_pos, gulp);

            encoder->samples_in += gulp / (2 * encoder->channels);
            encoder->input_buffer_pos += gulp;
            buf_pos += gulp;

            /* Pass data on to encoder */
            while(encoder->input_buffer_pos >= encoder->bytes_per_frame) {
                guchar output_buffer[OUTPUT_BUFFER_SIZE];
                IN_OUT x;

                x = hx_mp3enc_mp3_encode_frame(encoder->xing_encoder, 
                    encoder->input_buffer, output_buffer);

                if(x.in_bytes == 0 && x.out_bytes == 0) {
                    break;
                }

                memmove(encoder->input_buffer, encoder->input_buffer + x.in_bytes,
                    encoder->input_buffer_pos - x.in_bytes);
                encoder->input_buffer_pos -= x.in_bytes;

                /* Accept output from encoder and pass it on.
                 * TODO: Do this less often and save CPU */
                if(x.out_bytes > 0) {
                    GstFlowReturn push_ret;
                    
                    if((push_ret = xing_mp3_encoder_push_buffer(encoder, output_buffer,
                        x.out_bytes)) != GST_FLOW_OK) {
                        gst_buffer_unref(buf);
                        return push_ret;
                    }
                }
            }
        }

        gst_buffer_unref(buf);
    }

    if(encoder->at_end_of_stream) {
        gst_pad_push_event(encoder->srcpad, gst_event_new_eos());
    }
  
    return ret;
}
Exemplo n.º 16
0
static gboolean
gst_identity_event (GstBaseTransform * trans, GstEvent * event)
{
  GstIdentity *identity;
  gboolean ret = TRUE;

  identity = GST_IDENTITY (trans);

  if (!identity->silent) {
    const GstStructure *s;
    gchar *sstr;

    GST_OBJECT_LOCK (identity);
    g_free (identity->last_message);

    if ((s = gst_event_get_structure (event)))
      sstr = gst_structure_to_string (s);
    else
      sstr = g_strdup ("");

    identity->last_message =
        g_strdup_printf ("event   ******* (%s:%s) E (type: %d, %s) %p",
        GST_DEBUG_PAD_NAME (trans->sinkpad), GST_EVENT_TYPE (event), sstr,
        event);
    g_free (sstr);
    GST_OBJECT_UNLOCK (identity);

    gst_identity_notify_last_message (identity);
  }

  if (identity->single_segment
      && (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)) {
    if (trans->have_newsegment == FALSE) {
      GstEvent *news;
      GstFormat format;

      gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL,
          NULL);

      /* This is the first newsegment, send out a (0, -1) newsegment */
      news = gst_event_new_new_segment (TRUE, 1.0, format, 0, -1, 0);

      gst_pad_event_default (trans->sinkpad, news);
    }
  }

  /* Reset previous timestamp, duration and offsets on NEWSEGMENT
   * to prevent false warnings when checking for perfect streams */
  if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
    identity->prev_timestamp = identity->prev_duration = GST_CLOCK_TIME_NONE;
    identity->prev_offset = identity->prev_offset_end = GST_BUFFER_OFFSET_NONE;
  }

  ret = parent_class->event (trans, event);

  if (identity->single_segment
      && (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)) {
    /* eat up segments */
    ret = FALSE;
  }

  return ret;
}
static gboolean
gst_type_find_element_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  gboolean res = FALSE;
  GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (parent);

  GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
      GST_EVENT_TYPE_NAME (event), typefind->mode);

  switch (typefind->mode) {
    case MODE_TYPEFIND:
      switch (GST_EVENT_TYPE (event)) {
        case GST_EVENT_CAPS:
        {
          GstCaps *caps;

          /* Parse and push out our caps and data */
          gst_event_parse_caps (event, &caps);
          res = gst_type_find_element_setcaps (typefind, caps);

          gst_event_unref (event);
          break;
        }
        case GST_EVENT_GAP:
        {
          GST_FIXME_OBJECT (typefind,
              "GAP events during typefinding not handled properly");

          /* FIXME: These would need to be inserted in the stream at
           * the right position between buffers, but we combine all
           * buffers with a GstAdapter. Drop the GAP event for now,
           * which will only cause an implicit GAP between buffers.
           */
          gst_event_unref (event);
          res = TRUE;
          break;
        }
        case GST_EVENT_EOS:
        {
          GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
          gst_type_find_element_chain_do_typefinding (typefind, FALSE, TRUE);

          res = gst_pad_push_event (typefind->src, event);
          break;
        }
        case GST_EVENT_FLUSH_STOP:{
          GList *l;

          GST_OBJECT_LOCK (typefind);

          for (l = typefind->cached_events; l; l = l->next) {
            if (GST_EVENT_IS_STICKY (l->data) &&
                GST_EVENT_TYPE (l->data) != GST_EVENT_SEGMENT &&
                GST_EVENT_TYPE (l->data) != GST_EVENT_EOS) {
              gst_pad_store_sticky_event (typefind->src, l->data);
            }
            gst_event_unref (l->data);
          }

          g_list_free (typefind->cached_events);
          typefind->cached_events = NULL;
          gst_adapter_clear (typefind->adapter);
          GST_OBJECT_UNLOCK (typefind);
          /* fall through */
        }
        case GST_EVENT_FLUSH_START:
          res = gst_pad_push_event (typefind->src, event);
          break;
        default:
          /* Forward events that would happen before the caps event
           * directly instead of storing them. There's no reason not
           * to send them directly and we should only store events
           * for later sending that would need to come after the caps
           * event */
          if (GST_EVENT_TYPE (event) < GST_EVENT_CAPS) {
            res = gst_pad_push_event (typefind->src, event);
          } else {
            GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
                GST_EVENT_TYPE_NAME (event));
            GST_OBJECT_LOCK (typefind);
            typefind->cached_events =
                g_list_append (typefind->cached_events, event);
            GST_OBJECT_UNLOCK (typefind);
            res = TRUE;
          }
          break;
      }
      break;
    case MODE_NORMAL:
      res = gst_pad_push_event (typefind->src, event);
      break;
    case MODE_ERROR:
      break;
    default:
      g_assert_not_reached ();
  }
  return res;
}
Exemplo n.º 18
0
static gboolean
gst_omx_audio_enc_sink_event (GstAudioEncoder * encoder, GstEvent * event)
{
  GstOMXAudioEnc *self;
  GstOMXAudioEncClass *klass;
  OMX_ERRORTYPE err;

  self = GST_OMX_AUDIO_ENC (encoder);
  klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);

  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
    GstOMXBuffer *buf;
    GstOMXAcquireBufferReturn acq_ret;

    GST_DEBUG_OBJECT (self, "Sending EOS to the component");

    /* Don't send EOS buffer twice, this doesn't work */
    if (self->eos) {
      GST_DEBUG_OBJECT (self, "Component is already EOS");
      return TRUE;
    }
    self->eos = TRUE;

    if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
      GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");

      /* Insert a NULL into the queue to signal EOS */
      g_mutex_lock (&self->enc->lock);
      g_queue_push_tail (&self->enc_out_port->pending_buffers, NULL);
      g_mutex_unlock (&self->enc->lock);
      g_mutex_lock (&self->enc->messages_lock);
      g_cond_broadcast (&self->enc->messages_cond);
      g_mutex_unlock (&self->enc->messages_lock);
      return TRUE;
    }

    /* Make sure to release the base class stream lock, otherwise
     * _loop() can't call _finish_frame() and we might block forever
     * because no input buffers are released */
    GST_AUDIO_ENCODER_STREAM_UNLOCK (self);

    /* Send an EOS buffer to the component and let the base
     * class drop the EOS event. We will send it later when
     * the EOS buffer arrives on the output port. */
    acq_ret = gst_omx_port_acquire_buffer (self->enc_in_port, &buf);
    if (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK) {
      buf->omx_buf->nFilledLen = 0;
      buf->omx_buf->nTimeStamp =
          gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
          GST_SECOND);
      buf->omx_buf->nTickCount = 0;
      buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
      err = gst_omx_port_release_buffer (self->enc_in_port, buf);
      if (err != OMX_ErrorNone) {
        GST_ERROR_OBJECT (self, "Failed to send EOS to component: %s (0x%08x)",
            gst_omx_error_to_string (err), err);
      } else {
        GST_DEBUG_OBJECT (self, "Sent EOS to the component");
      }
    } else {
      GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", acq_ret);
    }

    GST_AUDIO_ENCODER_STREAM_LOCK (self);

    return TRUE;
  }

  return FALSE;
}
Exemplo n.º 19
0
static gboolean
gst_raw_parse_sink_event (GstPad * pad, GstEvent * event)
{
  GstRawParse *rp = GST_RAW_PARSE (gst_pad_get_parent (pad));
  gboolean ret;

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_EOS:
    case GST_EVENT_FLUSH_STOP:
      /* Only happens in push mode */
      gst_raw_parse_reset (rp);
      ret = gst_pad_push_event (rp->srcpad, event);
      break;
    case GST_EVENT_NEWSEGMENT:
    {
      GstClockTimeDiff start, stop, time;
      gdouble rate, arate;
      gboolean update;
      GstFormat format;

      /* Only happens in push mode */

      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
          &start, &stop, &time);

      if (format == GST_FORMAT_TIME) {
        gst_segment_set_newsegment_full (&rp->segment, update, rate, arate,
            GST_FORMAT_TIME, start, stop, time);
        ret = gst_pad_push_event (rp->srcpad, event);
      } else {

        gst_event_unref (event);

        ret =
            gst_raw_parse_convert (rp, format, start, GST_FORMAT_TIME, &start);
        ret &= gst_raw_parse_convert (rp, format, time, GST_FORMAT_TIME, &time);
        ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_TIME, &stop);
        if (!ret) {
          GST_ERROR_OBJECT (rp,
              "Failed converting to GST_FORMAT_TIME format (%d)", format);
          break;
        }

        gst_segment_set_newsegment_full (&rp->segment, update, rate, arate,
            GST_FORMAT_TIME, start, stop, time);

        /* create new segment with the fields converted to time */
        event = gst_event_new_new_segment_full (update, rate, arate,
            GST_FORMAT_TIME, start, stop, time);

        ret = gst_pad_push_event (rp->srcpad, event);
      }
      break;
    }
    default:
      ret = gst_pad_event_default (rp->sinkpad, event);
      break;
  }

  gst_object_unref (rp);

  return ret;
}
Exemplo n.º 20
0
static gboolean
gst_timidity_src_event (GstPad * pad, GstEvent * event)
{
  gboolean res = FALSE;
  GstTimidity *timidity = GST_TIMIDITY (gst_pad_get_parent (pad));

  GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      gdouble rate;
      GstFormat src_format, dst_format;
      GstSeekFlags flags;
      GstSeekType start_type, stop_type;
      gint64 orig_start, start = 0, stop = 0;
      gboolean flush, update;

      if (!timidity->song)
        break;

      gst_event_parse_seek (event, &rate, &src_format, &flags,
          &start_type, &orig_start, &stop_type, &stop);

      dst_format = GST_FORMAT_DEFAULT;

      gst_timidity_src_convert (timidity, src_format, orig_start,
          &dst_format, &start);
      gst_timidity_src_convert (timidity, src_format, stop, &dst_format, &stop);

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

      if (flush) {
        GST_DEBUG ("performing flush");
        gst_pad_push_event (timidity->srcpad, gst_event_new_flush_start ());
      } else {
        gst_pad_stop_task (timidity->sinkpad);
      }

      GST_PAD_STREAM_LOCK (timidity->sinkpad);

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

      gst_segment_set_seek (timidity->o_segment, rate, dst_format, flags,
          start_type, start, stop_type, stop, &update);

      if (flags & GST_SEEK_FLAG_SEGMENT) {
        GST_DEBUG_OBJECT (timidity, "received segment seek %d, %d",
            (gint) start_type, (gint) stop_type);
      } else {
        GST_DEBUG_OBJECT (timidity, "received normal seek %d",
            (gint) start_type);
        update = FALSE;
      }

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

      timidity->o_seek = TRUE;

      gst_pad_start_task (timidity->sinkpad,
          (GstTaskFunction) gst_timidity_loop, timidity->sinkpad);

      GST_PAD_STREAM_UNLOCK (timidity->sinkpad);
      GST_DEBUG ("seek done");
    }
      res = TRUE;
      break;
    default:
      break;
  }

  g_object_unref (timidity);
  return res;
}
Exemplo n.º 21
0
static gboolean
gst_base_video_codec_sink_event (GstPad * pad, GstEvent * event)
{
  GstBaseVideoCodec *base_video_codec;
  gboolean ret = FALSE;

  base_video_codec = GST_BASE_VIDEO_CODEC (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
      ret = gst_pad_push_event (base_video_codec->srcpad, event);
      break;
    case GST_EVENT_FLUSH_STOP:
      gst_base_video_codec_reset (base_video_codec);
      ret = gst_pad_push_event (base_video_codec->srcpad, event);
      break;
    case GST_EVENT_EOS:
      if (gst_base_video_codec_push_all (base_video_codec,
              FALSE) == GST_FLOW_ERROR) {
        gst_event_unref (event);
        return FALSE;
      }

      ret = gst_pad_push_event (base_video_codec->srcpad, event);
      break;
    case GST_EVENT_NEWSEGMENT:
    {
      gboolean update;
      GstFormat format;
      gdouble rate;
      gint64 start, stop, time;

      gst_event_parse_new_segment (event, &update, &rate, &format, &start,
          &stop, &time);

      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

      if (rate <= 0.0)
        goto newseg_wrong_rate;

      GST_DEBUG ("newsegment %" GST_TIME_FORMAT " %" GST_TIME_FORMAT,
          GST_TIME_ARGS (start), GST_TIME_ARGS (time));
      gst_segment_set_newsegment (&base_video_codec->state.segment, update,
          rate, format, start, stop, time);

      ret = gst_pad_push_event (base_video_codec->srcpad, event);
      break;
    }
    default:
      ret = gst_pad_push_event (base_video_codec->srcpad, event);
      break;
  }
done:
  gst_object_unref (base_video_codec);
  return ret;

newseg_wrong_format:
  GST_DEBUG_OBJECT (base_video_codec, "received non TIME newsegment");
  gst_event_unref (event);
  goto done;

newseg_wrong_rate:
  GST_DEBUG_OBJECT (base_video_codec, "negative rates not supported");
  gst_event_unref (event);
  goto done;
}
Exemplo n.º 22
0
static gboolean
gst_dvbsub_overlay_event_text (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  gboolean ret = FALSE;
  GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (parent);

  GST_DEBUG_OBJECT (pad, "received text event %s", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEGMENT:
    {
      GstSegment seg;

      GST_DEBUG_OBJECT (render, "received new segment");

      gst_event_copy_segment (event, &seg);

      if (seg.format == GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (render, "SUBTITLE SEGMENT now: %" GST_SEGMENT_FORMAT,
            &render->subtitle_segment);

        render->subtitle_segment = seg;

        GST_DEBUG_OBJECT (render,
            "SUBTITLE SEGMENT after: %" GST_SEGMENT_FORMAT,
            &render->subtitle_segment);
        ret = TRUE;
        gst_event_unref (event);
      } else {
        GST_ELEMENT_WARNING (render, STREAM, MUX, (NULL),
            ("received non-TIME newsegment event on subtitle sinkpad"));
        ret = FALSE;
        gst_event_unref (event);
      }
      break;
    }
    case GST_EVENT_FLUSH_STOP:
      GST_DEBUG_OBJECT (render, "stop flushing");
      gst_dvbsub_overlay_flush_subtitles (render);
      gst_segment_init (&render->subtitle_segment, GST_FORMAT_TIME);
      gst_event_unref (event);
      ret = TRUE;
      break;
    case GST_EVENT_FLUSH_START:
      GST_DEBUG_OBJECT (render, "begin flushing");
      gst_event_unref (event);
      ret = TRUE;
      break;
    case GST_EVENT_EOS:
      GST_INFO_OBJECT (render, "text EOS");
      gst_event_unref (event);
      ret = TRUE;
      break;
    case GST_EVENT_GAP:
      gst_event_unref (event);
      ret = TRUE;
      break;
    case GST_EVENT_CAPS:
      /* don't want to forward the subtitle caps */
      gst_event_unref (event);
      ret = TRUE;
      break;
    default:
      ret = gst_pad_push_event (render->srcpad, event);
      break;
  }

  return ret;
}
Exemplo n.º 23
0
static gboolean
gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
{
  GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
  gdouble new_x, new_y, x, y;
  GstStructure *structure;
  gboolean ret;

  GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NAVIGATION:
      event =
          GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));

      structure = (GstStructure *) gst_event_get_structure (event);
      if (gst_structure_get_double (structure, "pointer_x", &x) &&
          gst_structure_get_double (structure, "pointer_y", &y)) {
        GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
        switch (vf->method) {
          case GST_VIDEO_FLIP_METHOD_90R:
            new_x = y;
            new_y = vf->to_width - x;
            break;
          case GST_VIDEO_FLIP_METHOD_90L:
            new_x = vf->to_height - y;
            new_y = x;
            break;
          case GST_VIDEO_FLIP_METHOD_OTHER:
            new_x = vf->to_height - y;
            new_y = vf->to_width - x;
            break;
          case GST_VIDEO_FLIP_METHOD_TRANS:
            new_x = y;
            new_y = x;
            break;
          case GST_VIDEO_FLIP_METHOD_180:
            new_x = vf->to_width - x;
            new_y = vf->to_height - y;
            break;
          case GST_VIDEO_FLIP_METHOD_HORIZ:
            new_x = vf->to_width - x;
            new_y = y;
            break;
          case GST_VIDEO_FLIP_METHOD_VERT:
            new_x = x;
            new_y = vf->to_height - y;
            break;
          default:
            new_x = x;
            new_y = y;
            break;
        }
        GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y);
        gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
            "pointer_y", G_TYPE_DOUBLE, new_y, NULL);
      }
      break;
    default:
      break;
  }

  ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);

  return ret;
}
Exemplo n.º 24
0
static gboolean
pad_event (GstPad *pad,
           GstEvent *event)
{
    GstOmxBaseFilter *self;
    GOmxCore *gomx;
    GOmxPort *in_port;
    GOmxPort *out_port;
    gboolean ret;

    self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
    gomx = self->gomx;
    in_port = self->in_port;
    out_port = self->out_port;

    GST_LOG_OBJECT (self, "begin");

    GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));

    switch (GST_EVENT_TYPE (event))
    {
        case GST_EVENT_EOS:
            if (self->initialized)
            {
                /* send buffer with eos flag */
                /** @todo move to util */
                {
                    OMX_BUFFERHEADERTYPE *omx_buffer;

                    GST_LOG_OBJECT (self, "request buffer");
                    omx_buffer = g_omx_port_request_buffer (in_port);

                    if (G_LIKELY (omx_buffer))
                    {
                        omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;

                        GST_LOG_OBJECT (self, "release_buffer");
                        /* foo_buffer_untaint (omx_buffer); */
                        g_omx_port_release_buffer (in_port, omx_buffer);
                    }
                    else
                    {
                        g_omx_core_set_done (gomx);
                    }
                }

                /* Wait for the output port to get the EOS. */
                g_omx_core_wait_for_done (gomx);
            }

            ret = gst_pad_push_event (self->srcpad, event);
            break;

        case GST_EVENT_FLUSH_START:
            gst_pad_push_event (self->srcpad, event);
            self->last_pad_push_return = GST_FLOW_WRONG_STATE;

            g_omx_core_flush_start (gomx);

            gst_pad_pause_task (self->srcpad);

            ret = TRUE;
            break;

        case GST_EVENT_FLUSH_STOP:
            gst_pad_push_event (self->srcpad, event);
            self->last_pad_push_return = GST_FLOW_OK;

            g_omx_core_flush_stop (gomx);

            gst_pad_start_task (self->srcpad, output_loop, self->srcpad);

            ret = TRUE;
            break;

        case GST_EVENT_NEWSEGMENT:
            ret = gst_pad_push_event (self->srcpad, event);
            break;

        default:
            ret = gst_pad_push_event (self->srcpad, event);
            break;
    }

    GST_LOG_OBJECT (self, "end");

    return ret;
}
Exemplo n.º 25
0
static GstPadProbeReturn
link_to_videomixer (GstPad * pad, GstPadProbeInfo * info,
    KmsCompositeMixerData * data)
{
  GstPadTemplate *sink_pad_template;
  KmsCompositeMixer *mixer;

  if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_EVENT (info)) !=
      GST_EVENT_STREAM_START) {
    return GST_PAD_PROBE_PASS;
  }

  mixer = KMS_COMPOSITE_MIXER (data->mixer);
  GST_DEBUG ("stream start detected %d", data->id);
  KMS_COMPOSITE_MIXER_LOCK (mixer);

  data->link_probe_id = 0;

  sink_pad_template =
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (mixer->priv->
          videomixer), "sink_%u");

  if (G_UNLIKELY (sink_pad_template == NULL)) {
    GST_ERROR_OBJECT (mixer, "Error taking a new pad from videomixer");
    KMS_COMPOSITE_MIXER_UNLOCK (mixer);
    return GST_PAD_PROBE_DROP;
  }

  if (mixer->priv->videotestsrc == NULL) {
    GstElement *capsfilter;
    GstCaps *filtercaps;
    GstPad *pad;

    mixer->priv->videotestsrc = gst_element_factory_make ("videotestsrc", NULL);
    capsfilter = gst_element_factory_make ("capsfilter", NULL);

    g_object_set (mixer->priv->videotestsrc, "is-live", TRUE, "pattern",
        /*black */ 2, NULL);

    filtercaps =
        gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "AYUV",
        "width", G_TYPE_INT, mixer->priv->output_width,
        "height", G_TYPE_INT, mixer->priv->output_height,
        "framerate", GST_TYPE_FRACTION, 15, 1, NULL);
    g_object_set (G_OBJECT (capsfilter), "caps", filtercaps, NULL);
    gst_caps_unref (filtercaps);

    gst_bin_add_many (GST_BIN (mixer), mixer->priv->videotestsrc,
        capsfilter, NULL);

    gst_element_link (mixer->priv->videotestsrc, capsfilter);

    /*link capsfilter -> videomixer */
    pad = gst_element_request_pad (mixer->priv->videomixer, sink_pad_template,
        NULL, NULL);

    gst_element_link_pads (capsfilter, NULL,
        mixer->priv->videomixer, GST_OBJECT_NAME (pad));
    g_object_set (pad, "xpos", 0, "ypos", 0, "alpha", 0.0, NULL);
    g_object_unref (pad);

    gst_element_sync_state_with_parent (capsfilter);
    gst_element_sync_state_with_parent (mixer->priv->videotestsrc);
  }

  data->videoscale = gst_element_factory_make ("videoscale", NULL);
  data->capsfilter = gst_element_factory_make ("capsfilter", NULL);
  data->videorate = gst_element_factory_make ("videorate", NULL);
  data->queue = gst_element_factory_make ("queue", NULL);
  data->input = TRUE;

  gst_bin_add_many (GST_BIN (mixer), data->queue, data->videorate,
      data->videoscale, data->capsfilter, NULL);

  g_object_set (data->videorate, "average-period", 200 * GST_MSECOND, NULL);
  g_object_set (data->queue, "flush-on-eos", TRUE, "max-size-buffers", 60,
      NULL);

  gst_element_link_many (data->videorate, data->queue, data->videoscale,
      data->capsfilter, NULL);

  /*link capsfilter -> videomixer */
  data->video_mixer_pad =
      gst_element_request_pad (mixer->priv->videomixer,
      sink_pad_template, NULL, NULL);
  gst_element_link_pads (data->capsfilter, NULL,
      mixer->priv->videomixer, GST_OBJECT_NAME (data->video_mixer_pad));

  gst_element_link (data->videoconvert, data->videorate);

  data->probe_id = gst_pad_add_probe (data->video_mixer_pad,
      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
      (GstPadProbeCallback) cb_EOS_received,
      KMS_COMPOSITE_MIXER_REF (data), (GDestroyNotify) kms_ref_struct_unref);

  gst_element_sync_state_with_parent (data->videoscale);
  gst_element_sync_state_with_parent (data->capsfilter);
  gst_element_sync_state_with_parent (data->videorate);
  gst_element_sync_state_with_parent (data->queue);

  /*recalculate the output sizes */
  mixer->priv->n_elems++;
  kms_composite_mixer_recalculate_sizes (mixer);

  KMS_COMPOSITE_MIXER_UNLOCK (mixer);

  return GST_PAD_PROBE_REMOVE;
}
/* srcpad functions */
static gboolean
gst_stream_synchronizer_src_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamSynchronizer *self = GST_STREAM_SYNCHRONIZER (parent);
  gboolean ret = FALSE;

  GST_LOG_OBJECT (pad, "Handling event %s: %" GST_PTR_FORMAT,
      GST_EVENT_TYPE_NAME (event), event);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_QOS:{
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;
      gint64 running_time_diff = -1;
      GstSyncStream *stream;

      gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
      gst_event_unref (event);

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (stream)
        running_time_diff = stream->segment.base;
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);

      if (running_time_diff == -1) {
        GST_WARNING_OBJECT (pad, "QOS event before group start");
        goto out;
      }
      if (timestamp < running_time_diff) {
        GST_DEBUG_OBJECT (pad, "QOS event from previous group");
        goto out;
      }

      GST_LOG_OBJECT (pad,
          "Adjusting QOS event: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " = %"
          GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
          GST_TIME_ARGS (running_time_diff),
          GST_TIME_ARGS (timestamp - running_time_diff));

      timestamp -= running_time_diff;

      /* That case is invalid for QoS events */
      if (diff < 0 && -diff > timestamp) {
        GST_DEBUG_OBJECT (pad, "QOS event from previous group");
        ret = TRUE;
        goto out;
      }

      event =
          gst_event_new_qos (GST_QOS_TYPE_UNDERFLOW, proportion, diff,
          timestamp);
      break;
    }
    default:
      break;
  }

  ret = gst_pad_event_default (pad, parent, event);

out:
  return ret;
}
static GstPadProbeReturn
handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
{
  GstSplitMuxSink *splitmux = ctx->splitmux;
  MqStreamBuf *buf_info = NULL;

  GST_LOG_OBJECT (pad, "Fired probe type 0x%x\n", info->type);

  /* FIXME: Handle buffer lists, until then make it clear they won't work */
  if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
    g_warning ("Buffer list handling not implemented");
    return GST_PAD_PROBE_DROP;
  }
  if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
    GstEvent *event = gst_pad_probe_info_get_event (info);

    GST_LOG_OBJECT (pad, "Event %" GST_PTR_FORMAT, event);

    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_SEGMENT:
        gst_event_copy_segment (event, &ctx->out_segment);
        break;
      case GST_EVENT_FLUSH_STOP:
        GST_SPLITMUX_LOCK (splitmux);
        gst_segment_init (&ctx->out_segment, GST_FORMAT_UNDEFINED);
        g_queue_foreach (&ctx->queued_bufs, (GFunc) mq_stream_buf_free, NULL);
        g_queue_clear (&ctx->queued_bufs);
        ctx->flushing = FALSE;
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_FLUSH_START:
        GST_SPLITMUX_LOCK (splitmux);
        GST_LOG_OBJECT (pad, "Flush start");
        ctx->flushing = TRUE;
        GST_SPLITMUX_BROADCAST (splitmux);
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_EOS:
        GST_SPLITMUX_LOCK (splitmux);
        if (splitmux->state == SPLITMUX_STATE_STOPPED)
          goto beach;
        ctx->out_eos = TRUE;
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_GAP:{
        GstClockTime gap_ts;

        gst_event_parse_gap (event, &gap_ts, NULL);
        if (gap_ts == GST_CLOCK_TIME_NONE)
          break;

        GST_SPLITMUX_LOCK (splitmux);

        gap_ts = gst_segment_to_running_time (&ctx->out_segment,
            GST_FORMAT_TIME, gap_ts);

        GST_LOG_OBJECT (pad, "Have GAP w/ ts %" GST_TIME_FORMAT,
            GST_TIME_ARGS (gap_ts));

        if (splitmux->state == SPLITMUX_STATE_STOPPED)
          goto beach;
        ctx->out_running_time = gap_ts;
        complete_or_wait_on_out (splitmux, ctx);
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      }
      default:
        break;
    }
    return GST_PAD_PROBE_PASS;
  }

  /* Allow everything through until the configured next stopping point */
  GST_SPLITMUX_LOCK (splitmux);

  buf_info = g_queue_pop_tail (&ctx->queued_bufs);
  if (buf_info == NULL)
    /* Can only happen due to a poorly timed flush */
    goto beach;

  /* If we have popped a keyframe, decrement the queued_gop count */
  if (buf_info->keyframe && splitmux->queued_gops > 0)
    splitmux->queued_gops--;

  ctx->out_running_time = buf_info->run_ts;

  GST_LOG_OBJECT (splitmux,
      "Pad %" GST_PTR_FORMAT " buffer with TS %" GST_TIME_FORMAT
      " size %" G_GSIZE_FORMAT,
      pad, GST_TIME_ARGS (ctx->out_running_time), buf_info->buf_size);

  complete_or_wait_on_out (splitmux, ctx);

  if (splitmux->muxed_out_time == GST_CLOCK_TIME_NONE ||
      splitmux->muxed_out_time < buf_info->run_ts)
    splitmux->muxed_out_time = buf_info->run_ts;

  splitmux->muxed_out_bytes += buf_info->buf_size;

#ifndef GST_DISABLE_GST_DEBUG
  {
    GstBuffer *buf = gst_pad_probe_info_get_buffer (info);
    GST_LOG_OBJECT (pad, "Returning to pass buffer %" GST_PTR_FORMAT
        " run ts %" GST_TIME_FORMAT, buf,
        GST_TIME_ARGS (ctx->out_running_time));
  }
#endif

  GST_SPLITMUX_UNLOCK (splitmux);

  mq_stream_buf_free (buf_info);

  return GST_PAD_PROBE_PASS;

beach:
  GST_SPLITMUX_UNLOCK (splitmux);
  return GST_PAD_PROBE_DROP;
}
/* sinkpad functions */
static gboolean
gst_stream_synchronizer_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamSynchronizer *self = GST_STREAM_SYNCHRONIZER (parent);
  gboolean ret = FALSE;

  GST_LOG_OBJECT (pad, "Handling event %s: %" GST_PTR_FORMAT,
      GST_EVENT_TYPE_NAME (event), event);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_STREAM_START:
    {
      GstSyncStream *stream, *ostream;
      guint32 seqnum = gst_event_get_seqnum (event);
      guint group_id;
      gboolean have_group_id;
      GList *l;
      gboolean all_wait = TRUE;
      gboolean new_stream = TRUE;

      have_group_id = gst_event_parse_group_id (event, &group_id);

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      self->have_group_id &= have_group_id;
      have_group_id = self->have_group_id;

      stream = gst_pad_get_element_private (pad);

      if (!stream) {
        GST_DEBUG_OBJECT (self, "No stream or STREAM_START from same source");
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        break;
      }

      gst_event_parse_stream_flags (event, &stream->flags);

      if ((have_group_id && stream->group_id != group_id) || (!have_group_id
              && stream->stream_start_seqnum != seqnum)) {
        stream->is_eos = FALSE;
        stream->eos_sent = FALSE;
        stream->flushing = FALSE;
        stream->stream_start_seqnum = seqnum;
        stream->group_id = group_id;

        if (!have_group_id) {
          /* Check if this belongs to a stream that is already there,
           * e.g. we got the visualizations for an audio stream */
          for (l = self->streams; l; l = l->next) {
            ostream = l->data;

            if (ostream != stream && ostream->stream_start_seqnum == seqnum
                && !ostream->wait) {
              new_stream = FALSE;
              break;
            }
          }

          if (!new_stream) {
            GST_DEBUG_OBJECT (pad,
                "Stream %d belongs to running stream %d, no waiting",
                stream->stream_number, ostream->stream_number);
            stream->wait = FALSE;

            GST_STREAM_SYNCHRONIZER_UNLOCK (self);
            break;
          }
        } else if (group_id == self->group_id) {
          GST_DEBUG_OBJECT (pad, "Stream %d belongs to running group %d, "
              "no waiting", stream->stream_number, group_id);
          GST_STREAM_SYNCHRONIZER_UNLOCK (self);
          break;
        }

        GST_DEBUG_OBJECT (pad, "Stream %d changed", stream->stream_number);

        stream->wait = TRUE;

        for (l = self->streams; l; l = l->next) {
          GstSyncStream *ostream = l->data;

          all_wait = all_wait && ((ostream->flags & GST_STREAM_FLAG_SPARSE)
              || (ostream->wait && (!have_group_id
                      || ostream->group_id == group_id)));
          if (!all_wait)
            break;
        }

        if (all_wait) {
          gint64 position = 0;

          if (have_group_id)
            GST_DEBUG_OBJECT (self,
                "All streams have changed to group id %u -- unblocking",
                group_id);
          else
            GST_DEBUG_OBJECT (self, "All streams have changed -- unblocking");

          self->group_id = group_id;

          for (l = self->streams; l; l = l->next) {
            GstSyncStream *ostream = l->data;
            gint64 stop_running_time;
            gint64 position_running_time;

            ostream->wait = FALSE;

            if (ostream->segment.format == GST_FORMAT_TIME) {
              if (ostream->segment.rate > 0)
                stop_running_time =
                    gst_segment_to_running_time (&ostream->segment,
                    GST_FORMAT_TIME, ostream->segment.stop);
              else
                stop_running_time =
                    gst_segment_to_running_time (&ostream->segment,
                    GST_FORMAT_TIME, ostream->segment.start);

              position_running_time =
                  gst_segment_to_running_time (&ostream->segment,
                  GST_FORMAT_TIME, ostream->segment.position);

              position_running_time =
                  MAX (position_running_time, stop_running_time);

              if (ostream->segment.rate > 0)
                position_running_time -=
                    gst_segment_to_running_time (&ostream->segment,
                    GST_FORMAT_TIME, ostream->segment.start);
              else
                position_running_time -=
                    gst_segment_to_running_time (&ostream->segment,
                    GST_FORMAT_TIME, ostream->segment.stop);

              position_running_time = MAX (0, position_running_time);

              position = MAX (position, position_running_time);
            }
          }

          self->group_start_time += position;

          GST_DEBUG_OBJECT (self, "New group start time: %" GST_TIME_FORMAT,
              GST_TIME_ARGS (self->group_start_time));

          for (l = self->streams; l; l = l->next) {
            GstSyncStream *ostream = l->data;
            ostream->wait = FALSE;
            g_cond_broadcast (&ostream->stream_finish_cond);
          }
        }
      }

      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_SEGMENT:{
      GstSyncStream *stream;
      GstSegment segment;

      gst_event_copy_segment (event, &segment);

      GST_STREAM_SYNCHRONIZER_LOCK (self);

      gst_stream_synchronizer_wait (self, pad);

      if (self->shutdown) {
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        gst_event_unref (event);
        goto done;
      }

      stream = gst_pad_get_element_private (pad);
      if (stream && segment.format == GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (pad,
            "New stream, updating base from %" GST_TIME_FORMAT " to %"
            GST_TIME_FORMAT, GST_TIME_ARGS (segment.base),
            GST_TIME_ARGS (segment.base + self->group_start_time));
        segment.base += self->group_start_time;

        GST_DEBUG_OBJECT (pad, "Segment was: %" GST_SEGMENT_FORMAT,
            &stream->segment);
        gst_segment_copy_into (&segment, &stream->segment);
        GST_DEBUG_OBJECT (pad, "Segment now is: %" GST_SEGMENT_FORMAT,
            &stream->segment);
        stream->segment_seqnum = gst_event_get_seqnum (event);

        GST_DEBUG_OBJECT (pad, "Stream start running time: %" GST_TIME_FORMAT,
            GST_TIME_ARGS (stream->segment.base));
        {
          GstEvent *tmpev;

          tmpev = gst_event_new_segment (&stream->segment);
          gst_event_set_seqnum (tmpev, stream->segment_seqnum);
          gst_event_unref (event);
          event = tmpev;
        }
      } else if (stream) {
        GST_WARNING_OBJECT (pad, "Non-TIME segment: %s",
            gst_format_get_name (segment.format));
        gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_FLUSH_START:{
      GstSyncStream *stream;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      self->eos = FALSE;
      if (stream) {
        GST_DEBUG_OBJECT (pad, "Flushing streams");
        stream->flushing = TRUE;
        g_cond_broadcast (&stream->stream_finish_cond);
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_FLUSH_STOP:{
      GstSyncStream *stream;
      GList *l;
      GstClockTime new_group_start_time = 0;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (stream) {
        GST_DEBUG_OBJECT (pad, "Resetting segment for stream %d",
            stream->stream_number);
        gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);

        stream->is_eos = FALSE;
        stream->eos_sent = FALSE;
        stream->flushing = FALSE;
        stream->wait = FALSE;
        g_cond_broadcast (&stream->stream_finish_cond);
      }

      for (l = self->streams; l; l = l->next) {
        GstSyncStream *ostream = l->data;
        GstClockTime start_running_time;

        if (ostream == stream || ostream->flushing)
          continue;

        if (ostream->segment.format == GST_FORMAT_TIME) {
          if (ostream->segment.rate > 0)
            start_running_time =
                gst_segment_to_running_time (&ostream->segment,
                GST_FORMAT_TIME, ostream->segment.start);
          else
            start_running_time =
                gst_segment_to_running_time (&ostream->segment,
                GST_FORMAT_TIME, ostream->segment.stop);

          new_group_start_time = MAX (new_group_start_time, start_running_time);
        }
      }

      GST_DEBUG_OBJECT (pad,
          "Updating group start time from %" GST_TIME_FORMAT " to %"
          GST_TIME_FORMAT, GST_TIME_ARGS (self->group_start_time),
          GST_TIME_ARGS (new_group_start_time));
      self->group_start_time = new_group_start_time;
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
      /* unblocking EOS wait when track switch. */
    case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:{
      if (gst_event_has_name (event, "playsink-custom-video-flush")
          || gst_event_has_name (event, "playsink-custom-audio-flush")
          || gst_event_has_name (event, "playsink-custom-subtitle-flush")) {
        GstSyncStream *stream;

        GST_STREAM_SYNCHRONIZER_LOCK (self);
        stream = gst_pad_get_element_private (pad);
        if (stream) {
          stream->is_eos = FALSE;
          stream->eos_sent = FALSE;
          stream->wait = FALSE;
          g_cond_broadcast (&stream->stream_finish_cond);
        }
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      }
      break;
    }
    case GST_EVENT_EOS:{
      GstSyncStream *stream;
      GList *l;
      gboolean all_eos = TRUE;
      gboolean seen_data;
      GSList *pads = NULL;
      GstPad *srcpad;
      GstClockTime timestamp;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (!stream) {
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        GST_WARNING_OBJECT (pad, "EOS for unknown stream");
        break;
      }

      GST_DEBUG_OBJECT (pad, "Have EOS for stream %d", stream->stream_number);
      stream->is_eos = TRUE;

      seen_data = stream->seen_data;
      srcpad = gst_object_ref (stream->srcpad);

      if (seen_data && stream->segment.position != -1)
        timestamp = stream->segment.position;
      else if (stream->segment.rate < 0.0 || stream->segment.stop == -1)
        timestamp = stream->segment.start;
      else
        timestamp = stream->segment.stop;

      stream->segment.position = timestamp;

      for (l = self->streams; l; l = l->next) {
        GstSyncStream *ostream = l->data;

        all_eos = all_eos && ostream->is_eos;
        if (!all_eos)
          break;
      }

      if (all_eos) {
        GST_DEBUG_OBJECT (self, "All streams are EOS -- forwarding");
        self->eos = TRUE;
        for (l = self->streams; l; l = l->next) {
          GstSyncStream *ostream = l->data;
          /* local snapshot of current pads */
          gst_object_ref (ostream->srcpad);
          pads = g_slist_prepend (pads, ostream->srcpad);
        }
      }
      if (pads) {
        GstPad *pad;
        GSList *epad;
        GstSyncStream *ostream;

        ret = TRUE;
        epad = pads;
        while (epad) {
          pad = epad->data;
          ostream = gst_pad_get_element_private (pad);
          if (ostream) {
            g_cond_broadcast (&ostream->stream_finish_cond);
          }

          gst_object_unref (pad);
          epad = g_slist_next (epad);
        }
        g_slist_free (pads);
      } else {
        if (seen_data) {
          self->send_gap_event = TRUE;
          stream->gap_duration = GST_CLOCK_TIME_NONE;
          stream->wait = TRUE;
          ret = gst_stream_synchronizer_wait (self, srcpad);
        }
      }

      /* send eos if haven't seen data. seen_data will be true if data buffer
       * of the track have received in anytime. sink is ready if seen_data is
       * true, so can send GAP event. Will send EOS if sink isn't ready. The
       * scenario for the case is one track haven't any media data and then
       * send EOS. Or no any valid media data in one track, so decoder can't
       * get valid CAPS for the track. sink can't ready without received CAPS.*/
      if (!seen_data || self->eos) {
        GST_DEBUG_OBJECT (pad, "send EOS event");
        /* drop lock when sending eos, which may block in e.g. preroll */
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        ret = gst_pad_push_event (srcpad, gst_event_new_eos ());
        GST_STREAM_SYNCHRONIZER_LOCK (self);
        stream = gst_pad_get_element_private (pad);
        if (stream) {
          stream->eos_sent = TRUE;
        }
      }

      gst_object_unref (srcpad);
      gst_event_unref (event);
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      goto done;
    }
    default:
      break;
  }

  ret = gst_pad_event_default (pad, parent, event);

done:

  return ret;
}
/* Pipeline Callbacks */
static gboolean
probe_cb (InsanityGstTest * ptest, GstPad * pad, GstMiniObject * object,
    gpointer userdata)
{
  InsanityTest *test = INSANITY_TEST (ptest);

  global_last_probe = g_get_monotonic_time ();

  DECODER_TEST_LOCK ();
  if (GST_IS_BUFFER (object)) {
    GstBuffer *buf;
    GstClockTime ts;

    buf = GST_BUFFER (object);
    ts = GST_BUFFER_PTS (buf);

    /* First check clipping */
    if (glob_testing_parser == FALSE && GST_CLOCK_TIME_IS_VALID (ts) &&
        glob_waiting_segment == FALSE) {
      GstClockTime ts_end, cstart, cstop;

      /* Check if buffer is completely outside the segment */
      ts_end = ts;
      if (GST_BUFFER_DURATION_IS_VALID (buf))
        ts_end += GST_BUFFER_DURATION (buf);

      /* Check if buffer is completely outside the segment */
      ts_end = ts;
      if (!gst_segment_clip (&glob_last_segment,
              glob_last_segment.format, ts, ts_end, &cstart, &cstop)) {
        char *msg = g_strdup_printf ("Got timestamp %" GST_TIME_FORMAT " -- %"
            GST_TIME_FORMAT ", outside configured segment (%" GST_TIME_FORMAT
            " -- %" GST_TIME_FORMAT "), method %s",
            GST_TIME_ARGS (ts), GST_TIME_ARGS (ts_end),
            GST_TIME_ARGS (glob_last_segment.start),
            GST_TIME_ARGS (glob_last_segment.stop),
            test_get_name (glob_in_progress));
        insanity_test_validate_checklist_item (INSANITY_TEST (ptest),
            "segment-clipping", FALSE, msg);
        g_free (msg);
        glob_bad_segment_clipping = TRUE;
      }
    }

    switch (glob_in_progress) {
      case TEST_NONE:
        if (glob_waiting_first_segment == TRUE)
          insanity_test_validate_checklist_item (test, "first-segment",
              FALSE, "Got a buffer before the first segment");

        /* Got the first buffer, starting testing dance */
        next_test (test);
        break;
      case TEST_POSITION:
        test_position (test, buf);
        break;
      case TEST_FAST_FORWARD:
      case TEST_BACKWARD_PLAYBACK:
      case TEST_FAST_BACKWARD:
      {
        gint64 stime_ts;

        if (GST_CLOCK_TIME_IS_VALID (ts) == FALSE ||
            glob_waiting_segment == TRUE) {
          break;
        }

        stime_ts = gst_segment_to_stream_time (&glob_last_segment,
            glob_last_segment.format, ts);

        if (GST_CLOCK_TIME_IS_VALID (glob_seek_first_buf_ts) == FALSE) {
          GstClockTime expected_ts =
              gst_segment_to_stream_time (&glob_last_segment,
              glob_last_segment.format,
              glob_seek_rate <
              0 ? glob_seek_stop_ts : glob_seek_segment_seektime);

          GstClockTimeDiff diff = ABS (GST_CLOCK_DIFF (stime_ts, expected_ts));

          if (diff > SEEK_THRESHOLD) {
            gchar *valmsg =
                g_strdup_printf ("Received buffer timestamp %" GST_TIME_FORMAT
                " Seeek wanted %" GST_TIME_FORMAT "",
                GST_TIME_ARGS (stime_ts),
                GST_TIME_ARGS (expected_ts));

            validate_current_test (test, FALSE, valmsg);
            next_test (test);

            g_free (valmsg);
          } else
            glob_seek_first_buf_ts = stime_ts;

        } else {
          GstClockTimeDiff diff =
              GST_CLOCK_DIFF (stime_ts, glob_seek_first_buf_ts);

          if (diff < 0)
            diff = -diff;

          if (diff >= glob_playback_duration * GST_SECOND) {
            validate_current_test (test, TRUE, NULL);
            next_test (test);
          }
        }
        break;
      }
      default:
        break;
    }

  } else if (GST_IS_EVENT (object)) {
    GstEvent *event = GST_EVENT (object);
    guint seqnum = gst_event_get_seqnum (event);

    if (G_LIKELY (glob_seqnum_found == FALSE) && seqnum == glob_seqnum)
      glob_seqnum_found = TRUE;

    if (glob_seqnum_found == TRUE && seqnum != glob_seqnum) {
      gchar *message = g_strdup_printf ("Current seqnum %i != "
          "received %i", glob_seqnum, seqnum);

      insanity_test_validate_checklist_item (test, "seqnum-management",
          FALSE, message);

      glob_wrong_seqnum = TRUE;
      g_free (message);
    }

    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_SEGMENT:
      {
        gst_event_copy_segment (event, &glob_last_segment);

        if (glob_waiting_segment == FALSE)
          /* Cache the segment as it will be our reference but don't look
           * further */
          goto done;

        glob_last_segment_start_time = glob_last_segment.start;
        if (glob_waiting_first_segment == TRUE) {
          insanity_test_validate_checklist_item (test, "first-segment", TRUE,
              NULL);

          glob_waiting_first_segment = FALSE;
        } else if (glob_in_progress >= TEST_FAST_FORWARD &&
            glob_in_progress <= TEST_FAST_BACKWARD) {
          GstClockTimeDiff diff;
          gboolean valid_stop = TRUE;
          GstClockTimeDiff wdiff, rdiff;

          rdiff =
              ABS (GST_CLOCK_DIFF (glob_last_segment.stop,
                  glob_last_segment.start)) * ABS (glob_last_segment.rate *
              glob_last_segment.applied_rate);
          wdiff =
              ABS (GST_CLOCK_DIFF (glob_seek_stop_ts,
                  glob_seek_segment_seektime));

          diff =
              GST_CLOCK_DIFF (glob_last_segment.position,
              glob_seek_segment_seektime);
          if (diff < 0)
            diff = -diff;

          /* Now compare with the expected segment */
          if ((glob_last_segment.rate * glob_last_segment.applied_rate) ==
              glob_seek_rate && diff <= SEEK_THRESHOLD && valid_stop) {
            glob_seek_got_segment = TRUE;
          } else {
            GstClockTime stopdiff = ABS (GST_CLOCK_DIFF (rdiff, wdiff));

            gchar *validate_msg =
                g_strdup_printf ("Wrong segment received, Rate %f expected "
                "%f, start time diff %" GST_TIME_FORMAT " stop diff %"
                GST_TIME_FORMAT,
                (glob_last_segment.rate * glob_last_segment.applied_rate),
                glob_seek_rate,
                GST_TIME_ARGS (diff), GST_TIME_ARGS (stopdiff));

            validate_current_test (test, FALSE, validate_msg);
            next_test (test);
            g_free (validate_msg);
          }
        }

        glob_waiting_segment = FALSE;
        break;
      }
      default:
        break;
    }
  }

done:
  DECODER_TEST_UNLOCK ();
  return TRUE;
}
Exemplo n.º 30
0
static gboolean
gst_kate_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstKateEnc *ke = GST_KATE_ENC (parent);
  const GstStructure *structure;
  gboolean ret;

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

      gst_event_parse_caps (event, &caps);
      ret = gst_kate_enc_setcaps (ke, caps);
      gst_event_unref (event);
      break;
    }
    case GST_EVENT_SEGMENT:{
      GstSegment seg;

      GST_LOG_OBJECT (ke, "Got newsegment event");

      gst_event_copy_segment (event, &seg);

      if (!ke->headers_sent) {
        if (ke->pending_segment)
          gst_event_unref (ke->pending_segment);
        ke->pending_segment = event;
        event = NULL;
      }

      if (ke->initialized) {
        GST_LOG_OBJECT (ke, "ensuring all headers are in");
        if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
          GST_WARNING_OBJECT (ke, "Failed to flush headers");
        } else {
          if (seg.format != GST_FORMAT_TIME
              || !GST_CLOCK_TIME_IS_VALID (seg.start)) {
            GST_WARNING_OBJECT (ke,
                "No time in newsegment event %p, format %d, timestamp %"
                G_GINT64_FORMAT, event, (int) seg.format, seg.start);
            /* to be safe, we'd need to generate a keepalive anyway, but we'd have to guess at the timestamp to use; a
               good guess would be the last known timestamp plus the keepalive time, but if we then get a packet with a
               timestamp less than this, it would fail to encode, which would be Bad. If we don't encode a keepalive, we
               run the risk of stalling the pipeline and hanging, which is Very Bad. Oh dear. We can't exit(-1), can we ? */
          } else {
            float t = seg.start / (double) GST_SECOND;

            if (ke->delayed_spu
                && t - ke->delayed_start / (double) GST_SECOND >=
                ke->default_spu_duration) {
              if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
                          seg.start) != GST_FLOW_OK)) {
                GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
                /* continue with new segment handling anyway */
              }
            }

            GST_LOG_OBJECT (ke, "ts %f, last %f (min %f)", t,
                ke->last_timestamp / (double) GST_SECOND,
                ke->keepalive_min_time);
            if (ke->keepalive_min_time > 0.0f
                && t - ke->last_timestamp / (double) GST_SECOND >=
                ke->keepalive_min_time) {
              /* we only generate a keepalive if there is no SPU waiting, as it would
                 mean out of sequence start times - and granulepos */
              if (!ke->delayed_spu) {
                gst_kate_enc_generate_keepalive (ke, seg.start);
              }
            }
          }
        }
      }
      if (event)
        ret = gst_pad_push_event (ke->srcpad, event);
      else
        ret = TRUE;
      break;
    }
    case GST_EVENT_CUSTOM_DOWNSTREAM:
      GST_LOG_OBJECT (ke, "Got custom downstream event");
      /* adapted from the dvdsubdec element */
      structure = gst_event_get_structure (event);
      if (structure != NULL
          && gst_structure_has_name (structure, "application/x-gst-dvd")) {
        if (ke->initialized) {
          GST_LOG_OBJECT (ke, "ensuring all headers are in");
          if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
            GST_WARNING_OBJECT (ke, "Failed to flush headers");
          } else {
            const gchar *event_name =
                gst_structure_get_string (structure, "event");
            if (event_name) {
              if (!strcmp (event_name, "dvd-spu-clut-change")) {
                gchar name[16];
                int idx;
                gboolean found;
                gint value;
                GST_INFO_OBJECT (ke, "New CLUT received");
                for (idx = 0; idx < 16; ++idx) {
                  g_snprintf (name, sizeof (name), "clut%02d", idx);
                  found = gst_structure_get_int (structure, name, &value);
                  if (found) {
                    ke->spu_clut[idx] = value;
                  } else {
                    GST_WARNING_OBJECT (ke,
                        "DVD CLUT event did not contain %s field", name);
                  }
                }
              } else if (!strcmp (event_name, "dvd-lang-codes")) {
                /* we can't know which stream corresponds to us */
              }
            } else {
              GST_WARNING_OBJECT (ke, "custom downstream event with no name");
            }
          }
        }
      }
      ret = gst_pad_push_event (ke->srcpad, event);
      break;

    case GST_EVENT_TAG:
      GST_LOG_OBJECT (ke, "Got tag event");
      if (ke->tags) {
        GstTagList *list;

        gst_event_parse_tag (event, &list);
        gst_tag_list_insert (ke->tags, list,
            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke)));
      } else {
        g_assert_not_reached ();
      }
      ret = gst_pad_event_default (pad, parent, event);
      break;

    case GST_EVENT_EOS:
      GST_INFO_OBJECT (ke, "Got EOS event");
      if (ke->initialized) {
        GST_LOG_OBJECT (ke, "ensuring all headers are in");
        if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
          GST_WARNING_OBJECT (ke, "Failed to flush headers");
        } else {
          kate_packet kp;
          int ret;
          GstClockTime delayed_end =
              ke->delayed_start + ke->default_spu_duration * GST_SECOND;

          if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
                      delayed_end) != GST_FLOW_OK)) {
            GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
            /* continue with EOS handling anyway */
          }

          ret = kate_encode_finish (&ke->k, -1, &kp);
          if (ret < 0) {
            GST_WARNING_OBJECT (ke, "Failed to encode EOS packet: %s",
                gst_kate_util_get_error_message (ret));
          } else {
            kate_int64_t granpos = kate_encode_get_granule (&ke->k);
            GST_LOG_OBJECT (ke, "EOS packet encoded");
            if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos,
                    ke->latest_end_time, 0, FALSE)) {
              GST_WARNING_OBJECT (ke, "Failed to push EOS packet");
            }
          }
        }
      }
      ret = gst_pad_event_default (pad, parent, event);
      break;

    default:
      GST_LOG_OBJECT (ke, "Got unhandled event");
      ret = gst_pad_event_default (pad, parent, event);
      break;
  }

  return ret;
}