mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +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_LAST_TABLE_ID;
|
||||||
static GQuark QUARK_EVENTS;
|
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);
|
static void _init_local (void);
|
||||||
G_DEFINE_TYPE_EXTENDED (MpegTSPacketizer2, mpegts_packetizer, G_TYPE_OBJECT, 0,
|
G_DEFINE_TYPE_EXTENDED (MpegTSPacketizer2, mpegts_packetizer, G_TYPE_OBJECT, 0,
|
||||||
_init_local ());
|
_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_dispose (GObject * object);
|
||||||
static void mpegts_packetizer_finalize (GObject * object);
|
static void mpegts_packetizer_finalize (GObject * object);
|
||||||
static gchar *convert_to_utf8 (const gchar * text, gint length, guint start,
|
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 gchar *get_encoding_and_convert (const gchar * text, guint length);
|
||||||
static GstClockTime calculate_skew (MpegTSPacketizer2 * packetizer,
|
static GstClockTime calculate_skew (MpegTSPacketizer2 * packetizer,
|
||||||
guint64 pcrtime, GstClockTime time);
|
guint64 pcrtime, GstClockTime time);
|
||||||
|
static void record_pcr (MpegTSPacketizer2 * packetizer, guint64 pcr,
|
||||||
|
guint64 offset);
|
||||||
static void mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer);
|
static void mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer);
|
||||||
|
|
||||||
#define CONTINUITY_UNSET 255
|
#define CONTINUITY_UNSET 255
|
||||||
|
@ -156,6 +183,8 @@ mpegts_packetizer_class_init (MpegTSPacketizer2Class * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
|
|
||||||
|
g_type_class_add_private (klass, sizeof (MpegTSPacketizerPrivate));
|
||||||
|
|
||||||
gobject_class = G_OBJECT_CLASS (klass);
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
gobject_class->dispose = mpegts_packetizer_dispose;
|
gobject_class->dispose = mpegts_packetizer_dispose;
|
||||||
|
@ -165,13 +194,22 @@ mpegts_packetizer_class_init (MpegTSPacketizer2Class * klass)
|
||||||
static void
|
static void
|
||||||
mpegts_packetizer_init (MpegTSPacketizer2 * packetizer)
|
mpegts_packetizer_init (MpegTSPacketizer2 * packetizer)
|
||||||
{
|
{
|
||||||
|
packetizer->priv = MPEGTS_PACKETIZER_GET_PRIVATE (packetizer);
|
||||||
packetizer->adapter = gst_adapter_new ();
|
packetizer->adapter = gst_adapter_new ();
|
||||||
packetizer->offset = 0;
|
packetizer->offset = 0;
|
||||||
packetizer->empty = TRUE;
|
packetizer->empty = TRUE;
|
||||||
packetizer->streams = g_new0 (MpegTSPacketizerStream *, 8192);
|
packetizer->streams = g_new0 (MpegTSPacketizerStream *, 8192);
|
||||||
packetizer->know_packet_size = FALSE;
|
packetizer->know_packet_size = FALSE;
|
||||||
packetizer->calculate_skew = FALSE;
|
packetizer->calculate_skew = FALSE;
|
||||||
|
packetizer->calculate_offset = FALSE;
|
||||||
mpegts_packetizer_reset_skew (packetizer);
|
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
|
static void
|
||||||
|
@ -269,17 +307,24 @@ mpegts_packetizer_parse_adaptation_field_control (MpegTSPacketizer2 *
|
||||||
/* PCR */
|
/* PCR */
|
||||||
if (afcflags & MPEGTS_AFC_PCR_FLAG) {
|
if (afcflags & MPEGTS_AFC_PCR_FLAG) {
|
||||||
packet->pcr = mpegts_packetizer_compute_pcr (data);
|
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)
|
if (packetizer->calculate_skew)
|
||||||
GST_BUFFER_TIMESTAMP (packet->buffer) =
|
GST_BUFFER_TIMESTAMP (packet->buffer) =
|
||||||
calculate_skew (packetizer, packet->pcr,
|
calculate_skew (packetizer, packet->pcr,
|
||||||
GST_BUFFER_TIMESTAMP (packet->buffer));
|
GST_BUFFER_TIMESTAMP (packet->buffer));
|
||||||
*data += 6;
|
if (packetizer->calculate_offset)
|
||||||
|
record_pcr (packetizer, packet->pcr, packet->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OPCR */
|
/* OPCR */
|
||||||
if (afcflags & MPEGTS_AFC_OPCR_FLAG) {
|
if (afcflags & MPEGTS_AFC_OPCR_FLAG) {
|
||||||
packet->opcr = mpegts_packetizer_compute_pcr (data);
|
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;
|
return TRUE;
|
||||||
|
@ -2782,6 +2827,7 @@ failed:
|
||||||
static void
|
static void
|
||||||
mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer)
|
mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer)
|
||||||
{
|
{
|
||||||
|
/* FIXME : These variables should be *per* PCR PID */
|
||||||
packetizer->base_time = GST_CLOCK_TIME_NONE;
|
packetizer->base_time = GST_CLOCK_TIME_NONE;
|
||||||
packetizer->base_pcrtime = GST_CLOCK_TIME_NONE;
|
packetizer->base_pcrtime = GST_CLOCK_TIME_NONE;
|
||||||
packetizer->last_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,
|
mpegts_packetizer_resync (MpegTSPacketizer2 * packetizer, GstClockTime time,
|
||||||
GstClockTime gstpcrtime, gboolean reset_skew)
|
GstClockTime gstpcrtime, gboolean reset_skew)
|
||||||
{
|
{
|
||||||
|
/* FIXME : These variables should be *per* PCR PID */
|
||||||
packetizer->base_time = time;
|
packetizer->base_time = time;
|
||||||
packetizer->base_pcrtime = gstpcrtime;
|
packetizer->base_pcrtime = gstpcrtime;
|
||||||
packetizer->prev_out_time = GST_CLOCK_TIME_NONE;
|
packetizer->prev_out_time = GST_CLOCK_TIME_NONE;
|
||||||
|
@ -3082,3 +3129,109 @@ no_skew:
|
||||||
|
|
||||||
return out_time;
|
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 _MpegTSPacketizer2 MpegTSPacketizer2;
|
||||||
typedef struct _MpegTSPacketizer2Class MpegTSPacketizer2Class;
|
typedef struct _MpegTSPacketizer2Class MpegTSPacketizer2Class;
|
||||||
|
typedef struct _MpegTSPacketizerPrivate MpegTSPacketizerPrivate;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -74,6 +75,7 @@ struct _MpegTSPacketizer2 {
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
/* streams hashed by pid */
|
/* streams hashed by pid */
|
||||||
|
/* FIXME : be more memory efficient (see how it's done in mpegtsbase) */
|
||||||
MpegTSPacketizerStream **streams;
|
MpegTSPacketizerStream **streams;
|
||||||
gboolean disposed;
|
gboolean disposed;
|
||||||
gboolean know_packet_size;
|
gboolean know_packet_size;
|
||||||
|
@ -102,6 +104,11 @@ struct _MpegTSPacketizer2 {
|
||||||
gint64 window_min;
|
gint64 window_min;
|
||||||
gint64 skew;
|
gint64 skew;
|
||||||
gint64 prev_send_diff;
|
gint64 prev_send_diff;
|
||||||
|
|
||||||
|
/* offset/bitrate calculator */
|
||||||
|
gboolean calculate_offset;
|
||||||
|
|
||||||
|
MpegTSPacketizerPrivate *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MpegTSPacketizer2Class {
|
struct _MpegTSPacketizer2Class {
|
||||||
|
@ -187,8 +194,22 @@ GstStructure *mpegts_packetizer_parse_eit (MpegTSPacketizer2 *packetizer,
|
||||||
MpegTSPacketizerSection *section);
|
MpegTSPacketizerSection *section);
|
||||||
GstStructure *mpegts_packetizer_parse_tdt (MpegTSPacketizer2 *packetizer,
|
GstStructure *mpegts_packetizer_parse_tdt (MpegTSPacketizer2 *packetizer,
|
||||||
MpegTSPacketizerSection *section);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* GST_MPEGTS_PACKETIZER_H */
|
#endif /* GST_MPEGTS_PACKETIZER_H */
|
||||||
|
|
Loading…
Reference in a new issue