mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
mpegpsmux: use DTS in addition to PTS
And refactor choose_best_stream() a little. videotestsrc pattern=ball ! x264enc ! mpegpsmux ! ... plays much nicer now.
This commit is contained in:
parent
9e1faac4df
commit
d1e9a96a69
2 changed files with 97 additions and 65 deletions
|
@ -373,6 +373,66 @@ no_stream:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
mpegpsmux_queue_buffer_for_stream (MpegPsMux * mux, MpegPsPadData * ps_data)
|
||||
{
|
||||
GstCollectData *c_data = (GstCollectData *) ps_data;
|
||||
GstBuffer *buf;
|
||||
|
||||
g_assert (ps_data->queued.buf == NULL);
|
||||
|
||||
buf = gst_collect_pads_peek (mux->collect, c_data);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
ps_data->queued.buf = buf;
|
||||
|
||||
/* do any raw -> byte-stream format conversions (e.g. for H.264, AAC) */
|
||||
if (ps_data->prepare_func) {
|
||||
buf = ps_data->prepare_func (buf, ps_data, mux);
|
||||
if (buf) { /* Take the prepared buffer instead */
|
||||
gst_buffer_unref (ps_data->queued.buf);
|
||||
ps_data->queued.buf = buf;
|
||||
} else { /* If data preparation returned NULL, use unprepared one */
|
||||
buf = ps_data->queued.buf;
|
||||
}
|
||||
}
|
||||
|
||||
ps_data->queued.pts = GST_BUFFER_PTS (buf);
|
||||
if (GST_CLOCK_TIME_IS_VALID (ps_data->queued.pts)) {
|
||||
ps_data->queued.pts = gst_segment_to_running_time (&c_data->segment,
|
||||
GST_FORMAT_TIME, ps_data->queued.pts);
|
||||
}
|
||||
|
||||
ps_data->queued.dts = GST_BUFFER_DTS (buf);
|
||||
if (GST_CLOCK_TIME_IS_VALID (ps_data->queued.dts)) {
|
||||
ps_data->queued.dts = gst_segment_to_running_time (&c_data->segment,
|
||||
GST_FORMAT_TIME, ps_data->queued.dts);
|
||||
}
|
||||
|
||||
if (GST_BUFFER_PTS_IS_VALID (buf) && GST_BUFFER_DTS_IS_VALID (buf)) {
|
||||
ps_data->queued.ts = MIN (ps_data->queued.dts, ps_data->queued.pts);
|
||||
} else if (GST_BUFFER_PTS_IS_VALID (buf) && !GST_BUFFER_DTS_IS_VALID (buf)) {
|
||||
ps_data->queued.ts = ps_data->queued.pts;
|
||||
} else if (GST_BUFFER_DTS_IS_VALID (buf) && !GST_BUFFER_PTS_IS_VALID (buf)) {
|
||||
GST_WARNING_OBJECT (c_data->pad, "got DTS without PTS");
|
||||
ps_data->queued.ts = ps_data->queued.dts;
|
||||
} else {
|
||||
ps_data->queued.ts = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (mux, "Queued buffer with ts %" GST_TIME_FORMAT ": "
|
||||
"uncorrected pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT ", "
|
||||
"buffer pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " for PID 0x%04x",
|
||||
GST_TIME_ARGS (ps_data->queued.ts),
|
||||
GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
|
||||
GST_TIME_ARGS (ps_data->queued.pts),
|
||||
GST_TIME_ARGS (ps_data->queued.dts), ps_data->stream_id);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static MpegPsPadData *
|
||||
mpegpsmux_choose_best_stream (MpegPsMux * mux)
|
||||
{
|
||||
|
@ -387,42 +447,14 @@ mpegpsmux_choose_best_stream (MpegPsMux * mux)
|
|||
MpegPsPadData *ps_data = (MpegPsPadData *) walk->data;
|
||||
|
||||
if (ps_data->eos == FALSE) {
|
||||
if (ps_data->queued_buf == NULL) {
|
||||
if (ps_data->queued.buf == NULL) {
|
||||
GstBuffer *buf;
|
||||
|
||||
ps_data->queued_buf = buf =
|
||||
gst_collect_pads_peek (mux->collect, c_data);
|
||||
|
||||
if (buf != NULL) {
|
||||
if (ps_data->prepare_func) {
|
||||
buf = ps_data->prepare_func (buf, ps_data, mux);
|
||||
if (buf) { /* Take the prepared buffer instead */
|
||||
gst_buffer_unref (ps_data->queued_buf);
|
||||
ps_data->queued_buf = buf;
|
||||
} else { /* If data preparation returned NULL, use unprepared one */
|
||||
buf = ps_data->queued_buf;
|
||||
buf = mpegpsmux_queue_buffer_for_stream (mux, ps_data);
|
||||
if (buf == NULL) {
|
||||
ps_data->eos = TRUE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
|
||||
/* Ignore timestamps that go backward for now. FIXME: Handle all
|
||||
* incoming PTS */
|
||||
if (ps_data->last_ts == GST_CLOCK_TIME_NONE ||
|
||||
ps_data->last_ts < GST_BUFFER_TIMESTAMP (buf)) {
|
||||
ps_data->cur_ts = ps_data->last_ts =
|
||||
gst_segment_to_running_time (&c_data->segment,
|
||||
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (mux, "Ignoring PTS that has gone backward");
|
||||
}
|
||||
} else
|
||||
ps_data->cur_ts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
GST_DEBUG_OBJECT (mux, "Pulled buffer with ts %" GST_TIME_FORMAT
|
||||
" (uncorrected ts %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
|
||||
") for PID 0x%04x",
|
||||
GST_TIME_ARGS (ps_data->cur_ts),
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||
GST_BUFFER_TIMESTAMP (buf), ps_data->stream_id);
|
||||
|
||||
/* Choose a stream we've never seen a timestamp for to ensure
|
||||
* we push enough buffers from it to reach a timestamp */
|
||||
|
@ -430,10 +462,6 @@ mpegpsmux_choose_best_stream (MpegPsMux * mux)
|
|||
best = ps_data;
|
||||
c_best = c_data;
|
||||
}
|
||||
} else {
|
||||
ps_data->eos = TRUE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we don't yet have a best pad, take this one, otherwise take
|
||||
|
@ -505,22 +533,20 @@ mpegpsmux_collected (GstCollectPads * pads, MpegPsMux * mux)
|
|||
}
|
||||
|
||||
if (best != NULL) {
|
||||
/* @*buf : the buffer to be processed */
|
||||
GstBuffer *buf = best->queued_buf;
|
||||
gint64 pts = -1;
|
||||
GstBuffer *buf = best->queued.buf;
|
||||
gint64 pts, dts;
|
||||
|
||||
g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
|
||||
g_assert (buf != NULL);
|
||||
|
||||
GST_DEBUG_OBJECT (mux,
|
||||
"Chose stream from pad %" GST_PTR_FORMAT " for output (PID: 0x%04x)",
|
||||
best->collect.pad, best->stream_id);
|
||||
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));
|
||||
|
||||
/* 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);
|
||||
}
|
||||
/* 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);
|
||||
|
@ -532,11 +558,10 @@ mpegpsmux_collected (GstCollectPads * pads, MpegPsMux * mux)
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* FIXME: porting: add DTS */
|
||||
/* give the buffer to libpsmux for processing */
|
||||
psmux_stream_add_data (best->stream, buf, pts, -1, keyunit);
|
||||
psmux_stream_add_data (best->stream, buf, pts, dts, keyunit);
|
||||
|
||||
best->queued_buf = NULL;
|
||||
best->queued.buf = NULL;
|
||||
|
||||
/* write the data from libpsmux to stream */
|
||||
while (psmux_stream_bytes_in_buffer (best->stream) > 0) {
|
||||
|
|
|
@ -94,9 +94,16 @@ struct MpegPsPadData {
|
|||
guint8 stream_id_ext;
|
||||
PsMuxStream *stream;
|
||||
|
||||
GstBuffer *queued_buf; /* Currently pulled buffer */
|
||||
GstClockTime cur_ts; /* Adjusted TS for the pulled buffer */
|
||||
GstClockTime last_ts; /* Most recent valid TS for this stream */
|
||||
/* Currently pulled buffer */
|
||||
struct {
|
||||
GstBuffer *buf;
|
||||
GstClockTime ts; /* adjusted TS = MIN (DTS, PTS) for the pulled buffer */
|
||||
GstClockTime pts; /* adjusted PTS (running time) */
|
||||
GstClockTime dts; /* adjusted DTS (running time) */
|
||||
} queued;
|
||||
|
||||
/* Most recent valid TS (DTS or PTS) for this stream */
|
||||
GstClockTime last_ts;
|
||||
|
||||
GstBuffer * codec_data; /* Optional codec data available in the caps */
|
||||
|
||||
|
@ -110,10 +117,10 @@ GType mpegpsmux_get_type (void);
|
|||
#define CLOCK_BASE 9LL
|
||||
#define CLOCK_FREQ (CLOCK_BASE * 10000)
|
||||
|
||||
#define MPEGTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
|
||||
GST_MSECOND/10, CLOCK_BASE))
|
||||
#define GSTTIME_TO_MPEGTIME(time) (gst_util_uint64_scale ((time), \
|
||||
CLOCK_BASE, GST_MSECOND/10))
|
||||
#define GSTTIME_TO_MPEGTIME(time) \
|
||||
(GST_CLOCK_TIME_IS_VALID(time) ? \
|
||||
gst_util_uint64_scale ((time), CLOCK_BASE, GST_MSECOND/10) : \
|
||||
-1)
|
||||
|
||||
#define NORMAL_TS_PACKET_LENGTH 188
|
||||
#define M2TS_PACKET_LENGTH 192
|
||||
|
|
Loading…
Reference in a new issue