/** * tsmux_stream_initialize_pes_packet: * @stream: a #TsMuxStream * * Initializes the PES packet. * * Returns: TRUE if we the packet was initialized. */ gboolean tsmux_stream_initialize_pes_packet (TsMuxStream * stream) { if (stream->state != TSMUX_STREAM_STATE_HEADER) return TRUE; if (stream->pes_payload_size != 0) { /* Use prescribed fixed PES payload size */ stream->cur_pes_payload_size = stream->pes_payload_size; tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size, &stream->pts, &stream->dts); } else if (stream->is_video_stream) { /* Unbounded for video streams */ stream->cur_pes_payload_size = 0; tsmux_stream_find_pts_dts_within (stream, tsmux_stream_bytes_in_buffer (stream), &stream->pts, &stream->dts); } else { /* Output a PES packet of all currently available bytes otherwise */ stream->cur_pes_payload_size = tsmux_stream_bytes_in_buffer (stream); tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size, &stream->pts, &stream->dts); } stream->pi.flags &= ~(TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS | TSMUX_PACKET_FLAG_PES_WRITE_PTS); if (stream->pts != -1 && stream->dts != -1) stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS; else { if (stream->pts != -1) stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS; } if (stream->buffers) { TsMuxStreamBuffer *buf = (TsMuxStreamBuffer *) (stream->buffers->data); if (buf->random_access) { stream->pi.flags |= TSMUX_PACKET_FLAG_RANDOM_ACCESS; stream->pi.flags |= TSMUX_PACKET_FLAG_ADAPTATION; } } return TRUE; }
/** * tsmux_stream_bytes_avail: * @stream: a #TsMuxStream * * Calculate how much bytes are available. * * Returns: The number of bytes available. */ gint tsmux_stream_bytes_avail (TsMuxStream * stream) { gint bytes_avail; g_return_val_if_fail (stream != NULL, 0); if (stream->cur_pes_payload_size != 0) bytes_avail = stream->cur_pes_payload_size - stream->pes_bytes_written; else bytes_avail = tsmux_stream_bytes_in_buffer (stream); bytes_avail = MIN (bytes_avail, tsmux_stream_bytes_in_buffer (stream)); /* Calculate the number of bytes available in the current PES */ if (stream->state == TSMUX_STREAM_STATE_HEADER) bytes_avail += tsmux_stream_pes_header_length (stream); return bytes_avail; }
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 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; }