mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
mpegtspacketizer: Offset calculation
Allows PCR<=>PTS<=>offset estimation/calculation Right now the calculation is very naive, but can be extended later on without disrupting the code in tsdemux/mpegtsbase
This commit is contained in:
parent
39cc29a7d2
commit
a4899af8d6
2 changed files with 177 additions and 3 deletions
|
@ -69,10 +69,35 @@ static GQuark QUARK_SEGMENT_LAST_SECTION_NUMBER;
|
|||
static GQuark QUARK_LAST_TABLE_ID;
|
||||
static GQuark QUARK_EVENTS;
|
||||
|
||||
|
||||
#define MPEGTS_PACKETIZER_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_MPEGTS_PACKETIZER, MpegTSPacketizerPrivate))
|
||||
|
||||
static void _init_local (void);
|
||||
G_DEFINE_TYPE_EXTENDED (MpegTSPacketizer2, mpegts_packetizer, G_TYPE_OBJECT, 0,
|
||||
_init_local ());
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint64 offset; /* offset in upstream */
|
||||
guint64 pcr; /* pcr (wraparound not fixed) */
|
||||
} MpegTSPacketizerOffset;
|
||||
|
||||
struct _MpegTSPacketizerPrivate
|
||||
{
|
||||
/* Used for bitrate calculation */
|
||||
/* FIXME : Replace this later on with a balanced tree or sequence */
|
||||
guint64 first_offset;
|
||||
guint64 first_pcr;
|
||||
guint64 last_offset;
|
||||
guint64 last_pcr;
|
||||
|
||||
/* Reference offset */
|
||||
guint64 refoffset;
|
||||
|
||||
guint nb_seen_offsets;
|
||||
};
|
||||
|
||||
static void mpegts_packetizer_dispose (GObject * object);
|
||||
static void mpegts_packetizer_finalize (GObject * object);
|
||||
static gchar *convert_to_utf8 (const gchar * text, gint length, guint start,
|
||||
|
@ -82,6 +107,8 @@ static gchar *get_encoding (const gchar * text, guint * start_text,
|
|||
static gchar *get_encoding_and_convert (const gchar * text, guint length);
|
||||
static GstClockTime calculate_skew (MpegTSPacketizer2 * packetizer,
|
||||
guint64 pcrtime, GstClockTime time);
|
||||
static void record_pcr (MpegTSPacketizer2 * packetizer, guint64 pcr,
|
||||
guint64 offset);
|
||||
static void mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer);
|
||||
|
||||
#define CONTINUITY_UNSET 255
|
||||
|
@ -156,6 +183,8 @@ mpegts_packetizer_class_init (MpegTSPacketizer2Class * klass)
|
|||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (MpegTSPacketizerPrivate));
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = mpegts_packetizer_dispose;
|
||||
|
@ -165,13 +194,22 @@ mpegts_packetizer_class_init (MpegTSPacketizer2Class * klass)
|
|||
static void
|
||||
mpegts_packetizer_init (MpegTSPacketizer2 * packetizer)
|
||||
{
|
||||
packetizer->priv = MPEGTS_PACKETIZER_GET_PRIVATE (packetizer);
|
||||
packetizer->adapter = gst_adapter_new ();
|
||||
packetizer->offset = 0;
|
||||
packetizer->empty = TRUE;
|
||||
packetizer->streams = g_new0 (MpegTSPacketizerStream *, 8192);
|
||||
packetizer->know_packet_size = FALSE;
|
||||
packetizer->calculate_skew = FALSE;
|
||||
packetizer->calculate_offset = FALSE;
|
||||
mpegts_packetizer_reset_skew (packetizer);
|
||||
|
||||
packetizer->priv->first_offset = -1;
|
||||
packetizer->priv->first_pcr = -1;
|
||||
packetizer->priv->last_offset = -1;
|
||||
packetizer->priv->last_pcr = -1;
|
||||
packetizer->priv->nb_seen_offsets = 0;
|
||||
packetizer->priv->refoffset = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -269,17 +307,24 @@ mpegts_packetizer_parse_adaptation_field_control (MpegTSPacketizer2 *
|
|||
/* PCR */
|
||||
if (afcflags & MPEGTS_AFC_PCR_FLAG) {
|
||||
packet->pcr = mpegts_packetizer_compute_pcr (data);
|
||||
*data += 6;
|
||||
GST_DEBUG ("pcr %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
|
||||
packet->pcr, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (packet->pcr)));
|
||||
|
||||
if (packetizer->calculate_skew)
|
||||
GST_BUFFER_TIMESTAMP (packet->buffer) =
|
||||
calculate_skew (packetizer, packet->pcr,
|
||||
GST_BUFFER_TIMESTAMP (packet->buffer));
|
||||
*data += 6;
|
||||
if (packetizer->calculate_offset)
|
||||
record_pcr (packetizer, packet->pcr, packet->offset);
|
||||
}
|
||||
|
||||
/* OPCR */
|
||||
if (afcflags & MPEGTS_AFC_OPCR_FLAG) {
|
||||
packet->opcr = mpegts_packetizer_compute_pcr (data);
|
||||
*data += 6;
|
||||
/* *data += 6; */
|
||||
GST_DEBUG ("opcr %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
|
||||
packet->pcr, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (packet->pcr)));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -2782,6 +2827,7 @@ failed:
|
|||
static void
|
||||
mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer)
|
||||
{
|
||||
/* FIXME : These variables should be *per* PCR PID */
|
||||
packetizer->base_time = GST_CLOCK_TIME_NONE;
|
||||
packetizer->base_pcrtime = GST_CLOCK_TIME_NONE;
|
||||
packetizer->last_pcrtime = GST_CLOCK_TIME_NONE;
|
||||
|
@ -2798,6 +2844,7 @@ static void
|
|||
mpegts_packetizer_resync (MpegTSPacketizer2 * packetizer, GstClockTime time,
|
||||
GstClockTime gstpcrtime, gboolean reset_skew)
|
||||
{
|
||||
/* FIXME : These variables should be *per* PCR PID */
|
||||
packetizer->base_time = time;
|
||||
packetizer->base_pcrtime = gstpcrtime;
|
||||
packetizer->prev_out_time = GST_CLOCK_TIME_NONE;
|
||||
|
@ -3082,3 +3129,109 @@ no_skew:
|
|||
|
||||
return out_time;
|
||||
}
|
||||
|
||||
static void
|
||||
record_pcr (MpegTSPacketizer2 * packetizer, guint64 pcr, guint64 offset)
|
||||
{
|
||||
MpegTSPacketizerPrivate *priv = packetizer->priv;
|
||||
|
||||
/* Check against first PCR */
|
||||
if (priv->first_pcr == -1 || priv->first_offset > offset) {
|
||||
GST_DEBUG ("Recording first value. PCR:%" G_GUINT64_FORMAT " offset:%"
|
||||
G_GUINT64_FORMAT, pcr, offset);
|
||||
priv->first_pcr = pcr;
|
||||
priv->first_offset = offset;
|
||||
priv->nb_seen_offsets++;
|
||||
} else
|
||||
/* If we didn't update the first PCR, let's check against last PCR */
|
||||
if (priv->last_pcr == -1 || priv->last_offset < offset) {
|
||||
GST_DEBUG ("Recording last value. PCR:%" G_GUINT64_FORMAT " offset:%"
|
||||
G_GUINT64_FORMAT, pcr, offset);
|
||||
priv->last_pcr = pcr;
|
||||
priv->last_offset = offset;
|
||||
priv->nb_seen_offsets++;
|
||||
}
|
||||
}
|
||||
|
||||
guint
|
||||
mpegts_packetizer_get_seen_pcr (MpegTSPacketizer2 * packetizer)
|
||||
{
|
||||
return packetizer->priv->nb_seen_offsets;
|
||||
}
|
||||
|
||||
GstClockTime
|
||||
mpegts_packetizer_offset_to_ts (MpegTSPacketizer2 * packetizer, guint64 offset)
|
||||
{
|
||||
MpegTSPacketizerPrivate *priv = packetizer->priv;
|
||||
GstClockTime res;
|
||||
|
||||
if (G_UNLIKELY (!packetizer->calculate_offset))
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
|
||||
if (G_UNLIKELY (priv->refoffset == -1))
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
|
||||
if (G_UNLIKELY (offset < priv->refoffset))
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
|
||||
/* Convert byte difference into time difference */
|
||||
res = PCRTIME_TO_GSTTIME (gst_util_uint64_scale (offset - priv->refoffset,
|
||||
priv->last_pcr - priv->first_pcr,
|
||||
priv->last_offset - priv->first_offset));
|
||||
GST_DEBUG ("Returning timestamp %" GST_TIME_FORMAT " for offset %"
|
||||
G_GUINT64_FORMAT, GST_TIME_ARGS (res), offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GstClockTime
|
||||
mpegts_packetizer_pts_to_ts (MpegTSPacketizer2 * packetizer, guint64 pts)
|
||||
{
|
||||
/* Use clock skew if present */
|
||||
if (packetizer->calculate_skew
|
||||
&& GST_CLOCK_TIME_IS_VALID (packetizer->base_time)) {
|
||||
GST_DEBUG ("pts %" G_GUINT64_FORMAT " base_pcrtime:%" G_GUINT64_FORMAT
|
||||
" base_time:%" GST_TIME_FORMAT, pts, packetizer->base_pcrtime,
|
||||
GST_TIME_ARGS (packetizer->base_time));
|
||||
return pts - packetizer->base_pcrtime + packetizer->base_time +
|
||||
packetizer->skew;
|
||||
}
|
||||
|
||||
/* If not, use pcr observations */
|
||||
if (packetizer->calculate_offset && packetizer->priv->first_pcr != -1)
|
||||
return pts - PCRTIME_TO_GSTTIME (packetizer->priv->first_pcr);
|
||||
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
guint64
|
||||
mpegts_packetizer_ts_to_offset (MpegTSPacketizer2 * packetizer, GstClockTime ts)
|
||||
{
|
||||
MpegTSPacketizerPrivate *priv = packetizer->priv;
|
||||
guint64 res;
|
||||
|
||||
if (!packetizer->calculate_offset || packetizer->priv->first_pcr == -1)
|
||||
return -1;
|
||||
|
||||
GST_DEBUG ("ts(pcr) %" G_GUINT64_FORMAT " first_pcr:%" G_GUINT64_FORMAT,
|
||||
GSTTIME_TO_MPEGTIME (ts), priv->first_pcr);
|
||||
|
||||
/* Convert ts to PCRTIME */
|
||||
res = gst_util_uint64_scale (GSTTIME_TO_PCRTIME (ts),
|
||||
priv->last_offset - priv->first_offset, priv->last_pcr - priv->first_pcr);
|
||||
res += priv->first_offset + priv->refoffset;
|
||||
|
||||
GST_DEBUG ("Returning offset %" G_GUINT64_FORMAT " for ts %" GST_TIME_FORMAT,
|
||||
res, GST_TIME_ARGS (ts));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_packetizer_set_reference_offset (MpegTSPacketizer2 * packetizer,
|
||||
guint64 refoffset)
|
||||
{
|
||||
GST_DEBUG ("Setting reference offset to %" G_GUINT64_FORMAT, refoffset);
|
||||
|
||||
packetizer->priv->refoffset = refoffset;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ G_BEGIN_DECLS
|
|||
|
||||
typedef struct _MpegTSPacketizer2 MpegTSPacketizer2;
|
||||
typedef struct _MpegTSPacketizer2Class MpegTSPacketizer2Class;
|
||||
typedef struct _MpegTSPacketizerPrivate MpegTSPacketizerPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -74,6 +75,7 @@ struct _MpegTSPacketizer2 {
|
|||
|
||||
GstAdapter *adapter;
|
||||
/* streams hashed by pid */
|
||||
/* FIXME : be more memory efficient (see how it's done in mpegtsbase) */
|
||||
MpegTSPacketizerStream **streams;
|
||||
gboolean disposed;
|
||||
gboolean know_packet_size;
|
||||
|
@ -102,6 +104,11 @@ struct _MpegTSPacketizer2 {
|
|||
gint64 window_min;
|
||||
gint64 skew;
|
||||
gint64 prev_send_diff;
|
||||
|
||||
/* offset/bitrate calculator */
|
||||
gboolean calculate_offset;
|
||||
|
||||
MpegTSPacketizerPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MpegTSPacketizer2Class {
|
||||
|
@ -187,8 +194,22 @@ GstStructure *mpegts_packetizer_parse_eit (MpegTSPacketizer2 *packetizer,
|
|||
MpegTSPacketizerSection *section);
|
||||
GstStructure *mpegts_packetizer_parse_tdt (MpegTSPacketizer2 *packetizer,
|
||||
MpegTSPacketizerSection *section);
|
||||
guint64 mpegts_packetizer_compute_pcr(const guint8 * data);
|
||||
|
||||
/* Only valid if calculate_offset is TRUE */
|
||||
guint mpegts_packetizer_get_seen_pcr (MpegTSPacketizer2 *packetizer);
|
||||
|
||||
GstClockTime
|
||||
mpegts_packetizer_offset_to_ts (MpegTSPacketizer2 * packetizer,
|
||||
guint64 offset);
|
||||
guint64
|
||||
mpegts_packetizer_ts_to_offset (MpegTSPacketizer2 * packetizer,
|
||||
GstClockTime ts);
|
||||
GstClockTime
|
||||
mpegts_packetizer_pts_to_ts (MpegTSPacketizer2 * packetizer,
|
||||
guint64 pcr);
|
||||
void
|
||||
mpegts_packetizer_set_reference_offset (MpegTSPacketizer2 * packetizer,
|
||||
guint64 refoffset);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GST_MPEGTS_PACKETIZER_H */
|
||||
|
|
Loading…
Reference in a new issue