static void
dxr3videosink_write_data (Dxr3VideoSink * sink, guint cut)
{
  guint size, written;
  guint8 *data;

  g_return_if_fail (sink->cur_buf != NULL);

  if (GST_OBJECT_FLAG_IS_SET (sink, DXR3VIDEOSINK_OPEN)) {
    if (sink->cur_ts != GST_CLOCK_TIME_NONE) {
      guint pts;

/*       fprintf (stderr, "------ Video Time %.04f\n", */
/*                (double) sink->cur_ts / GST_SECOND); */

      pts = (guint) GSTTIME_TO_MPEGTIME (sink->cur_ts);
      ioctl (sink->video_fd, EM8300_IOCTL_VIDEO_SETPTS, &pts);
      sink->cur_ts = GST_CLOCK_TIME_NONE;
    }

    data = GST_BUFFER_DATA (sink->cur_buf);
    size = sink->scan_pos - cut;

    g_assert (size <= GST_BUFFER_SIZE (sink->cur_buf));

    /* We should always write data that corresponds to whole MPEG
       video sintactical elements.  They should always start with an
       MPEG start code. */
    g_assert (size >= 4 && data[0] == 0 && data[1] == 0 && data[2] == 1);

    while (size > 0) {
      written = write (sink->video_fd, data, size);
      if (written < 0) {
        GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
            (_("Could not write to device \"%s\"."), sink->video_filename),
            GST_ERROR_SYSTEM);
        break;
      }
      size = size - written;
      data = data + written;
    };
  }

  dxr3videosink_discard_data (sink, cut);
}
Beispiel #2
0
static void
dxr3spusink_chain (GstPad * pad, GstData * _data)
{
  GstBuffer *buf = GST_BUFFER (_data);
  Dxr3SpuSink *sink;
  gint bytes_written = 0;

  g_return_if_fail (pad != NULL);
  g_return_if_fail (GST_IS_PAD (pad));
  g_return_if_fail (buf != NULL);

  sink = DXR3SPUSINK (gst_pad_get_parent (pad));

  if (GST_IS_EVENT (buf)) {
    dxr3spusink_handle_event (pad, GST_EVENT (buf));
    return;
  }

  if (GST_OBJECT_FLAG_IS_SET (sink, DXR3SPUSINK_OPEN)) {
    /* If we have PTS information for the SPU unit, register it now.
       The card needs the PTS to be written *before* the actual data. */
    if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
      guint pts = (guint) GSTTIME_TO_MPEGTIME (GST_BUFFER_TIMESTAMP (buf));

      ioctl (sink->spu_fd, EM8300_IOCTL_SPU_SETPTS, &pts);
    }

    bytes_written = write (sink->spu_fd, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf));
    if (bytes_written < GST_BUFFER_SIZE (buf)) {
      fprintf (stderr, "dxr3spusink: Warning: %d bytes should be written,"
          " only %d bytes written\n", GST_BUFFER_SIZE (buf), bytes_written);
    }
  }

  gst_buffer_unref (buf);
}
Beispiel #3
0
static GstFlowReturn
mpegtsmux_collected (GstCollectPads * pads, MpegTsMux * mux)
{
  GstFlowReturn ret = GST_FLOW_OK;
  MpegTsPadData *best = NULL;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (mux->first) {
    ret = mpegtsmux_create_streams (mux);
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    best = mpegtsmux_choose_best_stream (mux);

    if (!mpegtsdemux_prepare_srcpad (mux)) {
      GST_DEBUG_OBJECT (mux, "Failed to send new segment");
      goto new_seg_fail;
    }

    mux->first = FALSE;
  } else {
    best = mpegtsmux_choose_best_stream (mux);
  }

  if (best != NULL) {
    TsMuxProgram *prog = best->prog;
    GstBuffer *buf = best->queued_buf;
    gint64 pts = -1;
    gboolean delta = TRUE;

    if (prog == NULL) {
      GST_ELEMENT_ERROR (mux, STREAM, MUX, ("Stream is not associated with "
              "any program"), (NULL));
      return GST_FLOW_ERROR;
    }

    if (G_UNLIKELY (prog->pcr_stream == NULL)) {
      if (best) {
        /* Take the first data stream for the PCR */
        GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
            "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
            MPEG_TS_PAD_DATA (best)->pid, MPEG_TS_PAD_DATA (best)->prog_id);

        /* Set the chosen PCR stream */
        tsmux_program_set_pcr_stream (prog, best->stream);
      }
    }

    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
    if (best->stream->is_video_stream)
      delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
    GST_DEBUG_OBJECT (mux, "delta: %d", delta);

    GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
        "Chose stream for output (PID: 0x%04x)", best->pid);

    if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
      pts = GSTTIME_TO_MPEGTIME (best->cur_ts);
      GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
          G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
    }

    tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf), buf, pts, -1, !delta);
    best->queued_buf = NULL;

    mux->is_delta = delta;
    while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
      if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        goto write_fail;
      }
    }
    if (prog->pcr_stream == best->stream) {
      mux->last_ts = best->last_ts;
    }
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
  }

  return ret;
new_seg_fail:
  return GST_FLOW_ERROR;
write_fail:
  /* FIXME: Failed writing data for some reason. Should set appropriate error */
  return mux->last_flow_ret;
}
Beispiel #4
0
static GstFlowReturn
mpegtsmux_collected (GstCollectPads * pads, MpegTsMux * mux)
{
  GstFlowReturn ret = GST_FLOW_OK;
  MpegTsPadData *best = NULL;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (mux->first) {
    ret = mpegtsmux_create_streams (mux);
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    best = mpegtsmux_choose_best_stream (mux);

    if (mux->pcr_stream == NULL) {
      if (best) {
        /* Take the first data stream for the PCR */
        GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best), "Use stream as PCR");
        mux->pcr_stream = best->stream;
      }
    }

    /* Set the chosen PCR stream */
    g_return_val_if_fail (mux->pcr_stream != NULL, GST_FLOW_ERROR);
    tsmux_program_set_pcr_stream (mux->program, mux->pcr_stream);

    if (!mpegtsdemux_prepare_srcpad (mux)) {
      GST_DEBUG_OBJECT (mux, "Failed to send new segment");
      goto new_seg_fail;
    }

    mux->first = FALSE;
  } else {
    best = mpegtsmux_choose_best_stream (mux);
  }

  if (best != NULL) {
    GstBuffer *buf = best->queued_buf;
    gint64 pts = -1;

    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);

    GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
        "Chose stream for output (PID: 0x%04x)", best->pid);

    if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
      pts = GSTTIME_TO_MPEGTIME (best->cur_ts);
      GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
          G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
    }

    tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf), buf, pts, -1);
    best->queued_buf = NULL;

    while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
      if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        goto write_fail;
      }
    }
    if (mux->pcr_stream == best->stream) {
      mux->last_ts = best->last_ts;
    }
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
  }

  return ret;
new_seg_fail:
  return GST_FLOW_ERROR;
write_fail:
  /* FIXME: Failed writing data for some reason. Should set appropriate error */
  return mux->last_flow_ret;
}
Beispiel #5
0
static GstFlowReturn
mpegpsmux_collected (GstCollectPads * pads, MpegPsMux * mux)
{
  /* main muxing function */

  GstFlowReturn ret = GST_FLOW_OK;
  MpegPsPadData *best = NULL;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (mux->first) {             /* process block for the first mux */
    /* iterate through the collect pads and add streams to @mux */
    ret = mpegpsmux_create_streams (mux);
    /* Assumption : all pads are already added at this time */

    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    best = mpegpsmux_choose_best_stream (mux);

    /* prepare the src pad (output), return if failed */
    if (!mpegpsdemux_prepare_srcpad (mux)) {
      GST_DEBUG_OBJECT (mux, "Failed to send new segment");
      goto new_seg_fail;
    }

    mux->first = FALSE;
  } else {
    best = mpegpsmux_choose_best_stream (mux);
  }

  if (best != NULL) {
    /* @*buf : the buffer to be processed */
    GstBuffer *buf = best->queued_buf;
    gint64 pts = -1;

    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);

    GST_DEBUG_OBJECT (mux,
        "Chose stream from pad %" GST_PTR_FORMAT " for output (PID: 0x%04x)",
        best->collect.pad, best->stream_id);

    /* set timestamp */
    if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
      pts = GSTTIME_TO_MPEGTIME (best->cur_ts); /* @pts: current timestamp */
      GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
          G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
    }

    /* give the buffer to libpsmux for processing */
    psmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf), buf, pts, -1);
    best->queued_buf = NULL;

    /* write the data from libpsmux to stream */
    while (psmux_stream_bytes_in_buffer (best->stream) > 0) {
      GST_LOG_OBJECT (mux, "Before @psmux_write_stream_packet");
      if (!psmux_write_stream_packet (mux->psmux, best->stream)) {
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        goto write_fail;
      }
    }
    mux->last_ts = best->last_ts;
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    if (psmux_write_end_code (mux->psmux)) {
      GST_WARNING_OBJECT (mux, "Writing MPEG PS Program end code failed.");
    }
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
  }

  return ret;
new_seg_fail:
  return GST_FLOW_ERROR;
write_fail:
  /* FIXME: Failed writing data for some reason. Should set appropriate error */
  return mux->last_flow_ret;
}
Beispiel #6
0
static GstFlowReturn
mpegpsmux_collected (GstCollectPads * pads, MpegPsMux * mux)
{
  /* main muxing function */

  GstFlowReturn ret = GST_FLOW_OK;
  MpegPsPadData *best = NULL;
  gboolean keyunit;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (mux->first) {             /* process block for the first mux */
    /* iterate through the collect pads and add streams to @mux */
    ret = mpegpsmux_create_streams (mux);
    /* Assumption : all pads are already added at this time */

    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    best = mpegpsmux_choose_best_stream (mux);

    /* prepare the src pad (output), return if failed */
    if (!mpegpsdemux_prepare_srcpad (mux)) {
      GST_DEBUG_OBJECT (mux, "Failed to send new segment");
      goto new_seg_fail;
    }

    mux->first = FALSE;
  } else {
    best = mpegpsmux_choose_best_stream (mux);
  }

  if (best != NULL) {
    GstBuffer *buf = best->queued.buf;
    gint64 pts, dts;

    g_assert (buf != NULL);

    GST_LOG_OBJECT (mux,
        "Chose stream from pad %" GST_PTR_FORMAT " for output (PID: 0x%04x): "
        "adjusted pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT,
        best->collect.pad, best->stream_id,
        GST_TIME_ARGS (best->queued.pts), GST_TIME_ARGS (best->queued.dts));

    /* and convert to mpeg time stamps */
    pts = GSTTIME_TO_MPEGTIME (best->queued.pts);
    dts = GSTTIME_TO_MPEGTIME (best->queued.dts);

    /* start of new GOP? */
    keyunit = !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);

    if (keyunit && best->stream_id == mux->video_stream_id
        && mux->gop_list != NULL) {
      ret = mpegpsmux_push_gop_list (mux);
      if (ret != GST_FLOW_OK)
        goto done;
    }

    /* give the buffer to libpsmux for processing */
    psmux_stream_add_data (best->stream, buf, pts, dts, keyunit);

    best->queued.buf = NULL;

    /* write the data from libpsmux to stream */
    while (psmux_stream_bytes_in_buffer (best->stream) > 0) {
      GST_LOG_OBJECT (mux, "Before @psmux_write_stream_packet");
      if (!psmux_write_stream_packet (mux->psmux, best->stream)) {
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        goto write_fail;
      }
    }
    mux->last_ts = best->last_ts;
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    if (mux->gop_list != NULL)
      mpegpsmux_push_gop_list (mux);

    if (!psmux_write_end_code (mux->psmux)) {
      GST_WARNING_OBJECT (mux, "Writing MPEG PS Program end code failed.");
    }
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());

    ret = GST_FLOW_EOS;
  }

done:

  return ret;
new_seg_fail:
  return GST_FLOW_ERROR;
write_fail:
  /* FIXME: Failed writing data for some reason. Should set appropriate error */
  return mux->last_flow_ret;
}
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 void
dxr3audiosink_chain_ac3 (GstPad * pad, GstData * _data)
{
  Dxr3AudioSink *sink;
  gint bytes_written = 0;
  GstBuffer *buf;

  g_return_if_fail (pad != NULL);
  g_return_if_fail (GST_IS_PAD (pad));
  g_return_if_fail (_data != NULL);

  sink = DXR3AUDIOSINK (gst_pad_get_parent (pad));

  if (GST_IS_EVENT (_data)) {
    dxr3audiosink_handle_event (pad, GST_EVENT (_data));
    return;
  }

  buf = GST_BUFFER (_data);

  if (sink->mode != DXR3AUDIOSINK_MODE_AC3) {
    /* Switch to AC3 mode. */
    dxr3audiosink_set_mode_ac3 (sink);
  }

  if (GST_OBJECT_FLAG_IS_SET (sink, DXR3AUDIOSINK_OPEN)) {
    int event;

    if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
      /* We have a new scr value. */

/*       fprintf (stderr, "------ Audio Time %.04f\n", */
/*                (double) GST_BUFFER_TIMESTAMP (buf) / GST_SECOND); */

      sink->scr = GSTTIME_TO_MPEGTIME (GST_BUFFER_TIMESTAMP (buf));
    }

    /* Push the new data into the padder. */
    ac3p_push_data (sink->padder, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));

    /* Parse the data. */
    event = ac3p_parse (sink->padder);
    while (event != AC3P_EVENT_PUSH) {
      switch (event) {
        case AC3P_EVENT_FRAME:
          /* We have a new frame: */

          /* Update the system reference clock (SCR) in the card. */
        {
          unsigned in, out, odelay;
          unsigned diff;

          ioctl (sink->control_fd, EM8300_IOCTL_SCR_GET, &out);

          ioctl (sink->audio_fd, SNDCTL_DSP_GETODELAY, &odelay);
          /* 192000 bytes/sec */

          in = MPEGTIME_TO_DXRTIME (sink->scr - (odelay * 90) / 192);
          diff = in > out ? in - out : out - in;
          if (diff > 1800) {
            dxr3audiosink_set_scr (sink, in);
          }
        }

          /* Update our SCR value. */
          sink->scr += TIME_FOR_BYTES (ac3p_frame_size (sink->padder));

          /* Write the frame to the sound device. */
          bytes_written = write (sink->audio_fd, ac3p_frame (sink->padder),
              AC3P_IEC_FRAME_SIZE);

          if (bytes_written < AC3P_IEC_FRAME_SIZE) {
            fprintf (stderr, "dxr3audiosink: Warning: %d bytes should be "
                "written, only %d bytes written\n",
                AC3P_IEC_FRAME_SIZE, bytes_written);
          }

          break;
      }

      event = ac3p_parse (sink->padder);
    }
  }

  gst_buffer_unref (buf);
}
static void
dxr3audiosink_chain_pcm (GstPad * pad, GstData * _data)
{
  Dxr3AudioSink *sink;
  gint bytes_written = 0;
  GstBuffer *buf;

  g_return_if_fail (pad != NULL);
  g_return_if_fail (GST_IS_PAD (pad));
  g_return_if_fail (_data != NULL);

  sink = DXR3AUDIOSINK (gst_pad_get_parent (pad));

  if (GST_IS_EVENT (_data)) {
    dxr3audiosink_handle_event (pad, GST_EVENT (_data));
    return;
  }

  buf = GST_BUFFER (_data);

  if (sink->mode != DXR3AUDIOSINK_MODE_PCM) {
    /* Switch to PCM mode. */
    dxr3audiosink_set_mode_pcm (sink);
  }

  if (GST_OBJECT_FLAG_IS_SET (sink, DXR3AUDIOSINK_OPEN)) {
    if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
      /* We have a new scr value. */
      sink->scr = GSTTIME_TO_MPEGTIME (GST_BUFFER_TIMESTAMP (buf));
    }

    /* Update the system reference clock (SCR) in the card. */
    {
      unsigned in, out, odelay;
      unsigned diff;

      ioctl (sink->control_fd, EM8300_IOCTL_SCR_GET, &out);

      ioctl (sink->audio_fd, SNDCTL_DSP_GETODELAY, &odelay);

      in = MPEGTIME_TO_DXRTIME (sink->scr - (odelay * 90) / 192);
      diff = in > out ? in - out : out - in;
      if (diff > 1800) {
        dxr3audiosink_set_scr (sink, in);
      }
    }

    /* Update our SCR value. */
    sink->scr += (unsigned) (GST_BUFFER_SIZE (buf) *
        (90000.0 / ((float) sink->rate * 4)));

    /* Write the buffer to the sound device. */
    bytes_written = write (sink->audio_fd, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf));
    if (bytes_written < GST_BUFFER_SIZE (buf)) {
      fprintf (stderr, "dxr3audiosink: Warning: %d bytes should be "
          "written, only %d bytes written\n",
          GST_BUFFER_SIZE (buf), bytes_written);
    }
  }

  gst_buffer_unref (buf);
}
Beispiel #10
0
static GstFlowReturn
mpegtsmux_collected (GstCollectPads2 * pads, MpegTsMux * mux)
{
  GstFlowReturn ret = GST_FLOW_OK;
  MpegTsPadData *best = NULL;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (G_UNLIKELY (mux->first)) {
    ret = mpegtsmux_create_streams (mux);
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    mpegtsdemux_prepare_srcpad (mux);

    mux->first = FALSE;
  }

  best = mpegtsmux_choose_best_stream (mux);

  if (best != NULL) {
    TsMuxProgram *prog = best->prog;
    GstBuffer *buf = best->queued_buf;
    gint64 pts = -1;
    gboolean delta = TRUE;

    if (prog == NULL) {
      GST_ELEMENT_ERROR (mux, STREAM, MUX,
          ("Stream on pad %" GST_PTR_FORMAT
              " is not associated with any program", COLLECT_DATA_PAD (best)),
          (NULL));
      return GST_FLOW_ERROR;
    }

    if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
      GstEvent *event;

      event = check_pending_key_unit_event (mux->force_key_unit_event,
          &best->collect.segment, GST_BUFFER_TIMESTAMP (buf),
          GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
      if (event) {
        GstClockTime running_time;
        guint count;
        GList *cur;

        mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
        gst_event_replace (&mux->force_key_unit_event, NULL);

        gst_video_event_parse_downstream_force_key_unit (event,
            NULL, NULL, &running_time, NULL, &count);

        GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d "
            "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
            GST_TIME_ARGS (running_time), count);
        gst_pad_push_event (mux->srcpad, event);

        /* output PAT */
        mux->tsmux->last_pat_ts = -1;

        /* output PMT for each program */
        for (cur = g_list_first (mux->tsmux->programs); cur != NULL;
            cur = g_list_next (cur)) {
          TsMuxProgram *program = (TsMuxProgram *) cur->data;

          program->last_pmt_ts = -1;
        }
        tsmux_program_set_pcr_stream (prog, NULL);
      }
    }

    if (G_UNLIKELY (prog->pcr_stream == NULL)) {
      /* Take the first data stream for the PCR */
      GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
          "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
          MPEG_TS_PAD_DATA (best)->pid, MPEG_TS_PAD_DATA (best)->prog_id);

      /* Set the chosen PCR stream */
      tsmux_program_set_pcr_stream (prog, best->stream);
    }

    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
    if (best->stream->is_video_stream)
      delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
    GST_DEBUG_OBJECT (mux, "delta: %d", delta);

    GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
        "Chose stream for output (PID: 0x%04x)", best->pid);

    if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
      pts = GSTTIME_TO_MPEGTIME (best->cur_ts);
      GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
          G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
    }

    tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf), buf, pts, -1, !delta);
    best->queued_buf = NULL;

    mux->is_delta = delta;
    while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
      if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
        /* Failed writing data for some reason. Set appropriate error */
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        GST_ELEMENT_ERROR (mux, STREAM, MUX,
            ("Failed writing output data to stream %04x", best->stream->id),
            (NULL));
        goto write_fail;
      }
    }
    if (prog->pcr_stream == best->stream) {
      mux->last_ts = best->last_ts;
    }
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
  }

  return ret;
write_fail:
  return mux->last_flow_ret;
}