/** * psmux_stream_free: * @stream: a #PsMuxStream * * Free the resources of @stream. */ void psmux_stream_free (PsMuxStream * stream) { g_return_if_fail (stream != NULL); if (psmux_stream_bytes_in_buffer (stream)) { g_warning ("Freeing stream with data not yet processed"); } g_slice_free (PsMuxStream, stream); }
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; }
/** * psmux_stream_get_data: * @stream: a #PsMuxStream * @buf: a buffer to hold the result * @len: the length of @buf * * Write a PES packet to @buf, up to @len bytes * * Returns: number of bytes having been written, 0 if error */ guint psmux_stream_get_data (PsMuxStream * stream, guint8 * buf, guint len) { guint8 pes_hdr_length; guint w; g_return_val_if_fail (stream != NULL, FALSE); g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (len >= PSMUX_PES_MAX_HDR_LEN, FALSE); stream->cur_pes_payload_size = MIN (psmux_stream_bytes_in_buffer (stream), len - PSMUX_PES_MAX_HDR_LEN); /* Note that we cannot make a better estimation of the header length for the * time being; because the header length is dependent on whether we can find a * timestamp in the upcomming buffers, which in turn depends on * cur_pes_payload_size, which is exactly what we want to decide. */ psmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size, &stream->pts, &stream->dts); /* clear pts/dts flag */ stream->pi.flags &= ~(PSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS | PSMUX_PACKET_FLAG_PES_WRITE_PTS); /* update pts/dts flag */ if (stream->pts != -1 && stream->dts != -1) stream->pi.flags |= PSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS; else { if (stream->pts != -1) stream->pi.flags |= PSMUX_PACKET_FLAG_PES_WRITE_PTS; } pes_hdr_length = psmux_stream_pes_header_length (stream); /* write pes header */ GST_LOG ("Writing PES header of length %u and payload %d", pes_hdr_length, stream->cur_pes_payload_size); psmux_stream_write_pes_header (stream, buf); buf += pes_hdr_length; w = stream->cur_pes_payload_size; /* number of bytes of payload to write */ while (w > 0) { guint32 avail; guint8 *cur; if (stream->cur_buffer == NULL) { /* Start next packet */ if (stream->buffers == NULL) return FALSE; stream->cur_buffer = (PsMuxStreamBuffer *) (stream->buffers->data); stream->cur_buffer_consumed = 0; } /* Take as much as we can from the current buffer */ avail = stream->cur_buffer->map.size - stream->cur_buffer_consumed; cur = stream->cur_buffer->map.data + stream->cur_buffer_consumed; if (avail < w) { memcpy (buf, cur, avail); psmux_stream_consume (stream, avail); buf += avail; w -= avail; } else { memcpy (buf, cur, w); psmux_stream_consume (stream, w); w = 0; } } return pes_hdr_length + stream->cur_pes_payload_size; }