blob: 4425d78551c43a0199694dd6e04461951ee731c7 [file] [log] [blame]
hanghang.luofa7b16f2024-05-31 14:44:31 +08001/*
2 * mpegtspacketizer.c -
3 * Copyright (C) 2007, 2008 Alessandro Decina, Zaheer Merali
4 *
5 * Authors:
6 * Zaheer Merali <zaheerabbas at merali dot org>
7 * Alessandro Decina <alessandro@nnva.org>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <string.h>
29#include <stdlib.h>
30
31/* Skew calculation pameters */
32#define MAX_TIME (2 * GST_SECOND)
33
34/* maximal PCR time */
35#define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298)
36#define PCR_GST_MAX_VALUE (PCR_MAX_VALUE * GST_MSECOND / (PCR_MSECOND))
37#define PTS_DTS_MAX_VALUE (((guint64)1) << 33)
38
39#include "amltspacketizer.h"
40#include "gstamldesc.h"
41
42GST_DEBUG_CATEGORY_STATIC (amlts_packetizer_debug);
43#define GST_CAT_DEFAULT amlts_packetizer_debug
44
bo.xiaoff2de692024-08-07 14:38:55 +080045static void _aml_init_local (void);
hanghang.luofa7b16f2024-05-31 14:44:31 +080046G_DEFINE_TYPE_EXTENDED (AmlTSPacketizer2, amlts_packetizer, G_TYPE_OBJECT, 0,
bo.xiaoff2de692024-08-07 14:38:55 +080047 _aml_init_local ());
hanghang.luofa7b16f2024-05-31 14:44:31 +080048
49#define ABSDIFF(a,b) ((a) < (b) ? (b) - (a) : (a) - (b))
50
51#define PACKETIZER_GROUP_LOCK(p) g_mutex_lock(&((p)->group_lock))
52#define PACKETIZER_GROUP_UNLOCK(p) g_mutex_unlock(&((p)->group_lock))
53
54static void amlts_packetizer_dispose (GObject * object);
55static void amlts_packetizer_finalize (GObject * object);
56static GstClockTime calculate_skew (AmlTSPacketizer2 * packetizer,
57 AmlTSPCR * pcr, guint64 pcrtime, GstClockTime time);
bo.xiaoff2de692024-08-07 14:38:55 +080058static void _aml_close_current_group (AmlTSPCR * pcrtable);
59static void aml_record_pcr (AmlTSPacketizer2 * packetizer, AmlTSPCR * pcrtable,
hanghang.luofa7b16f2024-05-31 14:44:31 +080060 guint64 pcr, guint64 offset);
61
62#define CONTINUITY_UNSET 255
63#define VERSION_NUMBER_UNSET 255
64#define TABLE_ID_UNSET 0xFF
65#define PACKET_SYNC_BYTE 0x47
66
67static inline AmlTSPCR *
bo.xiaoff2de692024-08-07 14:38:55 +080068aml_get_pcr_table (AmlTSPacketizer2 * packetizer, guint16 pid)
hanghang.luofa7b16f2024-05-31 14:44:31 +080069{
70 AmlTSPCR *res;
71
72 res = packetizer->observations[packetizer->pcrtablelut[pid]];
73
74 if (G_UNLIKELY (res == NULL)) {
75 /* If we don't have a PCR table for the requested PID, create one .. */
76 res = g_new0 (AmlTSPCR, 1);
77 /* Add it to the last table position */
78 packetizer->observations[packetizer->lastobsid] = res;
79 /* Update the pcrtablelut */
80 packetizer->pcrtablelut[pid] = packetizer->lastobsid;
81 /* And increment the last know slot */
82 packetizer->lastobsid++;
83
84 /* Finally set the default values */
85 res->pid = pid;
86 res->base_time = GST_CLOCK_TIME_NONE;
87 res->base_pcrtime = GST_CLOCK_TIME_NONE;
88 res->last_pcrtime = GST_CLOCK_TIME_NONE;
89 res->window_pos = 0;
90 res->window_filling = TRUE;
91 res->window_min = 0;
92 res->skew = 0;
93 res->prev_send_diff = GST_CLOCK_TIME_NONE;
94 res->prev_out_time = GST_CLOCK_TIME_NONE;
95 res->pcroffset = 0;
96
97 res->current = g_slice_new0 (PCROffsetCurrent);
98 }
99
100 return res;
101}
102
103static void
bo.xiaoff2de692024-08-07 14:38:55 +0800104aml_pcr_offset_group_free (PCROffsetGroup * group)
hanghang.luofa7b16f2024-05-31 14:44:31 +0800105{
106 g_free (group->values);
107 g_slice_free (PCROffsetGroup, group);
108}
109
110static void
bo.xiaoff2de692024-08-07 14:38:55 +0800111aml_flush_observations (AmlTSPacketizer2 * packetizer)
hanghang.luofa7b16f2024-05-31 14:44:31 +0800112{
113 gint i;
114
115 for (i = 0; i < packetizer->lastobsid; i++) {
116 g_list_free_full (packetizer->observations[i]->groups,
bo.xiaoff2de692024-08-07 14:38:55 +0800117 (GDestroyNotify) aml_pcr_offset_group_free);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800118 if (packetizer->observations[i]->current)
119 g_slice_free (PCROffsetCurrent, packetizer->observations[i]->current);
120 g_free (packetizer->observations[i]);
121 packetizer->observations[i] = NULL;
122 }
123 memset (packetizer->pcrtablelut, 0xff, 0x2000);
124 packetizer->lastobsid = 0;
125}
126
127GstClockTime
128amlts_packetizer_get_current_time (AmlTSPacketizer2 * packetizer,
129 guint16 pcr_pid)
130{
bo.xiaoff2de692024-08-07 14:38:55 +0800131 AmlTSPCR *pcrtable = aml_get_pcr_table (packetizer, pcr_pid);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800132
133 if (pcrtable == NULL)
134 return GST_CLOCK_TIME_NONE;
135
136 return amlts_packetizer_pts_to_ts (packetizer, pcrtable->last_pcrtime,
137 pcr_pid);
138}
139
140static inline AmlTSPacketizerStreamSubtable *
141find_subtable (GSList * subtables, guint8 table_id, guint16 subtable_extension)
142{
143 GSList *tmp;
144
145 /* FIXME: Make this an array ! */
146 for (tmp = subtables; tmp; tmp = tmp->next) {
147 AmlTSPacketizerStreamSubtable *sub =
148 (AmlTSPacketizerStreamSubtable *) tmp->data;
149 if (sub->table_id == table_id
150 && sub->subtable_extension == subtable_extension)
151 return sub;
152 }
153
154 return NULL;
155}
156
157static gboolean
158seen_section_before (AmlTSPacketizerStream * stream, guint8 table_id,
159 guint16 subtable_extension, guint8 version_number, guint8 section_number,
160 guint8 last_section_number)
161{
162 AmlTSPacketizerStreamSubtable *subtable;
163
164 /* Check if we've seen this table_id/subtable_extension first */
165 subtable = find_subtable (stream->subtables, table_id, subtable_extension);
166 if (!subtable) {
167 GST_DEBUG ("Haven't seen subtable");
168 return FALSE;
169 }
170 /* If we have, check it has the same version_number */
171 if (subtable->version_number != version_number) {
172 GST_DEBUG ("Different version number");
173 return FALSE;
174 }
175 /* Did the number of sections change ? */
176 if (subtable->last_section_number != last_section_number) {
177 GST_DEBUG ("Different last_section_number");
178 return FALSE;
179 }
180 /* Finally return whether we saw that section or not */
181 return MPEGTS_BIT_IS_SET (subtable->seen_section, section_number);
182}
183
184static AmlTSPacketizerStreamSubtable *
185amlts_packetizer_stream_subtable_new (guint8 table_id,
186 guint16 subtable_extension, guint8 last_section_number)
187{
188 AmlTSPacketizerStreamSubtable *subtable;
189
190 subtable = g_new0 (AmlTSPacketizerStreamSubtable, 1);
191 subtable->version_number = VERSION_NUMBER_UNSET;
192 subtable->table_id = table_id;
193 subtable->subtable_extension = subtable_extension;
194 subtable->last_section_number = last_section_number;
195 return subtable;
196}
197
198static AmlTSPacketizerStream *
199amlts_packetizer_stream_new (guint16 pid)
200{
201 AmlTSPacketizerStream *stream;
202
203 stream = (AmlTSPacketizerStream *) g_new0 (AmlTSPacketizerStream, 1);
204 stream->continuity_counter = CONTINUITY_UNSET;
205 stream->subtables = NULL;
206 stream->table_id = TABLE_ID_UNSET;
207 stream->pid = pid;
208 return stream;
209}
210
211static void
212amlts_packetizer_clear_section (AmlTSPacketizerStream * stream)
213{
214 stream->continuity_counter = CONTINUITY_UNSET;
215 stream->section_length = 0;
216 stream->section_offset = 0;
217 stream->table_id = TABLE_ID_UNSET;
218 g_free (stream->section_data);
219 stream->section_data = NULL;
220}
221
222static void
223amlts_packetizer_stream_subtable_free (AmlTSPacketizerStreamSubtable *
224 subtable)
225{
226 g_free (subtable);
227}
228
229static void
230amlts_packetizer_stream_free (AmlTSPacketizerStream * stream)
231{
232 amlts_packetizer_clear_section (stream);
233 g_slist_foreach (stream->subtables,
234 (GFunc) amlts_packetizer_stream_subtable_free, NULL);
235 g_slist_free (stream->subtables);
236 g_free (stream);
237}
238
239static void
240amlts_packetizer_class_init (AmlTSPacketizer2Class * klass)
241{
242 GObjectClass *gobject_class;
243
244 gobject_class = G_OBJECT_CLASS (klass);
245
246 gobject_class->dispose = amlts_packetizer_dispose;
247 gobject_class->finalize = amlts_packetizer_finalize;
248}
249
250static void
251amlts_packetizer_init (AmlTSPacketizer2 * packetizer)
252{
253 g_mutex_init (&packetizer->group_lock);
254
255 packetizer->adapter = gst_adapter_new ();
256 packetizer->offset = 0;
257 packetizer->empty = TRUE;
258 packetizer->streams = g_new0 (AmlTSPacketizerStream *, 8192);
259 packetizer->packet_size = 0;
260 packetizer->calculate_skew = FALSE;
261 packetizer->calculate_offset = FALSE;
262
263 packetizer->map_data = NULL;
264 packetizer->map_size = 0;
265 packetizer->map_offset = 0;
266 packetizer->need_sync = FALSE;
267
268 memset (packetizer->pcrtablelut, 0xff, 0x2000);
269 memset (packetizer->observations, 0x0, sizeof (packetizer->observations));
270 packetizer->lastobsid = 0;
271
272 packetizer->nb_seen_offsets = 0;
273 packetizer->refoffset = -1;
274 packetizer->last_in_time = GST_CLOCK_TIME_NONE;
275 packetizer->pcr_discont_threshold = GST_SECOND;
276 packetizer->last_pts = GST_CLOCK_TIME_NONE;
277 packetizer->last_dts = GST_CLOCK_TIME_NONE;
278 packetizer->extra_shift = 0;
279}
280
281static void
282amlts_packetizer_dispose (GObject * object)
283{
284 AmlTSPacketizer2 *packetizer = GST_AMLTS_PACKETIZER (object);
285
286 if (!packetizer->disposed) {
287 if (packetizer->packet_size)
288 packetizer->packet_size = 0;
289 if (packetizer->streams) {
290 int i;
291 for (i = 0; i < 8192; i++) {
292 if (packetizer->streams[i])
293 amlts_packetizer_stream_free (packetizer->streams[i]);
294 }
295 g_free (packetizer->streams);
296 }
297
298 gst_adapter_clear (packetizer->adapter);
299 g_object_unref (packetizer->adapter);
300 g_mutex_clear (&packetizer->group_lock);
301 packetizer->disposed = TRUE;
302 packetizer->offset = 0;
303 packetizer->empty = TRUE;
304
bo.xiaoff2de692024-08-07 14:38:55 +0800305 aml_flush_observations (packetizer);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800306 }
307
308 if (G_OBJECT_CLASS (amlts_packetizer_parent_class)->dispose)
309 G_OBJECT_CLASS (amlts_packetizer_parent_class)->dispose (object);
310}
311
312static void
313amlts_packetizer_finalize (GObject * object)
314{
315 if (G_OBJECT_CLASS (amlts_packetizer_parent_class)->finalize)
316 G_OBJECT_CLASS (amlts_packetizer_parent_class)->finalize (object);
317}
318
319static inline guint64
320amlts_packetizer_compute_pcr (const guint8 * data)
321{
322 guint32 pcr1;
323 guint16 pcr2;
324 guint64 pcr, pcr_ext;
325
326 pcr1 = GST_READ_UINT32_BE (data);
327 pcr2 = GST_READ_UINT16_BE (data + 4);
328 pcr = ((guint64) pcr1) << 1;
329 pcr |= (pcr2 & 0x8000) >> 15;
330 pcr_ext = (pcr2 & 0x01ff);
331 return pcr * 300 + pcr_ext % 300;
332}
333
334static gboolean
335amlts_packetizer_parse_adaptation_field_control (AmlTSPacketizer2 *
336 packetizer, AmlTSPacketizerPacket * packet)
337{
338 guint8 length, afcflags;
339 guint8 *data;
340
341 length = *packet->data++;
342
343 /* an adaptation field with length 0 is valid and
344 * can be used to insert a single stuffing byte */
345 if (!length) {
346 packet->afc_flags = 0;
347 return TRUE;
348 }
349
350 if ((packet->scram_afc_cc & 0x30) == 0x20) {
351 /* no payload, adaptation field of 183 bytes */
352 if (length > 183) {
353 GST_WARNING ("PID 0x%04x afc == 0x%02x and length %d > 183",
354 packet->pid, packet->scram_afc_cc & 0x30, length);
355 return FALSE;
356 }
357 if (length != 183) {
358 GST_WARNING ("PID 0x%04x afc == 0x%02x and length %d != 183",
359 packet->pid, packet->scram_afc_cc & 0x30, length);
360 GST_MEMDUMP ("Unknown payload", packet->data + length,
361 packet->data_end - packet->data - length);
362 }
363 } else if (length == 183) {
364 /* Note: According to the specification, the adaptation field length
365 * must be 183 if there is no payload data and < 183 if the packet
366 * contains an adaptation field and payload data.
367 * Some payloaders always set the flag for payload data, even if the
368 * adaptation field length is 183. This just means a zero length
369 * payload so we clear the payload flag here and continue.
370 */
371 GST_WARNING ("PID 0x%04x afc == 0x%02x and length %d == 183 (ignored)",
372 packet->pid, packet->scram_afc_cc & 0x30, length);
373 packet->scram_afc_cc &= ~0x10;
374 } else if (length > 182) {
375 GST_WARNING ("PID 0x%04x afc == 0x%02x and length %d > 182",
376 packet->pid, packet->scram_afc_cc & 0x30, length);
377 return FALSE;
378 }
379
380 if (packet->data + length > packet->data_end) {
381 GST_DEBUG
382 ("PID 0x%04x afc length %d overflows the buffer current %d max %d",
383 packet->pid, length, (gint) (packet->data - packet->data_start),
384 (gint) (packet->data_end - packet->data_start));
385 return FALSE;
386 }
387
388 data = packet->data;
389 packet->data += length;
390
391 afcflags = packet->afc_flags = *data++;
392
393 GST_DEBUG ("flags: %s%s%s%s%s%s%s%s%s",
394 afcflags & 0x80 ? "discontinuity " : "",
395 afcflags & 0x40 ? "random_access " : "",
396 afcflags & 0x20 ? "elementary_stream_priority " : "",
397 afcflags & 0x10 ? "PCR " : "",
398 afcflags & 0x08 ? "OPCR " : "",
399 afcflags & 0x04 ? "splicing_point " : "",
400 afcflags & 0x02 ? "transport_private_data " : "",
401 afcflags & 0x01 ? "extension " : "", afcflags == 0x00 ? "<none>" : "");
402
403 /* PCR */
404 if (afcflags & MPEGTS_AFC_PCR_FLAG) {
405 AmlTSPCR *pcrtable = NULL;
406 packet->pcr = amlts_packetizer_compute_pcr (data);
407 data += 6;
408 GST_DEBUG ("pcr 0x%04x %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT
409 ") offset:%" G_GUINT64_FORMAT, packet->pid, packet->pcr,
410 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (packet->pcr)), packet->offset);
411
412 PACKETIZER_GROUP_LOCK (packetizer);
413 if (packetizer->calculate_skew
414 && GST_CLOCK_TIME_IS_VALID (packetizer->last_in_time)) {
bo.xiaoff2de692024-08-07 14:38:55 +0800415 pcrtable = aml_get_pcr_table (packetizer, packet->pid);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800416 calculate_skew (packetizer, pcrtable, packet->pcr,
417 packetizer->last_in_time);
418 }
419 if (packetizer->calculate_offset) {
420 if (!pcrtable)
bo.xiaoff2de692024-08-07 14:38:55 +0800421 pcrtable = aml_get_pcr_table (packetizer, packet->pid);
422 aml_record_pcr (packetizer, pcrtable, packet->pcr, packet->offset);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800423 }
424 PACKETIZER_GROUP_UNLOCK (packetizer);
425 }
426#ifndef GST_DISABLE_GST_DEBUG
427 /* OPCR */
428 if (afcflags & MPEGTS_AFC_OPCR_FLAG) {
429 /* Note: We don't use/need opcr for the time being */
430 guint64 opcr = amlts_packetizer_compute_pcr (data);
431 data += 6;
432 GST_DEBUG ("opcr %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
433 opcr, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (opcr)));
434 }
435
436 if (afcflags & MPEGTS_AFC_SPLICING_POINT_FLAG) {
437 GST_DEBUG ("splice_countdown: %u", *data++);
438 }
439
440 if (afcflags & MPEGTS_AFC_TRANSPORT_PRIVATE_DATA_FLAG) {
441 guint8 len = *data++;
442 GST_MEMDUMP ("private data", data, len);
443 data += len;
444 }
445
446 if (afcflags & MPEGTS_AFC_EXTENSION_FLAG) {
447 guint8 extlen = *data++;
448 guint8 flags = *data++;
449 GST_DEBUG ("extension size:%d flags : %s%s%s", extlen,
450 flags & 0x80 ? "ltw " : "",
451 flags & 0x40 ? "piecewise_rate " : "",
452 flags & 0x20 ? "seamless_splice " : "");
453 if (flags & 0x80) {
454 GST_DEBUG ("legal time window: valid_flag:%d offset:%d", *data >> 7,
455 GST_READ_UINT16_BE (data) & 0x7fff);
456 data += 2;
457 }
458 }
459#endif
460
461 return TRUE;
462}
463
464static AmlTSPacketizerPacketReturn
465amlts_packetizer_parse_packet (AmlTSPacketizer2 * packetizer,
466 AmlTSPacketizerPacket * packet)
467{
468 guint8 *data;
469 guint8 tmp;
470
471 data = packet->data_start;
472 data += 1;
473 tmp = *data;
474
475 /* transport_error_indicator 1 */
476 if (G_UNLIKELY (tmp & 0x80))
477 return PACKET_BAD;
478
479 /* payload_unit_start_indicator 1 */
480 packet->payload_unit_start_indicator = tmp & 0x40;
481
482 /* transport_priority 1 */
483 /* PID 13 */
484 packet->pid = GST_READ_UINT16_BE (data) & 0x1FFF;
485 data += 2;
486
487 packet->scram_afc_cc = tmp = *data++;
488 /* transport_scrambling_control 2 */
489 if (G_UNLIKELY (tmp & 0xc0))
490 return PACKET_BAD;
491
492 packet->data = data;
493
494 packet->afc_flags = 0;
495 packet->pcr = G_MAXUINT64;
496
497 if (FLAGS_HAS_AFC (tmp)) {
498 if (!amlts_packetizer_parse_adaptation_field_control (packetizer, packet))
499 return FALSE;
500 }
501
502 if (FLAGS_HAS_PAYLOAD (packet->scram_afc_cc))
503 packet->payload = packet->data;
504 else
505 packet->payload = NULL;
506
507 return PACKET_OK;
508}
509
510static GstMpegtsSection *
511amlts_packetizer_parse_section_header (AmlTSPacketizer2 * packetizer,
512 AmlTSPacketizerStream * stream)
513{
514 AmlTSPacketizerStreamSubtable *subtable;
515 GstMpegtsSection *res;
516
517 subtable =
518 find_subtable (stream->subtables, stream->table_id,
519 stream->subtable_extension);
520 if (subtable) {
521 GST_DEBUG ("Found previous subtable_extension:0x%04x",
522 stream->subtable_extension);
523 if (G_UNLIKELY (stream->version_number != subtable->version_number)) {
524 /* If the version number changed, reset the subtable */
525 subtable->version_number = stream->version_number;
526 subtable->last_section_number = stream->last_section_number;
527 memset (subtable->seen_section, 0, 32);
528 }
529 } else {
530 GST_DEBUG ("Appending new subtable_extension: 0x%04x",
531 stream->subtable_extension);
532 subtable = amlts_packetizer_stream_subtable_new (stream->table_id,
533 stream->subtable_extension, stream->last_section_number);
534 subtable->version_number = stream->version_number;
535
536 stream->subtables = g_slist_prepend (stream->subtables, subtable);
537 }
538
539 GST_MEMDUMP ("Full section data", stream->section_data,
540 stream->section_length);
541 /* TODO ? : Replace this by an efficient version (where we provide all
542 * pre-parsed header data) */
543 res =
544 gst_mpegts_section_new (stream->pid, stream->section_data,
545 stream->section_length);
546 stream->section_data = NULL;
547 amlts_packetizer_clear_section (stream);
548
549 if (res) {
550 /* NOTE : Due to the new mpegts-si system, There is a insanely low probability
551 * that we might have gotten a section that was corrupted (i.e. wrong crc)
552 * and that we consider it as seen.
553 *
554 * The reason why we consider this as acceptable is because all the previous
555 * checks were already done:
556 * * transport layer checks (DVB)
557 * * 0x47 validation
558 * * continuity counter validation
559 * * subtable validation
560 * * section_number validation
561 * * section_length validation
562 *
563 * The probability of this happening vs the overhead of doing CRC checks
564 * on all sections (including those we would not use) is just not worth it.
565 * */
566 MPEGTS_BIT_SET (subtable->seen_section, stream->section_number);
567 res->offset = stream->offset;
568 }
569
570 return res;
571}
572
573void
574amlts_packetizer_clear (AmlTSPacketizer2 * packetizer)
575{
576 guint i;
577 AmlTSPCR *pcrtable;
578
579 packetizer->packet_size = 0;
580
581 if (packetizer->streams) {
582 int i;
583 for (i = 0; i < 8192; i++) {
584 if (packetizer->streams[i]) {
585 amlts_packetizer_stream_free (packetizer->streams[i]);
586 }
587 }
588 memset (packetizer->streams, 0, 8192 * sizeof (AmlTSPacketizerStream *));
589 }
590
591 gst_adapter_clear (packetizer->adapter);
592 packetizer->offset = 0;
593 packetizer->empty = TRUE;
594 packetizer->need_sync = FALSE;
595 packetizer->map_data = NULL;
596 packetizer->map_size = 0;
597 packetizer->map_offset = 0;
598 packetizer->last_in_time = GST_CLOCK_TIME_NONE;
599 packetizer->last_pts = GST_CLOCK_TIME_NONE;
600 packetizer->last_dts = GST_CLOCK_TIME_NONE;
601
602 pcrtable = packetizer->observations[packetizer->pcrtablelut[0x1fff]];
603 if (pcrtable)
604 pcrtable->base_time = GST_CLOCK_TIME_NONE;
605
606 /* Close current PCR group */
607 PACKETIZER_GROUP_LOCK (packetizer);
608
609 for (i = 0; i < MAX_PCR_OBS_CHANNELS; i++) {
610 if (packetizer->observations[i])
bo.xiaoff2de692024-08-07 14:38:55 +0800611 _aml_close_current_group (packetizer->observations[i]);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800612 else
613 break;
614 }
615 PACKETIZER_GROUP_UNLOCK (packetizer);
616}
617
618void
619amlts_packetizer_flush (AmlTSPacketizer2 * packetizer, gboolean hard)
620{
621 guint i;
622 AmlTSPCR *pcrtable;
623 GST_DEBUG ("Flushing");
624
625 if (packetizer->streams) {
626 for (i = 0; i < 8192; i++) {
627 if (packetizer->streams[i]) {
628 amlts_packetizer_clear_section (packetizer->streams[i]);
629 }
630 }
631 }
632 gst_adapter_clear (packetizer->adapter);
633
634 packetizer->offset = 0;
635 packetizer->empty = TRUE;
636 packetizer->need_sync = FALSE;
637 packetizer->map_data = NULL;
638 packetizer->map_size = 0;
639 packetizer->map_offset = 0;
640 packetizer->last_in_time = GST_CLOCK_TIME_NONE;
641 packetizer->last_pts = GST_CLOCK_TIME_NONE;
642 packetizer->last_dts = GST_CLOCK_TIME_NONE;
643
644 pcrtable = packetizer->observations[packetizer->pcrtablelut[0x1fff]];
645 if (pcrtable)
646 pcrtable->base_time = GST_CLOCK_TIME_NONE;
647
648 /* Close current PCR group */
649 PACKETIZER_GROUP_LOCK (packetizer);
650 for (i = 0; i < MAX_PCR_OBS_CHANNELS; i++) {
651 if (packetizer->observations[i])
bo.xiaoff2de692024-08-07 14:38:55 +0800652 _aml_close_current_group (packetizer->observations[i]);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800653 else
654 break;
655 }
656 PACKETIZER_GROUP_UNLOCK (packetizer);
657
658 if (hard) {
659 /* For pull mode seeks in tsdemux the observation must be preserved */
bo.xiaoff2de692024-08-07 14:38:55 +0800660 aml_flush_observations (packetizer);
hanghang.luofa7b16f2024-05-31 14:44:31 +0800661 }
662}
663
664void
665amlts_packetizer_remove_stream (AmlTSPacketizer2 * packetizer, gint16 pid)
666{
667 AmlTSPacketizerStream *stream = packetizer->streams[pid];
668 if (stream) {
669 GST_INFO ("Removing stream for PID 0x%04x", pid);
670 amlts_packetizer_stream_free (stream);
671 packetizer->streams[pid] = NULL;
672 }
673}
674
675AmlTSPacketizer2 *
676amlts_packetizer_new (void)
677{
678 AmlTSPacketizer2 *packetizer;
679
680 packetizer =
681 GST_AMLTS_PACKETIZER (g_object_new (GST_TYPE_AMLTS_PACKETIZER, NULL));
682
683 return packetizer;
684}
685
686void
687amlts_packetizer_push (AmlTSPacketizer2 * packetizer, GstBuffer * buffer)
688{
689 GstClockTime ts;
690 if (G_UNLIKELY (packetizer->empty)) {
691 packetizer->empty = FALSE;
692 packetizer->offset = GST_BUFFER_OFFSET (buffer);
693 }
694
695 GST_DEBUG ("Pushing %" G_GSIZE_FORMAT " byte from offset %"
696 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
697 GST_BUFFER_OFFSET (buffer));
698 gst_adapter_push (packetizer->adapter, buffer);
699 /* If the buffer has a valid timestamp, store it - preferring DTS,
700 * which is where upstream arrival times should be stored */
701 ts = GST_BUFFER_DTS_OR_PTS (buffer);
702 if (GST_CLOCK_TIME_IS_VALID (ts))
703 packetizer->last_in_time = ts;
704 packetizer->last_pts = GST_BUFFER_PTS (buffer);
705 packetizer->last_dts = GST_BUFFER_DTS (buffer);
706}
707
708static void
709amlts_packetizer_flush_bytes (AmlTSPacketizer2 * packetizer, gsize size)
710{
711 if (size > 0) {
712 GST_LOG ("flushing %" G_GSIZE_FORMAT " bytes from adapter", size);
713 gst_adapter_flush (packetizer->adapter, size);
714 }
715
716 packetizer->map_data = NULL;
717 packetizer->map_size = 0;
718 packetizer->map_offset = 0;
719}
720
721static gboolean
722amlts_packetizer_map (AmlTSPacketizer2 * packetizer, gsize size)
723{
724 gsize available;
725
726 if (packetizer->map_size - packetizer->map_offset >= size)
727 return TRUE;
728
729 amlts_packetizer_flush_bytes (packetizer, packetizer->map_offset);
730
731 available = gst_adapter_available (packetizer->adapter);
732 if (available < size)
733 return FALSE;
734
735 packetizer->map_data =
736 (guint8 *) gst_adapter_map (packetizer->adapter, available);
737 if (!packetizer->map_data)
738 return FALSE;
739
740 packetizer->map_size = available;
741 packetizer->map_offset = 0;
742
743 GST_LOG ("mapped %" G_GSIZE_FORMAT " bytes from adapter", available);
744
745 return TRUE;
746}
747
748static gboolean
749amlts_try_discover_packet_size (AmlTSPacketizer2 * packetizer)
750{
751 guint8 *data;
752 gsize size, i, j;
753
754 static const guint psizes[] = {
755 MPEGTS_NORMAL_PACKETSIZE,
756 MPEGTS_M2TS_PACKETSIZE,
757 MPEGTS_DVB_ASI_PACKETSIZE,
758 MPEGTS_ATSC_PACKETSIZE
759 };
760
761 if (!amlts_packetizer_map (packetizer, 4 * MPEGTS_MAX_PACKETSIZE))
762 return FALSE;
763
764 size = packetizer->map_size - packetizer->map_offset;
765 data = packetizer->map_data + packetizer->map_offset;
766
767 for (i = 0; i + 3 * MPEGTS_MAX_PACKETSIZE < size; i++) {
768 /* find a sync byte */
769 if (data[i] != PACKET_SYNC_BYTE)
770 continue;
771
772 /* check for 4 consecutive sync bytes with each possible packet size */
773 for (j = 0; j < G_N_ELEMENTS (psizes); j++) {
774 guint packet_size = psizes[j];
775
776 if (data[i + packet_size] == PACKET_SYNC_BYTE &&
777 data[i + 2 * packet_size] == PACKET_SYNC_BYTE &&
778 data[i + 3 * packet_size] == PACKET_SYNC_BYTE) {
779 packetizer->packet_size = packet_size;
780 goto out;
781 }
782 }
783 }
784
785out:
786 packetizer->map_offset += i;
787
788 if (packetizer->packet_size == 0) {
789 GST_DEBUG ("Could not determine packet size in %" G_GSIZE_FORMAT
790 " bytes buffer, flush %" G_GSIZE_FORMAT " bytes", size, i);
791 amlts_packetizer_flush_bytes (packetizer, packetizer->map_offset);
792 return FALSE;
793 }
794
795 GST_INFO ("have packetsize detected: %u bytes", packetizer->packet_size);
796
797 if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE &&
798 packetizer->map_offset >= 4)
799 packetizer->map_offset -= 4;
800
801 return TRUE;
802}
803
804static gboolean
805amlts_packetizer_sync (AmlTSPacketizer2 * packetizer)
806{
807 gboolean found = FALSE;
808 guint8 *data;
809 guint packet_size;
810 gsize size, sync_offset, i;
811
812 packet_size = packetizer->packet_size;
813
814 if (!amlts_packetizer_map (packetizer, 3 * packet_size))
815 return FALSE;
816
817 size = packetizer->map_size - packetizer->map_offset;
818 data = packetizer->map_data + packetizer->map_offset;
819
820 if (packet_size == MPEGTS_M2TS_PACKETSIZE)
821 sync_offset = 4;
822 else
823 sync_offset = 0;
824
825 for (i = sync_offset; i + 2 * packet_size < size; i++) {
826 if (data[i] == PACKET_SYNC_BYTE &&
827 data[i + packet_size] == PACKET_SYNC_BYTE &&
828 data[i + 2 * packet_size] == PACKET_SYNC_BYTE) {
829 found = TRUE;
830 break;
831 }
832 }
833
834 packetizer->map_offset += i - sync_offset;
835
836 if (!found)
837 amlts_packetizer_flush_bytes (packetizer, packetizer->map_offset);
838
839 return found;
840}
841
842AmlTSPacketizerPacketReturn
843amlts_packetizer_next_packet (AmlTSPacketizer2 * packetizer,
844 AmlTSPacketizerPacket * packet)
845{
846 guint8 *packet_data;
847 guint packet_size;
848 gsize sync_offset;
849
850 packet_size = packetizer->packet_size;
kaiqiang.xiang83f60162024-08-05 16:43:08 +0800851 if (G_UNLIKELY(packet->protection_info)) {
852 gst_structure_free(packet->protection_info);
853 packet->protection_info = NULL;
854 }
hanghang.luofa7b16f2024-05-31 14:44:31 +0800855 if (G_UNLIKELY (!packet_size)) {
856 if (!amlts_try_discover_packet_size (packetizer))
857 return PACKET_NEED_MORE;
858 packet_size = packetizer->packet_size;
859 }
860
861 /* M2TS packets don't start with the sync byte, all other variants do */
862 if (packet_size == MPEGTS_M2TS_PACKETSIZE)
863 sync_offset = 4;
864 else
865 sync_offset = 0;
866
867 while (1) {
868 if (packetizer->need_sync) {
869 if (!amlts_packetizer_sync (packetizer))
870 return PACKET_NEED_MORE;
871 packetizer->need_sync = FALSE;
872 }
873
874 if (!amlts_packetizer_map (packetizer, packet_size))
875 return PACKET_NEED_MORE;
876
877 packet_data = &packetizer->map_data[packetizer->map_offset + sync_offset];
878
879 /* Check sync byte */
880 if (G_UNLIKELY (*packet_data != PACKET_SYNC_BYTE)) {
881 GST_DEBUG ("lost sync");
882 packetizer->need_sync = TRUE;
883 } else {
884 /* ALL mpeg-ts variants contain 188 bytes of data. Those with bigger
885 * packet sizes contain either extra data (timesync, FEC, ..) either
886 * before or after the data */
887 packet->data_start = packet_data;
888 packet->data_end = packet->data_start + 188;
889 packet->offset = packetizer->offset;
890 GST_LOG ("offset %" G_GUINT64_FORMAT, packet->offset);
891 packetizer->offset += packet_size;
892 GST_MEMDUMP ("data_start", packet->data_start, 16);
893
kaiqiang.xiang83f60162024-08-05 16:43:08 +0800894 GstBufferList *list = gst_adapter_get_buffer_list(packetizer->adapter, gst_adapter_available (packetizer->adapter));
895 GstBuffer *buffer = gst_buffer_list_get(list, 0);
896 GstProtectionMeta *meta = gst_buffer_get_protection_meta(buffer);
897 if (meta) {
898 packet->protection_info = gst_structure_copy(meta->info);
899 }
900 gst_buffer_list_unref(list);
901
hanghang.luofa7b16f2024-05-31 14:44:31 +0800902 return amlts_packetizer_parse_packet (packetizer, packet);
903 }
904 }
905}
906
907AmlTSPacketizerPacketReturn
908amlts_packetizer_process_next_packet (AmlTSPacketizer2 * packetizer)
909{
910 AmlTSPacketizerPacket packet;
911 AmlTSPacketizerPacketReturn ret;
912
kaiqiang.xiang83f60162024-08-05 16:43:08 +0800913 memset(&packet, 0, sizeof(AmlTSPacketizerPacket));
bo.xiaoff2de692024-08-07 14:38:55 +0800914
hanghang.luofa7b16f2024-05-31 14:44:31 +0800915 ret = amlts_packetizer_next_packet (packetizer, &packet);
916 if (ret != PACKET_NEED_MORE)
917 amlts_packetizer_clear_packet (packetizer, &packet);
918
919 return ret;
920}
921
922void
923amlts_packetizer_clear_packet (AmlTSPacketizer2 * packetizer,
924 AmlTSPacketizerPacket * packet)
925{
926 guint8 packet_size = packetizer->packet_size;
927
928 if (packetizer->map_data) {
929 packetizer->map_offset += packet_size;
930 if (packetizer->map_size - packetizer->map_offset < packet_size)
931 amlts_packetizer_flush_bytes (packetizer, packetizer->map_offset);
932 }
kaiqiang.xiang83f60162024-08-05 16:43:08 +0800933 if (G_LIKELY(packet->protection_info)) {
934 gst_structure_free(packet->protection_info);
935 packet->protection_info = NULL;
936 }
hanghang.luofa7b16f2024-05-31 14:44:31 +0800937}
938
939gboolean
940amlts_packetizer_has_packets (AmlTSPacketizer2 * packetizer)
941{
942 if (G_UNLIKELY (!packetizer->packet_size)) {
943 if (!amlts_try_discover_packet_size (packetizer))
944 return FALSE;
945 }
946 return gst_adapter_available (packetizer->adapter) >= packetizer->packet_size;
947}
948
949/*
950 * Ideally it should just return a section if:
951 * * The section is complete
952 * * The section is valid (sanity checks for length for example)
953 * * The section applies now (current_next_indicator)
954 * * The section is an update or was never seen
955 *
956 * The section should be a new GstMpegtsSection:
957 * * properly initialized
958 * * With pid, table_id AND section_type set (move logic from mpegtsbase)
959 * * With data copied into it (yes, minor overhead)
960 *
961 * In all other cases it should just return NULL
962 *
963 * If more than one section is available, the 'remaining' field will
964 * be set to the beginning of a valid GList containing other sections.
965 * */
966GstMpegtsSection *
967amlts_packetizer_push_section (AmlTSPacketizer2 * packetizer,
968 AmlTSPacketizerPacket * packet, GList ** remaining)
969{
970 GstMpegtsSection *section;
971 GstMpegtsSection *res = NULL;
972 AmlTSPacketizerStream *stream;
973 gboolean long_packet;
974 guint8 pointer = 0, table_id;
975 guint16 subtable_extension;
976 gsize to_read;
977 guint section_length;
978 /* data points to the current read location
979 * data_start points to the beginning of the data to accumulate */
980 guint8 *data, *data_start;
981 guint8 packet_cc;
982 GList *others = NULL;
983 guint8 version_number, section_number, last_section_number;
984 gboolean cc_discont = FALSE;
985
986 data = packet->data;
987 packet_cc = FLAGS_CONTINUITY_COUNTER (packet->scram_afc_cc);
988
989 /* Get our filter */
990 stream = packetizer->streams[packet->pid];
991 if (G_UNLIKELY (stream == NULL)) {
992 if (!packet->payload_unit_start_indicator) {
993 /* Early exit (we need to start with a section start) */
994 GST_DEBUG ("PID 0x%04x waiting for section start", packet->pid);
995 goto out;
996 }
997 stream = amlts_packetizer_stream_new (packet->pid);
998 packetizer->streams[packet->pid] = stream;
999 }
1000
1001 GST_MEMDUMP ("Full packet data", packet->data,
1002 packet->data_end - packet->data);
1003
1004 /* This function is split into several parts:
1005 *
1006 * Pre checks (packet-wide). Determines where we go next
1007 * accumulate_data: store data and check if section is complete
1008 * section_start: handle beginning of a section, if needed loop back to
1009 * accumulate_data
1010 *
1011 * The trigger that makes the loop stop and return is if:
1012 * 1) We do not have enough data for the current packet
1013 * 2) There is remaining data after a packet which is only made
1014 * of stuffing bytes (0xff).
1015 *
1016 * Pre-loop checks, related to the whole incoming packet:
1017 *
1018 * If there is a CC-discont:
1019 * If it is a PUSI, skip the pointer and handle section_start
1020 * If not a PUSI, reset and return nothing
1021 * If there is not a CC-discont:
1022 * If it is a PUSI
1023 * If pointer, accumulate that data and check for complete section
1024 * (loop)
1025 * If it is not a PUSI
1026 * Accumulate the expected data and check for complete section
1027 * (loop)
1028 *
1029 **/
1030
1031 if (packet->payload_unit_start_indicator)
1032 pointer = *data++;
1033
1034 if (stream->continuity_counter == CONTINUITY_UNSET ||
1035 (stream->continuity_counter + 1) % 16 != packet_cc) {
1036 if (stream->continuity_counter != CONTINUITY_UNSET) {
1037 GST_WARNING ("PID 0x%04x section discontinuity (%d vs %d)", packet->pid,
1038 stream->continuity_counter, packet_cc);
1039 cc_discont = TRUE;
1040 }
1041 amlts_packetizer_clear_section (stream);
1042 stream->continuity_counter = packet_cc;
1043 /* If not a PUSI, not much we can do */
1044 if (!packet->payload_unit_start_indicator) {
1045 GST_LOG ("PID 0x%04x continuity discont/unset and not PUSI, bailing out",
1046 packet->pid);
1047 goto out;
1048 }
1049 /* If PUSI, skip pointer data and carry on to section start */
1050 data += pointer;
1051 pointer = 0;
1052 GST_LOG ("discont, but PUSI, skipped %d bytes and doing section start",
1053 pointer);
1054 goto section_start;
1055 }
1056
1057 if (packet->payload_unit_start_indicator && pointer == 0) {
1058 /* If the pointer is zero, we're guaranteed to be able to handle it */
1059 GST_LOG
1060 ("PID 0x%04x PUSI and pointer == 0, skipping straight to section_start parsing",
1061 packet->pid);
1062 amlts_packetizer_clear_section (stream);
1063 stream->continuity_counter = packet_cc;
1064 goto section_start;
1065 }
1066
1067 stream->continuity_counter = packet_cc;
1068
1069
1070 GST_LOG ("Accumulating data from beginning of packet");
1071
1072 data_start = data;
1073
1074accumulate_data:
1075 /* If not the beginning of a new section, accumulate what we have */
1076 stream->continuity_counter = packet_cc;
1077 to_read = MIN (stream->section_length - stream->section_offset,
1078 packet->data_end - data_start);
1079 memcpy (stream->section_data + stream->section_offset, data_start, to_read);
1080 stream->section_offset += to_read;
1081 /* Point data to after the data we accumulated */
1082 data = data_start + to_read;
1083 GST_DEBUG ("Appending data (need %d, have %d)", stream->section_length,
1084 stream->section_offset);
1085
1086 /* Check if we have enough */
1087 if (stream->section_offset < stream->section_length) {
1088 GST_DEBUG ("PID 0x%04x, section not complete (Got %d, need %d)",
1089 stream->pid, stream->section_offset, stream->section_length);
1090 goto out;
1091 }
1092
1093 /* Small sanity check. We should have collected *exactly* the right amount */
1094 if (G_UNLIKELY (stream->section_offset != stream->section_length))
1095 GST_WARNING ("PID 0x%04x Accumulated too much data (%d vs %d) !",
1096 stream->pid, stream->section_offset, stream->section_length);
1097 GST_DEBUG ("PID 0x%04x Section complete", stream->pid);
1098
1099 if ((section = amlts_packetizer_parse_section_header (packetizer, stream))) {
1100 if (res)
1101 others = g_list_append (others, section);
1102 else
1103 res = section;
1104 }
1105
1106section_start:
1107 subtable_extension = 0;
1108 version_number = 0;
1109 last_section_number = 0;
1110 section_number = 0;
1111 table_id = 0;
1112
1113 /* FIXME : We need at least 3 bytes (or 8 for long packets) with current algorithm :(
1114 * We might end up losing sections that start across two packets (srsl...) */
1115 if (data > packet->data_end - 3 || *data == 0xff) {
1116 /* flush stuffing bytes and leave */
1117 amlts_packetizer_clear_section (stream);
1118 goto out;
1119 }
1120
1121 /* We have more data to process ... */
1122 GST_DEBUG ("PID 0x%04x, More section present in packet (remaining bytes:%"
1123 G_GSIZE_FORMAT ")", stream->pid, (gsize) (packet->data_end - data));
1124 GST_MEMDUMP ("section_start", data, packet->data_end - data);
1125 data_start = data;
1126 /* Beginning of a new section */
1127 /*
1128 * section_syntax_indicator means that the header is of the following format:
1129 * * table_id (8bit)
1130 * * section_syntax_indicator (1bit) == 0
1131 * * reserved/private fields (3bit)
1132 * * section_length (12bit)
1133 * * data (of size section_length)
1134 * * NO CRC !
1135 */
1136 long_packet = data[1] & 0x80;
1137
1138 /* Fast path for short packets */
1139 if (!long_packet) {
1140 /* We can create the section now (function will check for size) */
1141 GST_DEBUG ("Short packet");
1142 section_length = (GST_READ_UINT16_BE (data + 1) & 0xfff) + 3;
1143 /* Only do fast-path if we have enough byte */
1144 if (data + section_length <= packet->data_end) {
1145 if ((section =
bo.xiaoff2de692024-08-07 14:38:55 +08001146 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 20))
1147 gst_mpegts_section_new (packet->pid, g_memdup2 (data,
1148 #else
hanghang.luofa7b16f2024-05-31 14:44:31 +08001149 gst_mpegts_section_new (packet->pid, g_memdup (data,
bo.xiaoff2de692024-08-07 14:38:55 +08001150 #endif
hanghang.luofa7b16f2024-05-31 14:44:31 +08001151 section_length), section_length))) {
1152 GST_DEBUG ("PID 0x%04x Short section complete !", packet->pid);
1153 section->offset = packet->offset;
1154 if (res)
1155 others = g_list_append (others, section);
1156 else
1157 res = section;
1158 }
1159 /* Advance reader and potentially read another section */
1160 data += section_length;
1161 if (data < packet->data_end && *data != 0xff)
1162 goto section_start;
1163 /* If not, exit */
1164 goto out;
1165 }
1166 /* We don't have enough bytes to do short section shortcut */
1167 }
1168
1169 /* Beginning of a new section, do as much pre-parsing as possible */
1170 /* table_id : 8 bit */
1171 table_id = *data++;
1172
1173 /* section_syntax_indicator : 1 bit
1174 * other_fields (reserved) : 3 bit
1175 * section_length : 12 bit */
1176 section_length = (GST_READ_UINT16_BE (data) & 0x0FFF) + 3;
1177 data += 2;
1178
1179 if (long_packet) {
1180 /* Do we have enough data for a long packet? */
1181 if (data > packet->data_end - 5)
1182 goto out;
1183
1184 /* subtable_extension (always present, we are in a long section) */
1185 /* subtable extension : 16 bit */
1186 subtable_extension = GST_READ_UINT16_BE (data);
1187 data += 2;
1188
1189 /* reserved : 2 bit
1190 * version_number : 5 bit
1191 * current_next_indicator : 1 bit */
1192 /* Bail out now if current_next_indicator == 0 */
1193 if (G_UNLIKELY (!(*data & 0x01))) {
1194 GST_DEBUG
1195 ("PID 0x%04x table_id 0x%02x section does not apply (current_next_indicator == 0)",
1196 packet->pid, table_id);
1197 goto out;
1198 }
1199
1200 version_number = *data++ >> 1 & 0x1f;
1201 /* section_number : 8 bit */
1202 section_number = *data++;
1203 /* last_section_number : 8 bit */
1204 last_section_number = *data++;
1205 } else {
1206 subtable_extension = 0;
1207 version_number = 0;
1208 section_number = 0;
1209 last_section_number = 0;
1210 }
1211 GST_DEBUG
1212 ("PID 0x%04x length:%d table_id:0x%02x subtable_extension:0x%04x version_number:%d section_number:%d(last:%d)",
1213 packet->pid, section_length, table_id, subtable_extension, version_number,
1214 section_number, last_section_number);
1215
1216 to_read = MIN (section_length, packet->data_end - data_start);
1217
1218 /* Check as early as possible whether we already saw this section
1219 * i.e. that we saw a subtable with:
1220 * * same subtable_extension (might be zero)
1221 * * same version_number
1222 * * same last_section_number
1223 * * same section_number was seen
1224 */
1225 if (!cc_discont && seen_section_before (stream, table_id, subtable_extension,
1226 version_number, section_number, last_section_number)) {
1227 GST_DEBUG
1228 ("PID 0x%04x Already processed table_id:0x%02x subtable_extension:0x%04x, version_number:%d, section_number:%d",
1229 packet->pid, table_id, subtable_extension, version_number,
1230 section_number);
1231 /* skip data and see if we have more sections after */
1232 data = data_start + to_read;
1233 if (data == packet->data_end || *data == 0xff)
1234 goto out;
1235 goto section_start;
1236 }
1237 if (G_UNLIKELY (section_number > last_section_number)) {
1238 GST_WARNING
1239 ("PID 0x%04x corrupted packet (section_number:%d > last_section_number:%d)",
1240 packet->pid, section_number, last_section_number);
1241 goto out;
1242 }
1243
1244
1245 /* Copy over already parsed values */
1246 stream->table_id = table_id;
1247 stream->section_length = section_length;
1248 stream->version_number = version_number;
1249 stream->subtable_extension = subtable_extension;
1250 stream->section_number = section_number;
1251 stream->last_section_number = last_section_number;
1252 stream->offset = packet->offset;
1253
1254 /* Create enough room to store chunks of sections */
1255 stream->section_data = g_malloc (stream->section_length);
1256 stream->section_offset = 0;
1257
1258 /* Finally, accumulate and check if we parsed enough */
1259 goto accumulate_data;
1260
1261out:
1262 packet->data = data;
1263 *remaining = others;
1264
1265 GST_DEBUG ("result: %p", res);
1266
1267 return res;
1268}
1269
1270static void
bo.xiaoff2de692024-08-07 14:38:55 +08001271_aml_init_local (void)
hanghang.luofa7b16f2024-05-31 14:44:31 +08001272{
1273 GST_DEBUG_CATEGORY_INIT (amlts_packetizer_debug, "amltspacketizer", 0,
1274 "MPEG transport stream parser");
1275}
1276
1277
1278static void
1279amlts_packetizer_resync (AmlTSPCR * pcr, GstClockTime time,
1280 GstClockTime gstpcrtime, gboolean reset_skew)
1281{
1282 pcr->base_time = time;
1283 pcr->base_pcrtime = gstpcrtime;
1284 pcr->prev_out_time = GST_CLOCK_TIME_NONE;
1285 pcr->prev_send_diff = GST_CLOCK_TIME_NONE;
1286 if (reset_skew) {
1287 pcr->window_filling = TRUE;
1288 pcr->window_pos = 0;
1289 pcr->window_min = 0;
1290 pcr->window_size = 0;
1291 pcr->skew = 0;
1292 }
1293}
1294
1295
1296/* Code mostly copied from -good/gst/rtpmanager/rtpjitterbuffer.c */
1297
1298/* For the clock skew we use a windowed low point averaging algorithm as can be
1299 * found in Fober, Orlarey and Letz, 2005, "Real Time Clock Skew Estimation
1300 * over Network Delays":
1301 * http://www.grame.fr/Ressources/pub/TR-050601.pdf
1302 * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.102.1546
1303 *
1304 * The idea is that the jitter is composed of:
1305 *
1306 * J = N + n
1307 *
1308 * D : a constant network delay.
1309 * n : random added noise. The noise is concentrated around 0
1310 *
1311 * In the receiver we can track the elapsed time at the sender with:
1312 *
1313 * send_diff(i) = (Tsi - Ts0);
1314 *
1315 * Tsi : The time at the sender at packet i
1316 * Ts0 : The time at the sender at the first packet
1317 *
1318 * This is the difference between the RTP timestamp in the first received packet
1319 * and the current packet.
1320 *
1321 * At the receiver we have to deal with the jitter introduced by the network.
1322 *
1323 * recv_diff(i) = (Tri - Tr0)
1324 *
1325 * Tri : The time at the receiver at packet i
1326 * Tr0 : The time at the receiver at the first packet
1327 *
1328 * Both of these values contain a jitter Ji, a jitter for packet i, so we can
1329 * write:
1330 *
1331 * recv_diff(i) = (Cri + D + ni) - (Cr0 + D + n0))
1332 *
1333 * Cri : The time of the clock at the receiver for packet i
1334 * D + ni : The jitter when receiving packet i
1335 *
1336 * We see that the network delay is irrelevant here as we can eliminate D:
1337 *
1338 * recv_diff(i) = (Cri + ni) - (Cr0 + n0))
1339 *
1340 * The drift is now expressed as:
1341 *
1342 * Drift(i) = recv_diff(i) - send_diff(i);
1343 *
1344 * We now keep the W latest values of Drift and find the minimum (this is the
1345 * one with the lowest network jitter and thus the one which is least affected
1346 * by it). We average this lowest value to smooth out the resulting network skew.
1347 *
1348 * Both the window and the weighting used for averaging influence the accuracy
1349 * of the drift estimation. Finding the correct parameters turns out to be a
1350 * compromise between accuracy and inertia.
1351 *
1352 * We use a 2 second window or up to 512 data points, which is statistically big
1353 * enough to catch spikes (FIXME, detect spikes).
1354 * We also use a rather large weighting factor (125) to smoothly adapt. During
1355 * startup, when filling the window, we use a parabolic weighting factor, the
1356 * more the window is filled, the faster we move to the detected possible skew.
1357 *
1358 * Returns: @time adjusted with the clock skew.
1359 */
1360static GstClockTime
1361calculate_skew (AmlTSPacketizer2 * packetizer,
1362 AmlTSPCR * pcr, guint64 pcrtime, GstClockTime time)
1363{
1364 guint64 send_diff, recv_diff;
1365 gint64 delta;
1366 gint64 old;
1367 gint pos, i;
1368 GstClockTime gstpcrtime, out_time;
1369#ifndef GST_DISABLE_GST_DEBUG
1370 guint64 slope;
1371#endif
1372
1373 gstpcrtime = PCRTIME_TO_GSTTIME (pcrtime) + pcr->pcroffset;
1374
1375 /* first time, lock on to time and gstpcrtime */
1376 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pcr->base_time))) {
1377 pcr->base_time = time;
1378 pcr->prev_out_time = GST_CLOCK_TIME_NONE;
1379 GST_DEBUG ("Taking new base time %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
1380 }
1381
1382 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pcr->base_pcrtime))) {
1383 pcr->base_pcrtime = gstpcrtime;
1384 pcr->prev_send_diff = -1;
1385 GST_DEBUG ("Taking new base pcrtime %" GST_TIME_FORMAT,
1386 GST_TIME_ARGS (gstpcrtime));
1387 }
1388
1389 /* Handle PCR wraparound and resets */
1390 if (GST_CLOCK_TIME_IS_VALID (pcr->last_pcrtime) &&
1391 gstpcrtime < pcr->last_pcrtime) {
1392 if (pcr->last_pcrtime - gstpcrtime > PCR_GST_MAX_VALUE / 2) {
1393 /* PCR wraparound */
1394 GST_DEBUG ("PCR wrap");
1395 pcr->pcroffset += PCR_GST_MAX_VALUE;
1396 gstpcrtime = PCRTIME_TO_GSTTIME (pcrtime) + pcr->pcroffset;
1397 send_diff = gstpcrtime - pcr->base_pcrtime;
1398 } else if (GST_CLOCK_TIME_IS_VALID (time)
1399 && pcr->last_pcrtime - gstpcrtime > 15 * GST_SECOND) {
1400 /* Time jumped backward by > 15 seconds, and we have a timestamp
1401 * to use to close the discont. Assume a reset */
1402 GST_DEBUG ("PCR reset");
1403 /* Calculate PCR we would have expected for the given input time,
1404 * essentially applying the reverse correction process
1405 *
1406 * We want to find the PCR offset to apply
1407 * pcroffset = (corrected) gstpcrtime - (received) gstpcrtime
1408 *
1409 * send_diff = (corrected) gstpcrtime - pcr->base_pcrtime
1410 * recv_diff = time - pcr->base_time
1411 * out_time = pcr->base_time + send_diff
1412 *
1413 * We are assuming that send_diff == recv_diff
1414 * (corrected) gstpcrtime - pcr->base_pcrtime = time - pcr->base_time
1415 * Giving us:
1416 * (corrected) gstpcrtime = time - pcr->base_time + pcr->base_pcrtime
1417 *
1418 * And therefore:
1419 * pcroffset = time - pcr->base_time + pcr->base_pcrtime - (received) gstpcrtime
1420 **/
1421 pcr->pcroffset += time - pcr->base_time + pcr->base_pcrtime - gstpcrtime;
1422 gstpcrtime = PCRTIME_TO_GSTTIME (pcrtime) + pcr->pcroffset;
1423 send_diff = gstpcrtime - pcr->base_pcrtime;
1424 GST_DEBUG ("Introduced offset is now %" GST_TIME_FORMAT
1425 " corrected pcr time %" GST_TIME_FORMAT,
1426 GST_TIME_ARGS (pcr->pcroffset), GST_TIME_ARGS (gstpcrtime));
1427 } else {
1428 /* Small jumps backward, assume some arrival jitter and skip it */
1429 send_diff = 0;
1430
1431 /* The following code are the different ways we deal with small-ish
1432 * jitter, ranging in severity from "can be ignored" to "this needs a full
1433 * resync" */
1434
1435 if (time == pcr->base_time) {
1436 /* If this comes from a non-fully-timestamped source (i.e. adaptive
1437 * streams), then cope with the fact that some producers generate utter
1438 * PCR garbage on fragment ends.
1439 *
1440 * We detect this comes from a non-fully-timestamped source by the fact
1441 * that the buffer time never changes */
1442 GST_DEBUG ("Ignoring PCR resets on non-fully timestamped stream");
1443 } else if (pcr->last_pcrtime - gstpcrtime < GST_SECOND) {
1444 GST_WARNING
1445 ("(small) backward timestamps at server or no buffer timestamps. Ignoring.");
1446 /* This will trigger the no_skew logic before but leave other state
1447 * intact */
1448 time = GST_CLOCK_TIME_NONE;
1449 } else {
1450 /* A bigger backward step than packet out-of-order can account for. Reset base PCR time
1451 * to be resynched the next time we see a PCR */
1452 GST_WARNING
1453 ("backward timestamps at server or no buffer timestamps. Resync base PCR");
bo.xiao55ff0172024-08-12 16:18:03 +08001454
1455#if 0 //xiaobo-patch 0041-tsdemux
bo.xiaoff2de692024-08-07 14:38:55 +08001456 GST_DEBUG ("delta last_pcrtime - gstpcrtime:%" GST_TIME_FORMAT, GST_TIME_ARGS (pcr->last_pcrtime - gstpcrtime));
1457 if (pcr->last_pcrtime - gstpcrtime > 2*GST_SECOND) {
1458 pcr->base_pcrtime = GST_CLOCK_TIME_NONE;
bo.xiao55ff0172024-08-12 16:18:03 +08001459 GST_DEBUG("change base pcr");
bo.xiaoff2de692024-08-07 14:38:55 +08001460 }
bo.xiao55ff0172024-08-12 16:18:03 +08001461#else
hanghang.luofa7b16f2024-05-31 14:44:31 +08001462 pcr->base_pcrtime = GST_CLOCK_TIME_NONE;
bo.xiao55ff0172024-08-12 16:18:03 +08001463#endif
hanghang.luofa7b16f2024-05-31 14:44:31 +08001464 }
1465 }
1466 } else
1467 send_diff = gstpcrtime - pcr->base_pcrtime;
1468
1469 GST_DEBUG ("gstpcr %" GST_TIME_FORMAT ", buftime %" GST_TIME_FORMAT
1470 ", base %" GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT,
1471 GST_TIME_ARGS (gstpcrtime), GST_TIME_ARGS (time),
1472 GST_TIME_ARGS (pcr->base_pcrtime), GST_TIME_ARGS (send_diff));
1473
1474 /* keep track of the last extended pcrtime */
1475 pcr->last_pcrtime = gstpcrtime;
1476
1477 /* we don't have an arrival timestamp so we can't do skew detection. we
1478 * should still apply a timestamp based on RTP timestamp and base_time */
1479 if (!GST_CLOCK_TIME_IS_VALID (time)
1480 || !GST_CLOCK_TIME_IS_VALID (pcr->base_time))
1481 goto no_skew;
1482
1483 /* elapsed time at receiver, includes the jitter */
1484 recv_diff = time - pcr->base_time;
1485
1486 /* Ignore packets received at 100% the same time (i.e. from the same input buffer) */
1487 if (G_UNLIKELY (time == pcr->prev_in_time
1488 && GST_CLOCK_TIME_IS_VALID (pcr->prev_in_time)))
1489 goto no_skew;
1490
1491 /* measure the diff */
1492 delta = ((gint64) recv_diff) - ((gint64) send_diff);
1493
1494#ifndef GST_DISABLE_GST_DEBUG
1495 /* measure the slope, this gives a rought estimate between the sender speed
1496 * and the receiver speed. This should be approximately 8, higher values
1497 * indicate a burst (especially when the connection starts) */
1498 slope = recv_diff > 0 ? (send_diff * 8) / recv_diff : 8;
1499#endif
1500
1501 GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT
1502 ", recv_diff %" GST_TIME_FORMAT ", slope %" G_GUINT64_FORMAT,
1503 GST_TIME_ARGS (time), GST_TIME_ARGS (pcr->base_time),
1504 GST_TIME_ARGS (recv_diff), slope);
1505
1506 /* if the difference between the sender timeline and the receiver timeline
1507 * changed too quickly we have to resync because the server likely restarted
1508 * its timestamps. */
1509 if (ABS (delta - pcr->skew) > packetizer->pcr_discont_threshold) {
1510 GST_WARNING ("delta - skew: %" GST_STIME_FORMAT " too big, reset skew",
1511 GST_STIME_ARGS (delta - pcr->skew));
1512 amlts_packetizer_resync (pcr, time, gstpcrtime, TRUE);
1513 send_diff = 0;
1514 delta = 0;
1515 }
1516
1517 pos = pcr->window_pos;
1518
1519 if (G_UNLIKELY (pcr->window_filling)) {
1520 /* we are filling the window */
1521 GST_DEBUG ("filling %d, delta %" G_GINT64_FORMAT, pos, delta);
1522 pcr->window[pos++] = delta;
1523 /* calc the min delta we observed */
1524 if (G_UNLIKELY (pos == 1 || delta < pcr->window_min))
1525 pcr->window_min = delta;
1526
1527 if (G_UNLIKELY (send_diff >= MAX_TIME || pos >= MAX_WINDOW)) {
1528 pcr->window_size = pos;
1529
1530 /* window filled */
1531 GST_DEBUG ("min %" G_GINT64_FORMAT, pcr->window_min);
1532
1533 /* the skew is now the min */
1534 pcr->skew = pcr->window_min;
1535 pcr->window_filling = FALSE;
1536 } else {
1537 gint perc_time, perc_window, perc;
1538
1539 /* figure out how much we filled the window, this depends on the amount of
1540 * time we have or the max number of points we keep. */
1541 perc_time = send_diff * 100 / MAX_TIME;
1542 perc_window = pos * 100 / MAX_WINDOW;
1543 perc = MAX (perc_time, perc_window);
1544
1545 /* make a parabolic function, the closer we get to the MAX, the more value
1546 * we give to the scaling factor of the new value */
1547 perc = perc * perc;
1548
1549 /* quickly go to the min value when we are filling up, slowly when we are
1550 * just starting because we're not sure it's a good value yet. */
1551 pcr->skew =
1552 (perc * pcr->window_min + ((10000 - perc) * pcr->skew)) / 10000;
1553 pcr->window_size = pos + 1;
1554 }
1555 } else {
1556 /* pick old value and store new value. We keep the previous value in order
1557 * to quickly check if the min of the window changed */
1558 old = pcr->window[pos];
1559 pcr->window[pos++] = delta;
1560
1561 if (G_UNLIKELY (delta <= pcr->window_min)) {
1562 /* if the new value we inserted is smaller or equal to the current min,
1563 * it becomes the new min */
1564 pcr->window_min = delta;
1565 } else if (G_UNLIKELY (old == pcr->window_min)) {
1566 gint64 min = G_MAXINT64;
1567
1568 /* if we removed the old min, we have to find a new min */
1569 for (i = 0; i < pcr->window_size; i++) {
1570 /* we found another value equal to the old min, we can stop searching now */
1571 if (pcr->window[i] == old) {
1572 min = old;
1573 break;
1574 }
1575 if (pcr->window[i] < min)
1576 min = pcr->window[i];
1577 }
1578 pcr->window_min = min;
1579 }
1580 /* average the min values */
1581 pcr->skew = (pcr->window_min + (124 * pcr->skew)) / 125;
1582 GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT,
1583 delta, pcr->window_min);
1584 }
1585 /* wrap around in the window */
1586 if (G_UNLIKELY (pos >= pcr->window_size))
1587 pos = 0;
1588
1589 pcr->window_pos = pos;
1590
1591no_skew:
1592 /* the output time is defined as the base timestamp plus the PCR time
1593 * adjusted for the clock skew .*/
1594 if (pcr->base_time != -1) {
1595 out_time = pcr->base_time + send_diff;
1596 /* skew can be negative and we don't want to make invalid timestamps */
1597 if (pcr->skew < 0 && out_time < -pcr->skew) {
1598 out_time = 0;
1599 } else {
1600 out_time += pcr->skew;
1601 }
1602 /* check if timestamps are not going backwards, we can only check this if we
1603 * have a previous out time and a previous send_diff */
1604 if (G_LIKELY (pcr->prev_out_time != -1 && pcr->prev_send_diff != -1)) {
1605 /* now check for backwards timestamps */
1606 if (G_UNLIKELY (
1607 /* if the server timestamps went up and the out_time backwards */
1608 (send_diff > pcr->prev_send_diff
1609 && out_time < pcr->prev_out_time) ||
1610 /* if the server timestamps went backwards and the out_time forwards */
1611 (send_diff < pcr->prev_send_diff
1612 && out_time > pcr->prev_out_time) ||
1613 /* if the server timestamps did not change */
1614 send_diff == pcr->prev_send_diff)) {
1615 GST_DEBUG ("backwards timestamps, using previous time");
1616 out_time = GSTTIME_TO_MPEGTIME (out_time);
1617 }
1618 }
1619 } else {
1620 /* We simply use the pcrtime without applying any skew compensation */
1621 out_time = time;
1622 }
1623
1624 pcr->prev_out_time = out_time;
1625 pcr->prev_in_time = time;
1626 pcr->prev_send_diff = send_diff;
1627
1628 GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
1629 pcr->skew, GST_TIME_ARGS (out_time));
1630
1631 return out_time;
1632}
1633
1634static void
1635_reevaluate_group_pcr_offset (AmlTSPCR * pcrtable, PCROffsetGroup * group)
1636{
1637 PCROffsetGroup *prev = NULL;
1638#ifndef GST_DISABLE_GST_DEBUG
1639 PCROffsetGroup *first = pcrtable->groups->data;
1640#endif
1641 PCROffsetCurrent *current = pcrtable->current;
1642 GList *tmp;
1643
1644 /* Go over all ESTIMATED groups until the target group */
1645 for (tmp = pcrtable->groups; tmp; tmp = tmp->next) {
1646 PCROffsetGroup *cur = (PCROffsetGroup *) tmp->data;
1647
1648 /* Skip groups that don't need re-evaluation */
1649 if (!(cur->flags & PCR_GROUP_FLAG_ESTIMATED)) {
1650 GST_DEBUG ("Skipping group %p pcr_offset (currently %" GST_TIME_FORMAT
1651 ")", cur, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (cur->pcr_offset)));
1652 prev = cur;
1653 continue;
1654 }
1655
1656 /* This should not happen ! The first group is *always* correct (zero) */
1657 if (G_UNLIKELY (prev == NULL)) {
1658 GST_ERROR ("First PCR Group was not estimated (bug). Setting to zero");
1659 cur->pcr_offset = 0;
1660 cur->flags &= ~PCR_GROUP_FLAG_ESTIMATED;
1661 return;
1662 }
1663
1664 /* Finally do the estimation of this group's PCR offset based on the
1665 * previous group information */
1666
1667 GST_DEBUG ("Re-evaluating group %p pcr_offset (currently %" GST_TIME_FORMAT
1668 ")", group, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (cur->pcr_offset)));
1669
1670 GST_DEBUG ("cur->first_pcr:%" GST_TIME_FORMAT " prev->first_pcr:%"
1671 GST_TIME_FORMAT, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (cur->first_pcr)),
1672 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (prev->first_pcr)));
1673
1674 if (G_UNLIKELY (cur->first_pcr < prev->first_pcr)) {
1675 guint64 prevbr, lastbr;
1676 guint64 prevpcr;
1677 guint64 prevoffset, lastoffset;
1678
1679 /* Take the previous group pcr_offset and figure out how much to add
1680 * to it for the current group */
1681
1682 /* Right now we do a dumb bitrate estimation
1683 * estimate bitrate (prev - first) : bitrate from the start
1684 * estimate bitrate (prev) : bitrate of previous group
1685 * estimate bitrate (last - first) : bitrate from previous group
1686 *
1687 * We will use raw (non-corrected/non-absolute) PCR values in a first time
1688 * to detect wraparound/resets/gaps...
1689 *
1690 * We will use the corrected/absolute PCR values to calculate
1691 * bitrate and estimate the target group pcr_offset.
1692 * */
1693
1694 /* If the current window estimator is over the previous group, used those
1695 * values as the latest (since they are more recent) */
1696 if (current->group == prev && current->pending[current->last].offset) {
1697 prevoffset =
1698 current->pending[current->last].offset + prev->first_offset;
1699 prevpcr = current->pending[current->last].pcr + prev->first_pcr;
1700 /* prevbr: bitrate(prev) */
1701 prevbr =
1702 gst_util_uint64_scale (PCR_SECOND,
1703 current->pending[current->last].offset,
1704 current->pending[current->last].pcr);
1705 GST_DEBUG ("Previous group bitrate (%" G_GUINT64_FORMAT " / %"
1706 GST_TIME_FORMAT ") : %" G_GUINT64_FORMAT,
1707 current->pending[current->last].offset,
1708 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (current->pending[current->last].
1709 pcr)), prevbr);
1710 } else if (prev->values[prev->last_value].offset) {
1711 prevoffset = prev->values[prev->last_value].offset + prev->first_offset;
1712 prevpcr = prev->values[prev->last_value].pcr + prev->first_pcr;
1713 /* prevbr: bitrate(prev) (FIXME : Cache) */
1714 prevbr =
1715 gst_util_uint64_scale (PCR_SECOND,
1716 prev->values[prev->last_value].offset,
1717 prev->values[prev->last_value].pcr);
1718 GST_DEBUG ("Previous group bitrate (%" G_GUINT64_FORMAT " / %"
1719 GST_TIME_FORMAT ") : %" G_GUINT64_FORMAT,
1720 prev->values[prev->last_value].offset,
1721 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (prev->values[prev->last_value].
1722 pcr)), prevbr);
1723 } else {
1724 GST_DEBUG ("Using overall bitrate");
1725 prevoffset = prev->values[prev->last_value].offset + prev->first_offset;
1726 prevpcr = prev->values[prev->last_value].pcr + prev->first_pcr;
1727 prevbr = gst_util_uint64_scale (PCR_SECOND,
1728 prev->first_offset, prev->pcr_offset);
1729 }
1730 lastoffset = cur->values[cur->last_value].offset + cur->first_offset;
1731
1732 GST_DEBUG ("Offset first:%" G_GUINT64_FORMAT " prev:%" G_GUINT64_FORMAT
1733 " cur:%" G_GUINT64_FORMAT, first->first_offset, prevoffset,
1734 lastoffset);
1735 GST_DEBUG ("PCR first:%" GST_TIME_FORMAT " prev:%" GST_TIME_FORMAT
1736 " cur:%" GST_TIME_FORMAT,
1737 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (first->first_pcr)),
1738 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (prevpcr)),
1739 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (cur->values[cur->last_value].pcr +
1740 cur->first_pcr)));
1741
1742 if (prevpcr - cur->first_pcr > (PCR_MAX_VALUE * 9 / 10)) {
1743 gfloat diffprev;
1744 guint64 guess_offset;
1745
1746 /* Let's assume there is a PCR wraparound between the previous and current
1747 * group.
1748 * [ prev ]... PCR_MAX | 0 ...[ current ]
1749 * The estimated pcr_offset would therefore be:
1750 * current.first + (PCR_MAX_VALUE - prev.first)
1751 *
1752 * 1) Check if bitrate(prev) would be consistent with bitrate (cur - prev)
1753 */
1754 guess_offset = PCR_MAX_VALUE - prev->first_pcr + cur->first_pcr;
1755 lastbr = gst_util_uint64_scale (PCR_SECOND, lastoffset - prevoffset,
1756 guess_offset + cur->values[cur->last_value].pcr - (prevpcr -
1757 prev->first_pcr));
1758 GST_DEBUG ("Wraparound prev-cur (guess_offset:%" GST_TIME_FORMAT
1759 ") bitrate:%" G_GUINT64_FORMAT,
1760 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (guess_offset)), lastbr);
1761 diffprev = (float) 100.0 *(ABSDIFF (prevbr, lastbr)) / (float) prevbr;
1762 GST_DEBUG ("Difference with previous bitrate:%f", diffprev);
1763 if (diffprev < 10.0) {
1764 GST_DEBUG ("Difference < 10.0, Setting pcr_offset to %"
1765 G_GUINT64_FORMAT, guess_offset);
1766 cur->pcr_offset = guess_offset;
1767 if (diffprev < 1.0) {
1768 GST_DEBUG ("Difference < 1.0, Removing ESTIMATED flags");
1769 cur->flags &= ~PCR_GROUP_FLAG_ESTIMATED;
1770 }
1771 }
1772 /* Indicate the the previous group is before a wrapover */
1773 prev->flags |= PCR_GROUP_FLAG_WRAPOVER;
1774 } else {
1775 guint64 resetprev;
1776 /* Let's assume there was a PCR reset between the previous and current
1777 * group
1778 * [ prev ] ... x | x - reset ... [ current ]
1779 *
1780 * The estimated pcr_offset would then be
1781 * = current.first - (x - reset) + (x - prev.first) + 100ms (for safety)
1782 * = current.first + reset - prev.first + 100ms (for safety)
1783 */
1784 /* In order to calculate the reset, we estimate what the PCR would have
1785 * been by using prevbr */
1786 /* FIXME : Which bitrate should we use ??? */
1787 GST_DEBUG ("Using prevbr:%" G_GUINT64_FORMAT " and taking offsetdiff:%"
1788 G_GUINT64_FORMAT, prevbr, cur->first_offset - prev->first_offset);
1789 resetprev =
1790 gst_util_uint64_scale (PCR_SECOND,
1791 cur->first_offset - prev->first_offset, prevbr);
1792 GST_DEBUG ("Estimated full PCR for offset %" G_GUINT64_FORMAT
1793 ", using prevbr:%"
1794 GST_TIME_FORMAT, cur->first_offset,
1795 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (resetprev)));
1796 cur->pcr_offset = prev->pcr_offset + resetprev + 100 * PCR_MSECOND;
1797 GST_DEBUG ("Adjusted group PCR_offset to %" GST_TIME_FORMAT,
1798 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (cur->pcr_offset)));
1799 /* Indicate the the previous group is before a reset */
1800 prev->flags |= PCR_GROUP_FLAG_RESET;
1801 }
1802 } else {
1803 /* FIXME : Detect gaps if bitrate difference is really too big ? */
1804 cur->pcr_offset = prev->pcr_offset + cur->first_pcr - prev->first_pcr;
1805 GST_DEBUG ("Assuming there is no gap, setting pcr_offset to %"
1806 GST_TIME_FORMAT,
1807 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (cur->pcr_offset)));
1808 /* Remove the reset and wrapover flag (if it was previously there) */
1809 prev->flags &= ~PCR_GROUP_FLAG_RESET;
1810 prev->flags &= ~PCR_GROUP_FLAG_WRAPOVER;
1811 }
1812
1813
1814 /* Remember prev for the next group evaluation */
1815 prev = cur;
1816 }
1817}
1818
1819static PCROffsetGroup *
1820_new_group (guint64 pcr, guint64 offset, guint64 pcr_offset, guint flags)
1821{
1822 PCROffsetGroup *group = g_slice_new0 (PCROffsetGroup);
1823
1824 GST_DEBUG ("Input PCR %" GST_TIME_FORMAT " offset:%" G_GUINT64_FORMAT
1825 " pcr_offset:%" G_GUINT64_FORMAT " flags:%d",
1826 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcr)), offset, pcr_offset, flags);
1827
1828 group->flags = flags;
1829 group->values = g_new0 (PCROffset, DEFAULT_ALLOCATED_OFFSET);
1830 /* The first pcr/offset diff is always 0/0 */
1831 group->values[0].pcr = group->values[0].offset = 0;
1832 group->nb_allocated = DEFAULT_ALLOCATED_OFFSET;
1833
1834 /* Store the full values */
1835 group->first_pcr = pcr;
1836 group->first_offset = offset;
1837 group->pcr_offset = pcr_offset;
1838
1839 GST_DEBUG ("Created group starting with pcr:%" GST_TIME_FORMAT " offset:%"
1840 G_GUINT64_FORMAT " pcr_offset:%" GST_TIME_FORMAT,
1841 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->first_pcr)),
1842 group->first_offset,
1843 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->pcr_offset)));
1844
1845 return group;
1846}
1847
1848static void
1849_insert_group_after (AmlTSPCR * pcrtable, PCROffsetGroup * group,
1850 PCROffsetGroup * prev)
1851{
1852 if (prev == NULL) {
1853 /* First group */
1854 pcrtable->groups = g_list_prepend (pcrtable->groups, group);
1855 } else {
1856 GList *tmp, *toinsert, *prevlist = NULL, *nextlist = NULL;
1857 /* Insert before next and prev */
1858 for (tmp = pcrtable->groups; tmp; tmp = tmp->next) {
1859 if (tmp->data == prev) {
1860 prevlist = tmp;
1861 nextlist = tmp->next;
1862 break;
1863 }
1864 }
1865 if (!prevlist) {
1866 /* The non NULL prev given isn't in the list */
1867 GST_WARNING ("Request to insert before a group which isn't in the list");
1868 pcrtable->groups = g_list_prepend (pcrtable->groups, group);
1869 } else {
1870 toinsert = g_list_append (NULL, group);
1871 toinsert->next = nextlist;
1872 toinsert->prev = prevlist;
1873 prevlist->next = toinsert;
1874 if (nextlist)
1875 nextlist->prev = toinsert;
1876 }
1877 }
1878}
1879
1880static void
1881_use_group (AmlTSPCR * pcrtable, PCROffsetGroup * group)
1882{
1883 PCROffsetCurrent *current = pcrtable->current;
1884
1885 memset (current, 0, sizeof (PCROffsetCurrent));
1886 current->group = group;
1887 current->pending[0] = group->values[group->last_value];
1888 current->last_value = current->pending[0];
1889 current->write = 1;
1890 current->prev = group->values[group->last_value];
1891 current->first_pcr = group->first_pcr;
1892 current->first_offset = group->first_offset;
1893}
1894
1895/* Create a new group with the specified values after prev
1896 * Set current to that new group */
1897static void
1898_set_current_group (AmlTSPCR * pcrtable,
1899 PCROffsetGroup * prev, guint64 pcr, guint64 offset, gboolean contiguous)
1900{
1901 PCROffsetGroup *group;
1902 guint flags = 0;
1903 guint64 pcr_offset = 0;
1904
1905 /* Handle wraparound/gap (only if contiguous with previous group) */
1906 if (contiguous) {
1907 guint64 lastpcr = prev->first_pcr + prev->values[prev->last_value].pcr;
1908
1909 /* Set CLOSED flag on previous group and remember pcr_offset */
1910 prev->flags |= PCR_GROUP_FLAG_CLOSED;
1911 pcr_offset = prev->pcr_offset;
1912
1913 /* Wraparound ? */
1914 if (lastpcr > pcr) {
1915 /* In offset-mode, a PCR wraparound is only actually consistent if
1916 * we have a very high confidence (99% right now, might need to change
1917 * later) */
1918 if (lastpcr - pcr > (PCR_MAX_VALUE * 99 / 100)) {
1919 GST_WARNING ("WRAPAROUND detected. diff %" GST_TIME_FORMAT,
1920 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (lastpcr - pcr)));
1921 /* The previous group closed at PCR_MAX_VALUE */
1922 pcr_offset += PCR_MAX_VALUE - prev->first_pcr + pcr;
1923 } else {
1924 GST_WARNING ("RESET detected. diff %" GST_TIME_FORMAT,
1925 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (lastpcr - pcr)));
1926 /* The previous group closed at the raw last_pcr diff (+100ms for safety) */
1927 pcr_offset += prev->values[prev->last_value].pcr + 100 * PCR_MSECOND;
1928 }
1929 } else if (lastpcr < pcr - 500 * PCR_MSECOND) {
1930 GST_WARNING ("GAP detected. diff %" GST_TIME_FORMAT,
1931 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcr - lastpcr)));
hanghang.luoda8ba322024-06-03 16:21:06 +08001932 /*pcr_offset need to add gap time of pcr to lastpcr, because prev->values[prev->last_value].pcr is
1933 always 0 that cause calcute current pts issue*/
1934 pcr_offset += pcr - lastpcr;
hanghang.luofa7b16f2024-05-31 14:44:31 +08001935 } else
1936 /* Normal continuation (contiguous in time) */
1937 pcr_offset += pcr - prev->first_pcr;
1938
1939 } else if (prev != NULL)
1940 /* If we are not contiguous and it's not the first group, the pcr_offset
1941 * will be estimated */
1942 flags = PCR_GROUP_FLAG_ESTIMATED;
1943
1944 group = _new_group (pcr, offset, pcr_offset, flags);
1945 _use_group (pcrtable, group);
1946 _insert_group_after (pcrtable, group, prev);
1947 if (!contiguous)
1948 _reevaluate_group_pcr_offset (pcrtable, group);
1949}
1950
1951static inline void
1952_append_group_values (PCROffsetGroup * group, PCROffset pcroffset)
1953{
1954 /* Only append if new values */
1955 if (group->values[group->last_value].offset == pcroffset.offset &&
1956 group->values[group->last_value].pcr == pcroffset.pcr) {
1957 GST_DEBUG ("Same values, ignoring");
1958 } else {
1959 group->last_value++;
1960 /* Resize values if needed */
1961 if (G_UNLIKELY (group->nb_allocated == group->last_value)) {
1962 group->nb_allocated += DEFAULT_ALLOCATED_OFFSET;
1963 group->values =
1964 g_realloc (group->values, group->nb_allocated * sizeof (PCROffset));
1965 }
1966 group->values[group->last_value] = pcroffset;
1967 }
1968
1969 GST_DEBUG ("First PCR:%" GST_TIME_FORMAT " offset:%" G_GUINT64_FORMAT
1970 " PCR_offset:%" GST_TIME_FORMAT,
1971 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->first_pcr)),
1972 group->first_offset,
1973 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->pcr_offset)));
1974 GST_DEBUG ("Last PCR: +%" GST_TIME_FORMAT " offset: +%" G_GUINT64_FORMAT,
1975 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcroffset.pcr)), pcroffset.offset);
1976}
1977
1978/* Move last values from current (if any) to the current group
1979 * and reset current.
1980 * Note: This does not set the CLOSED flag (since we have no next
1981 * contiguous group) */
1982static void
bo.xiaoff2de692024-08-07 14:38:55 +08001983_aml_close_current_group (AmlTSPCR * pcrtable)
hanghang.luofa7b16f2024-05-31 14:44:31 +08001984{
1985 PCROffsetCurrent *current = pcrtable->current;
1986 PCROffsetGroup *group = current->group;
1987
1988 if (group == NULL)
1989 return;
1990 GST_DEBUG ("Closing group and resetting current");
1991
1992 /* Store last values */
1993 _append_group_values (group, current->pending[current->last]);
1994 memset (current, 0, sizeof (PCROffsetCurrent));
1995 /* And re-evaluate all groups */
1996}
1997
1998static void
bo.xiaoff2de692024-08-07 14:38:55 +08001999aml_record_pcr (AmlTSPacketizer2 * packetizer, AmlTSPCR * pcrtable,
hanghang.luofa7b16f2024-05-31 14:44:31 +08002000 guint64 pcr, guint64 offset)
2001{
2002 PCROffsetCurrent *current = pcrtable->current;
2003 gint64 corpcr, coroffset;
2004
2005 packetizer->nb_seen_offsets += 1;
2006
2007 pcrtable->last_pcrtime = PCRTIME_TO_GSTTIME (pcr);
2008 /* FIXME : Invert logic later (probability is higher that we have a
2009 * current estimator) */
2010
2011 /* Check for current */
2012 if (G_UNLIKELY (current->group == NULL)) {
2013 PCROffsetGroup *prev = NULL;
2014 GList *tmp;
2015 /* No current estimator. This happens for the initial value, or after
2016 * discont and flushes. Figure out where we need to record this position.
2017 *
2018 * Possible choices:
2019 * 1) No groups at all:
2020 * Create a new group with pcr/offset
2021 * Initialize current to that group
2022 * 2) Entirely within an existing group
2023 * bail out (FIXME: Make this detection faster)
2024 * 3) Not in any group
2025 * Create a new group with pcr/offset at the right position
2026 * Initialize current to that group
2027 */
2028 GST_DEBUG ("No current window estimator, Checking for group to use");
2029 for (tmp = pcrtable->groups; tmp; tmp = tmp->next) {
2030 PCROffsetGroup *group = (PCROffsetGroup *) tmp->data;
2031
2032 GST_DEBUG ("First PCR:%" GST_TIME_FORMAT " offset:%" G_GUINT64_FORMAT
2033 " PCR_offset:%" GST_TIME_FORMAT,
2034 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->first_pcr)),
2035 group->first_offset,
2036 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->pcr_offset)));
2037 GST_DEBUG ("Last PCR: +%" GST_TIME_FORMAT " offset: +%" G_GUINT64_FORMAT,
2038 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->values[group->last_value].
2039 pcr)), group->values[group->last_value].offset);
2040 /* Check if before group */
2041 if (offset < group->first_offset) {
2042 GST_DEBUG ("offset is before that group");
2043 break;
2044 }
2045 /* Check if within group */
2046 if (offset <=
2047 (group->values[group->last_value].offset + group->first_offset)) {
2048 GST_DEBUG ("Already observed PCR offset %" G_GUINT64_FORMAT, offset);
2049 return;
2050 }
2051 /* Check if just after group (i.e. continuation of it) */
2052 if (!(group->flags & PCR_GROUP_FLAG_CLOSED) &&
2053 pcr - group->first_pcr - group->values[group->last_value].pcr <=
2054 100 * PCR_MSECOND) {
2055 GST_DEBUG ("Continuation of existing group");
2056 _use_group (pcrtable, group);
2057 return;
2058 }
2059 /* Else after group */
2060 prev = group;
2061 }
2062 _set_current_group (pcrtable, prev, pcr, offset, FALSE);
2063 return;
2064 }
2065
2066 corpcr = pcr - current->first_pcr;
2067 coroffset = offset - current->first_offset;
2068
2069 /* FIXME : Detect if we've gone into the next group !
2070 * FIXME : Close group when that happens */
2071 GST_DEBUG ("first:%d, last:%d, write:%d", current->first, current->last,
2072 current->write);
2073 GST_DEBUG ("First PCR:%" GST_TIME_FORMAT " offset:%" G_GUINT64_FORMAT,
2074 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (current->first_pcr)),
2075 current->first_offset);
2076 GST_DEBUG ("Last PCR: +%" GST_TIME_FORMAT " offset: +%" G_GUINT64_FORMAT,
2077 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (current->pending[current->last].pcr)),
2078 current->pending[current->last].offset);
2079 GST_DEBUG ("To add (corrected) PCR:%" GST_TIME_FORMAT " offset:%"
2080 G_GINT64_FORMAT, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (corpcr)), coroffset);
2081
2082 /* Do we need to close the current group ? */
2083 /* Check for wrapover/discont */
2084 if (G_UNLIKELY (corpcr < current->pending[current->last].pcr)) {
2085 /* FIXME : ignore very small deltas (< 500ms ?) which are most likely
2086 * stray values */
2087 GST_DEBUG
2088 ("PCR smaller than previously observed one, handling discont/wrapover");
2089 /* Take values from current and put them in the current group (closing it) */
2090 /* Create new group with new pcr/offset just after the current group
2091 * and mark it as a wrapover */
2092 /* Initialize current to that group with new values */
2093 _append_group_values (current->group, current->pending[current->last]);
2094 _set_current_group (pcrtable, current->group, pcr, offset, TRUE);
2095 return;
2096 }
2097 /* If PCR diff is greater than 500ms, create new group */
2098 if (G_UNLIKELY (corpcr - current->pending[current->last].pcr >
2099 500 * PCR_MSECOND)) {
2100 GST_DEBUG ("New PCR more than 500ms away, handling discont");
2101 /* Take values from current and put them in the current group (closing it) */
2102 /* Create new group with pcr/offset just after the current group
2103 * and mark it as a discont */
2104 /* Initialize current to that group with new values */
2105 _append_group_values (current->group, current->pending[current->last]);
2106 _set_current_group (pcrtable, current->group, pcr, offset, TRUE);
2107 return;
2108 }
2109
2110 if (G_UNLIKELY (corpcr == current->last_value.pcr)) {
2111 GST_DEBUG ("Ignoring same PCR (stream is drunk)");
2112 return;
2113 }
2114
2115 /* update current window */
2116 current->pending[current->write].pcr = corpcr;
2117 current->pending[current->write].offset = coroffset;
2118 current->last_value = current->pending[current->write];
2119 current->last = (current->last + 1) % PCR_BITRATE_NEEDED;
2120 current->write = (current->write + 1) % PCR_BITRATE_NEEDED;
2121
2122 GST_DEBUG ("first:%d, last:%d, write:%d", current->first, current->last,
2123 current->write);
2124 GST_DEBUG ("First PCR:%" GST_TIME_FORMAT " offset:%" G_GUINT64_FORMAT,
2125 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (current->first_pcr)),
2126 current->first_offset);
2127 GST_DEBUG ("Last PCR: +%" GST_TIME_FORMAT " offset: +%" G_GUINT64_FORMAT,
2128 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (current->pending[current->last].pcr)),
2129 current->pending[current->last].offset);
2130
2131 /* If we haven't stored enough values, bail out */
2132 if (current->write != current->first) {
2133 GST_DEBUG
2134 ("Not enough observations to calculate bitrate (first:%d, last:%d)",
2135 current->first, current->last);
2136 return;
2137 }
2138
2139 /* If we are at least 1s away from reference value AND we have filled our
2140 * window, we can start comparing bitrates */
2141 if (current->pending[current->first].pcr - current->prev.pcr > PCR_SECOND) {
2142 /* Calculate window bitrate */
2143 current->cur_bitrate = gst_util_uint64_scale (PCR_SECOND,
2144 current->pending[current->last].offset -
2145 current->pending[current->first].offset,
2146 current->pending[current->last].pcr -
2147 current->pending[current->first].pcr);
2148 GST_DEBUG ("Current bitrate is now %" G_GUINT64_FORMAT,
2149 current->cur_bitrate);
2150
2151 /* Calculate previous bitrate */
2152 current->prev_bitrate =
2153 gst_util_uint64_scale (PCR_SECOND,
2154 current->pending[current->first].offset - current->prev.offset,
2155 current->pending[current->first].pcr - current->prev.pcr);
2156 GST_DEBUG ("Previous group bitrate now %" G_GUINT64_FORMAT,
2157 current->prev_bitrate);
2158
2159 /* FIXME : Better bitrate changes ? Currently 10% changes */
2160 if (ABSDIFF (current->cur_bitrate,
2161 current->prev_bitrate) * 10 > current->prev_bitrate) {
2162 GST_DEBUG ("Current bitrate changed by more than 10%% (old:%"
2163 G_GUINT64_FORMAT " new:%" G_GUINT64_FORMAT ")", current->prev_bitrate,
2164 current->cur_bitrate);
2165 /* If we detected a change in bitrate, this means that
2166 * d(first - prev) is a different bitrate than d(last - first).
2167 *
2168 * Two conclusions can be made:
2169 * 1) d(first - prev) is a complete bitrate "chain" (values between the
2170 * reference value and first pending value have consistent bitrate).
2171 * 2) next values (from second pending value onwards) will no longer have
2172 * the same bitrate.
2173 *
2174 * The question remains as to how long the new bitrate change is going to
2175 * last for (it might be short or longer term). For this we need to restart
2176 * bitrate estimation.
2177 *
2178 * * We move over first to the last value of group (a new chain ends and
2179 * starts from there)
2180 * * We remember that last group value as our new window reference
2181 * * We restart our window filing from the last observed value
2182 *
2183 * Once our new window is filled we will end up in two different scenarios:
2184 * 1) Either the bitrate change was consistent, and therefore the bitrate
2185 * will have remained constant over at least 2 window length
2186 * 2) The bitrate change was very short (1 window duration) and we will
2187 * close that chain and restart again.
2188 * X) And of course if any discont/gaps/wrapover happen in the meantime they
2189 * will also close the group.
2190 */
2191 _append_group_values (current->group, current->pending[current->first]);
2192 current->prev = current->pending[current->first];
2193 current->first = current->last;
2194 current->write = (current->first + 1) % PCR_BITRATE_NEEDED;
2195 return;
2196 }
2197 }
2198
2199 /* Update read position */
2200 current->first = (current->first + 1) % PCR_BITRATE_NEEDED;
2201}
2202
2203
2204/* convert specified offset into stream time */
2205GstClockTime
2206amlts_packetizer_offset_to_ts (AmlTSPacketizer2 * packetizer,
2207 guint64 offset, guint16 pid)
2208{
2209 PCROffsetGroup *last;
2210 AmlTSPCR *pcrtable;
2211 GList *tmp;
2212 GstClockTime res;
2213 guint64 lastpcr, lastoffset;
2214
2215 GST_DEBUG ("offset %" G_GUINT64_FORMAT, offset);
2216
2217 if (G_UNLIKELY (!packetizer->calculate_offset))
2218 return GST_CLOCK_TIME_NONE;
2219
2220 if (G_UNLIKELY (packetizer->refoffset == -1))
2221 return GST_CLOCK_TIME_NONE;
2222
2223 if (G_UNLIKELY (offset < packetizer->refoffset))
2224 return GST_CLOCK_TIME_NONE;
2225
2226 PACKETIZER_GROUP_LOCK (packetizer);
2227
bo.xiaoff2de692024-08-07 14:38:55 +08002228 pcrtable = aml_get_pcr_table (packetizer, pid);
hanghang.luofa7b16f2024-05-31 14:44:31 +08002229
2230 if (g_list_length (pcrtable->groups) < 1) {
2231 PACKETIZER_GROUP_UNLOCK (packetizer);
2232 GST_WARNING ("Not enough observations to return a duration estimate");
2233 return GST_CLOCK_TIME_NONE;
2234 }
2235
2236 if (g_list_length (pcrtable->groups) > 1) {
2237 GST_LOG ("Using last group");
2238
2239 /* FIXME : Refine this later to use neighbouring groups */
2240 tmp = g_list_last (pcrtable->groups);
2241 last = tmp->data;
2242
2243 if (G_UNLIKELY (last->flags & PCR_GROUP_FLAG_ESTIMATED))
2244 _reevaluate_group_pcr_offset (pcrtable, last);
2245
2246 /* lastpcr is the full value in PCR from the first first chunk of data */
2247 lastpcr = last->values[last->last_value].pcr + last->pcr_offset;
2248 /* lastoffset is the full offset from the first chunk of data */
2249 lastoffset =
2250 last->values[last->last_value].offset + last->first_offset -
2251 packetizer->refoffset;
2252 } else {
2253 PCROffsetCurrent *current = pcrtable->current;
2254
2255 if (!current->group) {
2256 PACKETIZER_GROUP_UNLOCK (packetizer);
2257 GST_LOG ("No PCR yet");
2258 return GST_CLOCK_TIME_NONE;
2259 }
2260 /* If doing progressive read, use current */
2261 GST_LOG ("Using current group");
2262 lastpcr = current->group->pcr_offset + current->pending[current->last].pcr;
2263 lastoffset = current->first_offset + current->pending[current->last].offset;
2264 }
2265 GST_DEBUG ("lastpcr:%" GST_TIME_FORMAT " lastoffset:%" G_GUINT64_FORMAT
2266 " refoffset:%" G_GUINT64_FORMAT,
2267 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (lastpcr)), lastoffset,
2268 packetizer->refoffset);
2269
2270 /* Convert byte difference into time difference (and transformed from 27MHz to 1GHz) */
2271 res =
2272 PCRTIME_TO_GSTTIME (gst_util_uint64_scale (offset - packetizer->refoffset,
2273 lastpcr, lastoffset));
2274
2275 PACKETIZER_GROUP_UNLOCK (packetizer);
2276
2277 GST_DEBUG ("Returning timestamp %" GST_TIME_FORMAT " for offset %"
2278 G_GUINT64_FORMAT, GST_TIME_ARGS (res), offset);
2279
2280 return res;
2281}
2282
2283/* Input : local PTS (in GHz units)
2284 * Return : Stream time (in GHz units) */
2285GstClockTime
2286amlts_packetizer_pts_to_ts (AmlTSPacketizer2 * packetizer,
2287 GstClockTime pts, guint16 pcr_pid)
2288{
2289 GstClockTime res = GST_CLOCK_TIME_NONE;
2290 AmlTSPCR *pcrtable;
2291
2292 PACKETIZER_GROUP_LOCK (packetizer);
bo.xiaoff2de692024-08-07 14:38:55 +08002293 pcrtable = aml_get_pcr_table (packetizer, pcr_pid);
hanghang.luofa7b16f2024-05-31 14:44:31 +08002294
2295 if (!GST_CLOCK_TIME_IS_VALID (pcrtable->base_time) && pcr_pid == 0x1fff &&
2296 GST_CLOCK_TIME_IS_VALID (packetizer->last_in_time)) {
2297 pcrtable->base_time = packetizer->last_in_time;
2298 pcrtable->base_pcrtime = pts;
2299 }
2300
2301 /* Use clock skew if present */
2302 if (packetizer->calculate_skew
2303 && GST_CLOCK_TIME_IS_VALID (pcrtable->base_time)) {
2304 GST_DEBUG ("pts %" GST_TIME_FORMAT " base_pcrtime:%" GST_TIME_FORMAT
2305 " base_time:%" GST_TIME_FORMAT " pcroffset:%" GST_TIME_FORMAT,
2306 GST_TIME_ARGS (pts),
2307 GST_TIME_ARGS (pcrtable->base_pcrtime),
2308 GST_TIME_ARGS (pcrtable->base_time),
2309 GST_TIME_ARGS (pcrtable->pcroffset));
2310 res = pts + pcrtable->pcroffset + packetizer->extra_shift;
2311
2312 /* Don't return anything if we differ too much against last seen PCR */
2313 if (G_UNLIKELY (pcr_pid != 0x1fff &&
2314 ABSDIFF (res, pcrtable->last_pcrtime) > 15 * GST_SECOND))
2315 res = GST_CLOCK_TIME_NONE;
bo.xiao55ff0172024-08-12 16:18:03 +08002316#if 0 //xiaobo-patch 0040-live-app
2317 else if GST_CLOCK_TIME_IS_VALID (pcrtable->base_pcrtime){
2318#else
hanghang.luofa7b16f2024-05-31 14:44:31 +08002319 else {
bo.xiao55ff0172024-08-12 16:18:03 +08002320#endif
hanghang.luofa7b16f2024-05-31 14:44:31 +08002321 GstClockTime tmp = pcrtable->base_time + pcrtable->skew;
2322 if (tmp + res >= pcrtable->base_pcrtime) {
2323 res += tmp - pcrtable->base_pcrtime;
2324 } else if (ABSDIFF (tmp + res + PCR_GST_MAX_VALUE,
2325 pcrtable->base_pcrtime) < PCR_GST_MAX_VALUE / 2) {
2326 /* Handle wrapover */
2327 res += tmp + PCR_GST_MAX_VALUE - pcrtable->base_pcrtime;
2328 } else {
2329 /* Fallback for values that differ way too much */
2330 res = GST_CLOCK_TIME_NONE;
2331 }
2332 }
bo.xiao55ff0172024-08-12 16:18:03 +08002333#if 0 // xiaobo-patch 0040-live-app
2334 else
2335 {
2336 res = GST_CLOCK_TIME_NONE;
2337 GST_DEBUG ("set pts as -1, base_pcrtime:%" GST_TIME_FORMAT, GST_TIME_ARGS (pcrtable->base_pcrtime));
2338 }
2339#endif
hanghang.luofa7b16f2024-05-31 14:44:31 +08002340 } else if (packetizer->calculate_offset && pcrtable->groups) {
2341 gint64 refpcr = G_MAXINT64, refpcroffset;
2342 PCROffsetGroup *group = pcrtable->current->group;
2343
2344 /* Generic calculation:
2345 * Stream Time = PTS - first group PCR + group PCR_offset
2346 *
2347 * In case of wrapover:
2348 * Stream Time = PTS + MAX_PCR - first group PCR + group PCR_offset
2349 * (which we actually do by using first group PCR -= MAX_PCR in order
2350 * to end up with the same calculation as for non-wrapover) */
2351
2352 if (group) {
2353 /* If we have a current group the value is pretty much guaranteed */
2354 GST_DEBUG ("Using current First PCR:%" GST_TIME_FORMAT " offset:%"
2355 G_GUINT64_FORMAT " PCR_offset:%" GST_TIME_FORMAT,
2356 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->first_pcr)),
2357 group->first_offset,
2358 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->pcr_offset)));
2359 refpcr = group->first_pcr;
2360 refpcroffset = group->pcr_offset;
2361 if (pts < PCRTIME_TO_GSTTIME (refpcr)) {
2362 /* Only apply wrapover if we're certain it is, and avoid
2363 * returning bogus values if it's a PTS/DTS which is *just*
2364 * before the start of the current group
2365 */
2366 if (PCRTIME_TO_GSTTIME (refpcr) - pts > GST_SECOND) {
2367 pts += PCR_GST_MAX_VALUE;
2368 } else
2369 refpcr = G_MAXINT64;
2370 }
2371 } else {
2372 GList *tmp;
2373 /* Otherwise, find a suitable group */
2374
2375 GST_DEBUG ("Find group for current offset %" G_GUINT64_FORMAT,
2376 packetizer->offset);
2377
2378 for (tmp = pcrtable->groups; tmp; tmp = tmp->next) {
2379 PCROffsetGroup *tgroup = tmp->data;
2380 GST_DEBUG ("Trying First PCR:%" GST_TIME_FORMAT " offset:%"
2381 G_GUINT64_FORMAT " PCR_offset:%" GST_TIME_FORMAT,
2382 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (tgroup->first_pcr)),
2383 tgroup->first_offset,
2384 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (tgroup->pcr_offset)));
2385 /* Gone too far ? */
2386 if (tgroup->first_offset > packetizer->offset) {
2387 /* If there isn't a pending reset, use that value */
2388 if (group) {
2389 GST_DEBUG ("PTS is %" GST_TIME_FORMAT " into group",
2390 GST_TIME_ARGS (pts - PCRTIME_TO_GSTTIME (group->first_pcr)));
2391 }
2392 break;
2393 }
2394 group = tgroup;
2395 /* In that group ? */
2396 if (group->first_offset + group->values[group->last_value].offset >
2397 packetizer->offset) {
2398 GST_DEBUG ("PTS is %" GST_TIME_FORMAT " into group",
2399 GST_TIME_ARGS (pts - PCRTIME_TO_GSTTIME (group->first_pcr)));
2400 break;
2401 }
2402 }
2403 if (group && !(group->flags & PCR_GROUP_FLAG_RESET)) {
2404 GST_DEBUG ("Using group !");
2405 refpcr = group->first_pcr;
2406 refpcroffset = group->pcr_offset;
2407 if (pts < PCRTIME_TO_GSTTIME (refpcr)) {
2408 if (PCRTIME_TO_GSTTIME (refpcr) - pts > GST_SECOND)
2409 pts += PCR_GST_MAX_VALUE;
2410 else
2411 refpcr = G_MAXINT64;
2412 }
2413 }
2414 }
2415 if (refpcr != G_MAXINT64)
2416 res =
2417 pts - PCRTIME_TO_GSTTIME (refpcr) + PCRTIME_TO_GSTTIME (refpcroffset);
bo.xiao55ff0172024-08-12 16:18:03 +08002418 else
2419 GST_WARNING ("No groups, can't calculate timestamp");
2420 } else {
2421 //case: valid pcr after frame, patch 0045-SWPL-124457-set-base-pcr
2422 if (!GST_CLOCK_TIME_IS_VALID (pcrtable->base_pcrtime) && GST_CLOCK_TIME_IS_VALID (pts) && pcr_pid != 0x1fff && \
hanghang.luo4be9bc82024-06-04 17:10:39 +08002423 !GST_CLOCK_TIME_IS_VALID (pcrtable->base_time) && GST_CLOCK_TIME_IS_VALID (packetizer->last_in_time)) {
bo.xiao55ff0172024-08-12 16:18:03 +08002424 GST_WARNING ("set pcr base time %" GST_TIME_FORMAT " base time %" GST_TIME_FORMAT, GST_TIME_ARGS (pts), GST_TIME_ARGS (packetizer->last_in_time));
2425 pcrtable->base_time = packetizer->last_in_time;
2426 pcrtable->base_pcrtime = pts;
hanghang.luo4be9bc82024-06-04 17:10:39 +08002427 }
bo.xiao55ff0172024-08-12 16:18:03 +08002428 //AML MOD FLOW patch 0016-Discard-ts-pcr
2429 GST_WARNING ("Not enough information to calculate proper timestamp use origin pts %" GST_TIME_FORMAT, GST_TIME_ARGS (pts));
2430 res = pts;
2431 }
2432
hanghang.luofa7b16f2024-05-31 14:44:31 +08002433
2434 PACKETIZER_GROUP_UNLOCK (packetizer);
2435
2436 GST_DEBUG ("Returning timestamp %" GST_TIME_FORMAT " for pts %"
2437 GST_TIME_FORMAT " pcr_pid:0x%04x", GST_TIME_ARGS (res),
2438 GST_TIME_ARGS (pts), pcr_pid);
2439 return res;
2440}
2441
2442/* Stream time to offset */
2443guint64
2444amlts_packetizer_ts_to_offset (AmlTSPacketizer2 * packetizer,
2445 GstClockTime ts, guint16 pcr_pid)
2446{
2447 AmlTSPCR *pcrtable;
2448 guint64 res;
2449 PCROffsetGroup *nextgroup = NULL, *prevgroup = NULL;
2450 guint64 querypcr, firstpcr, lastpcr, firstoffset, lastoffset;
2451 PCROffsetCurrent *current;
2452 GList *tmp;
2453
2454 if (!packetizer->calculate_offset)
2455 return -1;
2456
2457 PACKETIZER_GROUP_LOCK (packetizer);
bo.xiaoff2de692024-08-07 14:38:55 +08002458 pcrtable = aml_get_pcr_table (packetizer, pcr_pid);
hanghang.luofa7b16f2024-05-31 14:44:31 +08002459
2460 if (pcrtable->groups == NULL) {
2461 PACKETIZER_GROUP_UNLOCK (packetizer);
2462 return -1;
2463 }
2464
2465 querypcr = GSTTIME_TO_PCRTIME (ts);
2466
2467 GST_DEBUG ("Searching offset for ts %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
2468
2469 /* First check if we're within the current pending group */
2470 current = pcrtable->current;
2471 if (current && current->group && (querypcr >= current->group->pcr_offset) &&
2472 querypcr - current->group->pcr_offset <=
2473 current->pending[current->last].pcr) {
2474 GST_DEBUG ("pcr is in current group");
2475 nextgroup = current->group;
2476 goto calculate_points;
2477 }
2478
2479 /* Find the neighbouring groups */
2480 for (tmp = pcrtable->groups; tmp; tmp = tmp->next) {
2481 nextgroup = (PCROffsetGroup *) tmp->data;
2482
2483 GST_DEBUG ("Trying group PCR %" GST_TIME_FORMAT " (offset %"
2484 G_GUINT64_FORMAT " pcr_offset %" GST_TIME_FORMAT,
2485 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (nextgroup->first_pcr)),
2486 nextgroup->first_offset,
2487 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (nextgroup->pcr_offset)));
2488
2489 /* Check if we've gone too far */
2490 if (nextgroup->pcr_offset > querypcr) {
2491 GST_DEBUG ("pcr is before that group");
2492 break;
2493 }
2494
2495 if (tmp->next == NULL) {
2496 GST_DEBUG ("pcr is beyond last group");
2497 break;
2498 }
2499
2500 prevgroup = nextgroup;
2501
2502 /* Maybe it's in this group */
2503 if (nextgroup->values[nextgroup->last_value].pcr +
2504 nextgroup->pcr_offset >= querypcr) {
2505 GST_DEBUG ("pcr is in that group");
2506 break;
2507 }
2508 }
2509
2510calculate_points:
2511
2512 GST_DEBUG ("nextgroup:%p, prevgroup:%p", nextgroup, prevgroup);
2513
2514 if (nextgroup == prevgroup || prevgroup == NULL) {
2515 /* We use the current group to calculate position:
2516 * * if the PCR is within this group
2517 * * if there is only one group to use for calculation
2518 */
2519 GST_DEBUG ("In group or after last one");
2520 lastoffset = firstoffset = nextgroup->first_offset;
2521 lastpcr = firstpcr = nextgroup->pcr_offset;
2522 if (current && nextgroup == current->group) {
2523 lastoffset += current->pending[current->last].offset;
2524 lastpcr += current->pending[current->last].pcr;
2525 } else {
2526 lastoffset += nextgroup->values[nextgroup->last_value].offset;
2527 lastpcr += nextgroup->values[nextgroup->last_value].pcr;
2528 }
2529 } else {
2530 GST_DEBUG ("Between group");
2531 lastoffset = nextgroup->first_offset;
2532 lastpcr = nextgroup->pcr_offset;
2533 firstoffset =
2534 prevgroup->values[prevgroup->last_value].offset +
2535 prevgroup->first_offset;
2536 firstpcr =
2537 prevgroup->values[prevgroup->last_value].pcr + prevgroup->pcr_offset;
2538 }
2539
2540 PACKETIZER_GROUP_UNLOCK (packetizer);
2541
2542 GST_DEBUG ("Using prev PCR %" G_GUINT64_FORMAT " offset %" G_GUINT64_FORMAT,
2543 firstpcr, firstoffset);
2544 GST_DEBUG ("Using last PCR %" G_GUINT64_FORMAT " offset %" G_GUINT64_FORMAT,
2545 lastpcr, lastoffset);
2546
2547 res = firstoffset;
bo.xiao6f525042024-08-08 17:34:40 +08002548 if (lastpcr != firstpcr && querypcr > firstpcr)
hanghang.luofa7b16f2024-05-31 14:44:31 +08002549 res += gst_util_uint64_scale (querypcr - firstpcr,
2550 lastoffset - firstoffset, lastpcr - firstpcr);
2551
2552 GST_DEBUG ("Returning offset %" G_GUINT64_FORMAT " for ts %"
2553 GST_TIME_FORMAT, res, GST_TIME_ARGS (ts));
2554
2555 return res;
2556}
2557
2558void
2559amlts_packetizer_set_reference_offset (AmlTSPacketizer2 * packetizer,
2560 guint64 refoffset)
2561{
2562 GST_DEBUG ("Setting reference offset to %" G_GUINT64_FORMAT, refoffset);
2563
2564 PACKETIZER_GROUP_LOCK (packetizer);
2565 packetizer->refoffset = refoffset;
2566 PACKETIZER_GROUP_UNLOCK (packetizer);
2567}
2568
2569void
2570amlts_packetizer_set_pcr_discont_threshold (AmlTSPacketizer2 * packetizer,
2571 GstClockTime threshold)
2572{
2573 PACKETIZER_GROUP_LOCK (packetizer);
2574 packetizer->pcr_discont_threshold = threshold;
2575 PACKETIZER_GROUP_UNLOCK (packetizer);
2576}
2577
2578void
2579amlts_packetizer_set_current_pcr_offset (AmlTSPacketizer2 * packetizer,
2580 GstClockTime offset, guint16 pcr_pid)
2581{
2582 guint64 pcr_offset;
2583 gint64 delta;
2584 AmlTSPCR *pcrtable;
2585 PCROffsetGroup *group;
2586 GList *tmp;
2587 gboolean apply = FALSE;
2588
2589 /* fast path */
2590 PACKETIZER_GROUP_LOCK (packetizer);
bo.xiaoff2de692024-08-07 14:38:55 +08002591 pcrtable = aml_get_pcr_table (packetizer, pcr_pid);
hanghang.luofa7b16f2024-05-31 14:44:31 +08002592
2593 if (pcrtable == NULL || pcrtable->current->group == NULL) {
2594 PACKETIZER_GROUP_UNLOCK (packetizer);
2595 return;
2596 }
2597
2598 pcr_offset = GSTTIME_TO_PCRTIME (offset);
2599
2600 /* Pick delta from *first* group */
2601 if (pcrtable->groups)
2602 group = pcrtable->groups->data;
2603 else
2604 group = pcrtable->current->group;
2605 GST_DEBUG ("Current group PCR %" GST_TIME_FORMAT " (offset %"
2606 G_GUINT64_FORMAT " pcr_offset %" GST_TIME_FORMAT,
2607 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->first_pcr)),
2608 group->first_offset,
2609 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (group->pcr_offset)));
2610
2611 /* Remember the difference between previous initial pcr_offset and
2612 * new initial pcr_offset */
2613 delta = pcr_offset - group->pcr_offset;
2614 if (delta == 0) {
2615 GST_DEBUG ("No shift to apply");
2616 PACKETIZER_GROUP_UNLOCK (packetizer);
2617 return;
2618 }
2619 GST_DEBUG ("Shifting groups by %" GST_TIME_FORMAT
2620 " for new initial pcr_offset %" GST_TIME_FORMAT,
2621 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (delta)), GST_TIME_ARGS (offset));
2622
2623 for (tmp = pcrtable->groups; tmp; tmp = tmp->next) {
2624 PCROffsetGroup *tgroup = (tmp->data);
2625 if (tgroup == group)
2626 apply = TRUE;
2627 if (apply) {
2628 tgroup->pcr_offset += delta;
2629 GST_DEBUG ("Update group PCR %" GST_TIME_FORMAT " (offset %"
2630 G_GUINT64_FORMAT " pcr_offset %" GST_TIME_FORMAT,
2631 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (tgroup->first_pcr)),
2632 tgroup->first_offset,
2633 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (tgroup->pcr_offset)));
2634 } else
2635 GST_DEBUG ("Not modifying group PCR %" GST_TIME_FORMAT " (offset %"
2636 G_GUINT64_FORMAT " pcr_offset %" GST_TIME_FORMAT,
2637 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (tgroup->first_pcr)),
2638 tgroup->first_offset,
2639 GST_TIME_ARGS (PCRTIME_TO_GSTTIME (tgroup->pcr_offset)));
2640 }
2641 PACKETIZER_GROUP_UNLOCK (packetizer);
2642}