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