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:
Edward Hervey 2012-03-01 17:56:34 +01:00
parent 39cc29a7d2
commit a4899af8d6
2 changed files with 177 additions and 3 deletions

View file

@ -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;
}

View file

@ -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 */