1
|
/**
|
2
|
* Timestamp fixup
|
3
|
* Copyright (C) 2010 Andreas Öman
|
4
|
*
|
5
|
* This program is free software: you can redistribute it and/or modify
|
6
|
* it under the terms of the GNU General Public License as published by
|
7
|
* the Free Software Foundation, either version 3 of the License, or
|
8
|
* (at your option) any later version.
|
9
|
*
|
10
|
* This program is distributed in the hope that it will be useful,
|
11
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
* GNU General Public License for more details.
|
14
|
*
|
15
|
* You should have received a copy of the GNU General Public License
|
16
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
*/
|
18
|
|
19
|
#include "tvheadend.h"
|
20
|
#include "streaming.h"
|
21
|
#include "tsfix.h"
|
22
|
|
23
|
#define REF_OK 0
|
24
|
#define REF_ERROR 1
|
25
|
#define REF_DROP 2
|
26
|
|
27
|
LIST_HEAD(tfstream_list, tfstream);
|
28
|
|
29
|
/**
|
30
|
*
|
31
|
*/
|
32
|
typedef struct tfstream {
|
33
|
|
34
|
LIST_ENTRY(tfstream) tfs_link;
|
35
|
|
36
|
int tfs_index;
|
37
|
|
38
|
streaming_component_type_t tfs_type;
|
39
|
uint8_t tfs_video;
|
40
|
uint8_t tfs_audio;
|
41
|
uint8_t tfs_subtitle;
|
42
|
|
43
|
int tfs_bad_dts;
|
44
|
int64_t tfs_local_ref;
|
45
|
int64_t tfs_last_dts_norm;
|
46
|
int64_t tfs_dts_epoch;
|
47
|
|
48
|
int64_t tfs_last_dts_in;
|
49
|
|
50
|
int tfs_seen;
|
51
|
|
52
|
struct tfstream *tfs_parent;
|
53
|
|
54
|
} tfstream_t;
|
55
|
|
56
|
|
57
|
/**
|
58
|
*
|
59
|
*/
|
60
|
typedef struct tsfix {
|
61
|
streaming_target_t tf_input;
|
62
|
|
63
|
streaming_target_t *tf_output;
|
64
|
|
65
|
struct tfstream_list tf_streams;
|
66
|
int tf_hasvideo;
|
67
|
int tf_wait_for_video;
|
68
|
int64_t tf_tsref;
|
69
|
int64_t tf_start_time;
|
70
|
int64_t dts_offset;
|
71
|
int dts_offset_apply;
|
72
|
|
73
|
struct th_pktref_queue tf_ptsq;
|
74
|
struct th_pktref_queue tf_backlog;
|
75
|
|
76
|
} tsfix_t;
|
77
|
|
78
|
|
79
|
/**
|
80
|
* Compute the timestamp deltas
|
81
|
*/
|
82
|
static int64_t
|
83
|
tsfix_ts_diff(int64_t ts1, int64_t ts2)
|
84
|
{
|
85
|
int64_t r;
|
86
|
ts1 &= PTS_MASK;
|
87
|
ts2 &= PTS_MASK;
|
88
|
|
89
|
r = llabs(ts1 - ts2);
|
90
|
if (r > (PTS_MASK / 2)) {
|
91
|
/* try to wrap the lowest value */
|
92
|
if (ts1 < ts2)
|
93
|
ts1 += PTS_MASK + 1;
|
94
|
else
|
95
|
ts2 += PTS_MASK + 1;
|
96
|
return llabs(ts1 - ts2);
|
97
|
}
|
98
|
return r;
|
99
|
}
|
100
|
|
101
|
/**
|
102
|
*
|
103
|
*/
|
104
|
static void
|
105
|
tsfix_destroy_streams(tsfix_t *tf)
|
106
|
{
|
107
|
tfstream_t *tfs;
|
108
|
pktref_clear_queue(&tf->tf_ptsq);
|
109
|
pktref_clear_queue(&tf->tf_backlog);
|
110
|
while((tfs = LIST_FIRST(&tf->tf_streams)) != NULL) {
|
111
|
LIST_REMOVE(tfs, tfs_link);
|
112
|
free(tfs);
|
113
|
}
|
114
|
}
|
115
|
|
116
|
|
117
|
static tfstream_t *
|
118
|
tfs_find(tsfix_t *tf, th_pkt_t *pkt)
|
119
|
{
|
120
|
tfstream_t *tfs;
|
121
|
LIST_FOREACH(tfs, &tf->tf_streams, tfs_link)
|
122
|
if(pkt->pkt_componentindex == tfs->tfs_index)
|
123
|
break;
|
124
|
return tfs;
|
125
|
}
|
126
|
|
127
|
/**
|
128
|
*
|
129
|
*/
|
130
|
static tfstream_t *
|
131
|
tsfix_add_stream(tsfix_t *tf, int index, streaming_component_type_t type)
|
132
|
{
|
133
|
tfstream_t *tfs = calloc(1, sizeof(tfstream_t));
|
134
|
|
135
|
tfs->tfs_type = type;
|
136
|
if (SCT_ISVIDEO(type))
|
137
|
tfs->tfs_video = 1;
|
138
|
else if (SCT_ISAUDIO(type))
|
139
|
tfs->tfs_audio = 1;
|
140
|
else if (SCT_ISSUBTITLE(type))
|
141
|
tfs->tfs_subtitle = 1;
|
142
|
|
143
|
tfs->tfs_index = index;
|
144
|
tfs->tfs_local_ref = PTS_UNSET;
|
145
|
tfs->tfs_last_dts_norm = PTS_UNSET;
|
146
|
tfs->tfs_last_dts_in = PTS_UNSET;
|
147
|
tfs->tfs_dts_epoch = 0;
|
148
|
tfs->tfs_seen = 0;
|
149
|
|
150
|
LIST_INSERT_HEAD(&tf->tf_streams, tfs, tfs_link);
|
151
|
return tfs;
|
152
|
}
|
153
|
|
154
|
|
155
|
/**
|
156
|
*
|
157
|
*/
|
158
|
static void
|
159
|
tsfix_start(tsfix_t *tf, streaming_start_t *ss)
|
160
|
{
|
161
|
int i, hasvideo = 0, vwait = 0;
|
162
|
tfstream_t *tfs;
|
163
|
|
164
|
for(i = 0; i < ss->ss_num_components; i++) {
|
165
|
const streaming_start_component_t *ssc = &ss->ss_components[i];
|
166
|
tfs = tsfix_add_stream(tf, ssc->es_index, ssc->es_type);
|
167
|
if (tfs->tfs_video) {
|
168
|
if (ssc->es_width == 0 || ssc->es_height == 0)
|
169
|
/* only first video stream may be valid */
|
170
|
vwait = !hasvideo ? 1 : 0;
|
171
|
hasvideo = 1;
|
172
|
}
|
173
|
}
|
174
|
|
175
|
TAILQ_INIT(&tf->tf_ptsq);
|
176
|
TAILQ_INIT(&tf->tf_backlog);
|
177
|
|
178
|
tf->tf_tsref = PTS_UNSET;
|
179
|
tf->tf_hasvideo = hasvideo;
|
180
|
tf->tf_wait_for_video = vwait;
|
181
|
}
|
182
|
|
183
|
|
184
|
/**
|
185
|
*
|
186
|
*/
|
187
|
static void
|
188
|
tsfix_stop(tsfix_t *tf)
|
189
|
{
|
190
|
tsfix_destroy_streams(tf);
|
191
|
}
|
192
|
|
193
|
|
194
|
/**
|
195
|
*
|
196
|
*/
|
197
|
static void
|
198
|
tsfix_packet_drop(tfstream_t *tfs, th_pkt_t *pkt, const char *reason)
|
199
|
{
|
200
|
if (tvhtrace_enabled()) {
|
201
|
char buf[64];
|
202
|
snprintf(buf, sizeof(buf), "drop %s", reason);
|
203
|
pkt_trace(LS_TSFIX, pkt, buf);
|
204
|
}
|
205
|
pkt_ref_dec(pkt);
|
206
|
}
|
207
|
|
208
|
/**
|
209
|
*
|
210
|
*/
|
211
|
static void
|
212
|
normalize_ts(tsfix_t *tf, tfstream_t *tfs, th_pkt_t *pkt, int backlog)
|
213
|
{
|
214
|
int64_t ref, dts, odts, opts, d;
|
215
|
|
216
|
if(tf->tf_tsref == PTS_UNSET) {
|
217
|
if (backlog) {
|
218
|
if (pkt->pkt_dts != PTS_UNSET)
|
219
|
tfs->tfs_seen = 1;
|
220
|
pktref_enqueue(&tf->tf_backlog, pkt);
|
221
|
} else
|
222
|
pkt_ref_dec(pkt);
|
223
|
return;
|
224
|
}
|
225
|
|
226
|
ref = tfs->tfs_local_ref != PTS_UNSET ? tfs->tfs_local_ref : tf->tf_tsref;
|
227
|
odts = pkt->pkt_dts;
|
228
|
opts = pkt->pkt_pts;
|
229
|
|
230
|
if (pkt->pkt_dts == PTS_UNSET) {
|
231
|
if (pkt->pkt_pts != PTS_UNSET)
|
232
|
pkt->pkt_dts = pkt->pkt_pts;
|
233
|
else
|
234
|
goto deliver;
|
235
|
}
|
236
|
|
237
|
pkt->pkt_dts &= PTS_MASK;
|
238
|
|
239
|
/* Subtract the transport wide start offset */
|
240
|
if (tf->dts_offset_apply)
|
241
|
dts = pts_diff(ref, pkt->pkt_dts + tf->dts_offset);
|
242
|
else
|
243
|
dts = pts_diff(ref, pkt->pkt_dts);
|
244
|
|
245
|
if (tfs->tfs_last_dts_norm == PTS_UNSET) {
|
246
|
if (dts < 0 || pkt->pkt_err) {
|
247
|
/* Early packet with negative time stamp, drop those */
|
248
|
tsfix_packet_drop(tfs, pkt, "negative/error");
|
249
|
return;
|
250
|
}
|
251
|
} else {
|
252
|
const int64_t nlimit = -1; /* allow negative values - rounding errors? */
|
253
|
int64_t low = 90000; /* one second */
|
254
|
int64_t upper = 2*90000; /* two seconds */
|
255
|
d = dts + tfs->tfs_dts_epoch - tfs->tfs_last_dts_norm;
|
256
|
|
257
|
if (tfs->tfs_subtitle) {
|
258
|
/*
|
259
|
* special conditions for subtitles, because they may be broadcasted
|
260
|
* with large time gaps
|
261
|
*/
|
262
|
low = PTS_MASK / 2; /* more than 13 hours */
|
263
|
upper = low - 1;
|
264
|
}
|
265
|
|
266
|
if (d < nlimit || d > low) {
|
267
|
if (d < -PTS_MASK || d > -PTS_MASK + upper) {
|
268
|
if (pkt->pkt_err) {
|
269
|
tsfix_packet_drop(tfs, pkt, "possible wrong discontinuity");
|
270
|
return;
|
271
|
}
|
272
|
tfs->tfs_bad_dts++;
|
273
|
if (tfs->tfs_bad_dts < 5) {
|
274
|
tvhwarn(LS_TSFIX,
|
275
|
"transport stream %s, DTS discontinuity. "
|
276
|
"DTS = %" PRId64 ", last = %" PRId64,
|
277
|
streaming_component_type2txt(tfs->tfs_type),
|
278
|
dts, tfs->tfs_last_dts_norm);
|
279
|
}
|
280
|
} else {
|
281
|
/* DTS wrapped, increase upper bits */
|
282
|
tfs->tfs_dts_epoch += PTS_MASK + 1;
|
283
|
tfs->tfs_bad_dts = 0;
|
284
|
}
|
285
|
} else {
|
286
|
tfs->tfs_bad_dts = 0;
|
287
|
}
|
288
|
}
|
289
|
|
290
|
dts += tfs->tfs_dts_epoch;
|
291
|
tfs->tfs_last_dts_norm = dts;
|
292
|
|
293
|
if(pkt->pkt_pts != PTS_UNSET) {
|
294
|
/* Compute delta between PTS and DTS (and watch out for 33 bit wrap) */
|
295
|
d = ((pkt->pkt_pts & PTS_MASK) - pkt->pkt_dts) & PTS_MASK;
|
296
|
pkt->pkt_pts = dts + d;
|
297
|
}
|
298
|
if(pkt->pkt_pcr != PTS_UNSET) {
|
299
|
/* Compute delta between PCR and DTS (and watch out for 33 bit wrap) */
|
300
|
d = ((pkt->pkt_pcr & PTS_MASK) - pkt->pkt_dts) & PTS_MASK;
|
301
|
if (d > PTS_MASK / 2)
|
302
|
d = -(PTS_MASK - d);
|
303
|
pkt->pkt_pcr = dts + d;
|
304
|
}
|
305
|
|
306
|
pkt->pkt_dts = dts;
|
307
|
|
308
|
if (pkt->pkt_pts < 0 || pkt->pkt_dts < 0 || pkt->pkt_pcr < 0) {
|
309
|
tsfix_packet_drop(tfs, pkt, "negative2/error");
|
310
|
return;
|
311
|
}
|
312
|
|
313
|
deliver:
|
314
|
if (tvhtrace_enabled()) {
|
315
|
char _odts[22], _opts[22];
|
316
|
pkt_trace(LS_TSFIX, pkt,
|
317
|
"deliver odts %s opts %s ref %"PRId64" epoch %"PRId64,
|
318
|
pts_to_string(odts, _odts), pts_to_string(opts, _opts),
|
319
|
ref, tfs->tfs_dts_epoch);
|
320
|
}
|
321
|
|
322
|
streaming_message_t *sm = streaming_msg_create_pkt(pkt);
|
323
|
streaming_target_deliver2(tf->tf_output, sm);
|
324
|
pkt_ref_dec(pkt);
|
325
|
}
|
326
|
|
327
|
/**
|
328
|
*
|
329
|
*/
|
330
|
static inline int
|
331
|
txfix_need_to_update_ref(tsfix_t *tf, tfstream_t *tfs, th_pkt_t *pkt)
|
332
|
{
|
333
|
return tfs->tfs_local_ref == PTS_UNSET &&
|
334
|
tf->tf_tsref != PTS_UNSET &&
|
335
|
pkt->pkt_dts != PTS_UNSET;
|
336
|
}
|
337
|
|
338
|
/**
|
339
|
*
|
340
|
*/
|
341
|
static int
|
342
|
tsfix_update_ref(tsfix_t *tf, tfstream_t *tfs, th_pkt_t *pkt)
|
343
|
{
|
344
|
tfstream_t *tfs2;
|
345
|
int64_t diff;
|
346
|
|
347
|
if (pkt->pkt_err)
|
348
|
return REF_ERROR;
|
349
|
|
350
|
if (tfs->tfs_audio) {
|
351
|
diff = tsfix_ts_diff(tf->tf_tsref, pkt->pkt_dts);
|
352
|
if (diff > 3 * 90000) {
|
353
|
tvhwarn(LS_TSFIX, "The timediff for %s is big (%"PRId64"), using current dts",
|
354
|
streaming_component_type2txt(tfs->tfs_type), diff);
|
355
|
tfs->tfs_local_ref = pkt->pkt_dts;
|
356
|
} else {
|
357
|
tfs->tfs_local_ref = tf->tf_tsref;
|
358
|
}
|
359
|
} else if (tfs->tfs_type == SCT_DVBSUB || tfs->tfs_type == SCT_TEXTSUB) {
|
360
|
/* find first valid audio stream and check the dts timediffs */
|
361
|
LIST_FOREACH(tfs2, &tf->tf_streams, tfs_link)
|
362
|
if (tfs2->tfs_audio && tfs2->tfs_last_dts_in != PTS_UNSET) {
|
363
|
diff = tsfix_ts_diff(tfs2->tfs_last_dts_in, pkt->pkt_dts);
|
364
|
/*if (diff > 6 * 90000) {
|
365
|
tvhwarn(LS_TSFIX, "The timediff for %s is big (%"PRId64"), using audio dts",
|
366
|
streaming_component_type2txt(tfs->tfs_type), diff);
|
367
|
tfs->tfs_parent = tfs2;
|
368
|
tfs->tfs_local_ref = tfs2->tfs_local_ref;
|
369
|
} else {
|
370
|
tfs->tfs_local_ref = tf->tf_tsref;
|
371
|
}*/
|
372
|
tfs->tfs_local_ref = tf->tf_tsref;
|
373
|
break;
|
374
|
}
|
375
|
if (tfs2 == NULL)
|
376
|
return REF_DROP;
|
377
|
} else if (tfs->tfs_type == SCT_TELETEXT) {
|
378
|
diff = tsfix_ts_diff(tf->tf_tsref, pkt->pkt_dts);
|
379
|
if (diff > 2 * 90000) {
|
380
|
tvhwarn(LS_TSFIX, "The timediff for TELETEXT is big (%"PRId64"), using current dts", diff);
|
381
|
tfs->tfs_local_ref = pkt->pkt_dts;
|
382
|
} else {
|
383
|
tfs->tfs_local_ref = tf->tf_tsref;
|
384
|
}
|
385
|
}
|
386
|
return REF_OK;
|
387
|
}
|
388
|
|
389
|
/**
|
390
|
*
|
391
|
*/
|
392
|
static void
|
393
|
tsfix_backlog(tsfix_t *tf)
|
394
|
{
|
395
|
th_pkt_t *pkt;
|
396
|
tfstream_t *tfs;
|
397
|
int r;
|
398
|
|
399
|
while((pkt = pktref_get_first(&tf->tf_backlog)) != NULL) {
|
400
|
tfs = tfs_find(tf, pkt);
|
401
|
if (txfix_need_to_update_ref(tf, tfs, pkt)) {
|
402
|
r = tsfix_update_ref(tf, tfs, pkt);
|
403
|
if (r != REF_OK) {
|
404
|
tsfix_packet_drop(tfs, pkt, r == REF_ERROR ? "bckle" : "bckld");
|
405
|
continue;
|
406
|
}
|
407
|
}
|
408
|
normalize_ts(tf, tfs, pkt, 0);
|
409
|
}
|
410
|
}
|
411
|
|
412
|
|
413
|
/**
|
414
|
*
|
415
|
*/
|
416
|
static int64_t
|
417
|
tsfix_backlog_diff(tsfix_t *tf)
|
418
|
{
|
419
|
th_pkt_t *pkt;
|
420
|
th_pktref_t *pr;
|
421
|
tfstream_t *tfs;
|
422
|
int64_t res = 0;
|
423
|
|
424
|
PKTREF_FOREACH(pr, &tf->tf_backlog) {
|
425
|
pkt = pr->pr_pkt;
|
426
|
if (pkt->pkt_dts == PTS_UNSET) continue;
|
427
|
if (pkt->pkt_dts >= tf->tf_tsref) continue;
|
428
|
if (tf->tf_tsref > (PTS_MASK * 3) / 4 &&
|
429
|
pkt->pkt_dts < PTS_MASK / 4) continue;
|
430
|
tfs = tfs_find(tf, pkt);
|
431
|
if (!tfs->tfs_audio && !tfs->tfs_video) continue;
|
432
|
res = MAX(tsfix_ts_diff(pkt->pkt_dts, tf->tf_tsref), res);
|
433
|
}
|
434
|
return res;
|
435
|
}
|
436
|
|
437
|
|
438
|
/**
|
439
|
*
|
440
|
* Recover unset PTS.
|
441
|
*
|
442
|
* MPEG2 DTS/PTS example (rpts = result pts):
|
443
|
* 01: I dts 4922701936 pts 4922712736 rpts 4922712736
|
444
|
* 02: B dts 4922705536 pts <unset> rpts 4922705536
|
445
|
* 03: B dts 4922709136 pts <unset> rpts 4922709136
|
446
|
* 04: P dts 4922712736 pts <unset> rpts 4922723536
|
447
|
* 05: B dts 4922716336 pts <unset> rpts 4922716336
|
448
|
* 06: B dts 4922719936 pts <unset> rpts 4922719936
|
449
|
* 07: P dts 4922723536 pts <unset> rpts 4922734336
|
450
|
* 08: B dts 4922727136 pts <unset> rpts 4922727136
|
451
|
* 09: B dts 4922730736 pts <unset> rpts 4922730736
|
452
|
* 10: P dts 4922734336 pts <unset> rpts 4922745136
|
453
|
* 11: B dts 4922737936 pts <unset> rpts 4922737936
|
454
|
* 12: B dts 4922741536 pts <unset> rpts 4922741536
|
455
|
* 13: I dts 4922745136 pts 4922755936 rpts 4922755936
|
456
|
*/
|
457
|
static void
|
458
|
recover_pts(tsfix_t *tf, tfstream_t *tfs, th_pkt_t *pkt)
|
459
|
{
|
460
|
th_pktref_t *srch;
|
461
|
int total;
|
462
|
|
463
|
pktref_enqueue(&tf->tf_ptsq, pkt);
|
464
|
while((pkt = pktref_get_first(&tf->tf_ptsq)) != NULL) {
|
465
|
tfs = tfs_find(tf, pkt);
|
466
|
|
467
|
switch(tfs->tfs_type) {
|
468
|
|
469
|
case SCT_MPEG2VIDEO:
|
470
|
|
471
|
switch(pkt->v.pkt_frametype) {
|
472
|
case PKT_B_FRAME:
|
473
|
if (pkt->pkt_pts == PTS_UNSET) {
|
474
|
/* B-frames have same PTS as DTS, pass them on */
|
475
|
tvhtrace(LS_TSFIX, "%-12s PTS b-frame set to %"PRId64" (old %"PRId64")",
|
476
|
streaming_component_type2txt(tfs->tfs_type),
|
477
|
pkt->pkt_dts, pkt->pkt_pts);
|
478
|
pkt->pkt_pts = pkt->pkt_dts;
|
479
|
}
|
480
|
break;
|
481
|
|
482
|
case PKT_I_FRAME:
|
483
|
case PKT_P_FRAME:
|
484
|
if (pkt->pkt_pts == PTS_UNSET) {
|
485
|
/* Presentation occures at DTS of next I or P frame,
|
486
|
try to find it */
|
487
|
total = 0;
|
488
|
PKTREF_FOREACH(srch, &tf->tf_ptsq) {
|
489
|
if (pkt->pkt_componentindex != tfs->tfs_index)
|
490
|
continue;
|
491
|
total++;
|
492
|
if (srch->pr_pkt->v.pkt_frametype <= PKT_P_FRAME &&
|
493
|
pts_is_greater_or_equal(pkt->pkt_dts, srch->pr_pkt->pkt_dts) > 0 &&
|
494
|
pts_diff(pkt->pkt_dts, srch->pr_pkt->pkt_dts) < 10 * 90000) {
|
495
|
tvhtrace(LS_TSFIX, "%-12s PTS *-frame set to %"PRId64" (old %"PRId64"), DTS %"PRId64,
|
496
|
streaming_component_type2txt(tfs->tfs_type),
|
497
|
srch->pr_pkt->pkt_dts, pkt->pkt_pts, pkt->pkt_dts);
|
498
|
pkt->pkt_pts = srch->pr_pkt->pkt_dts;
|
499
|
break;
|
500
|
}
|
501
|
}
|
502
|
if (srch == NULL) {
|
503
|
if (total < 50) {
|
504
|
/* return packet back to tf_ptsq */
|
505
|
pktref_insert_head(&tf->tf_ptsq, pkt);
|
506
|
} else {
|
507
|
tsfix_packet_drop(tfs, pkt, "mpeg2video overflow");
|
508
|
}
|
509
|
return; /* not arrived yet or invalid, wait */
|
510
|
}
|
511
|
}
|
512
|
}
|
513
|
break;
|
514
|
|
515
|
default:
|
516
|
break;
|
517
|
}
|
518
|
|
519
|
normalize_ts(tf, tfs, pkt, 1);
|
520
|
}
|
521
|
}
|
522
|
|
523
|
|
524
|
/**
|
525
|
* Compute PTS (if not known)
|
526
|
*/
|
527
|
static void
|
528
|
compute_pts(tsfix_t *tf, tfstream_t *tfs, th_pkt_t *pkt)
|
529
|
{
|
530
|
// If PTS is missing, set it to DTS if not video
|
531
|
if(pkt->pkt_pts == PTS_UNSET && !tfs->tfs_video) {
|
532
|
pkt->pkt_pts = pkt->pkt_dts;
|
533
|
tvhtrace(LS_TSFIX, "%-12s PTS set to %"PRId64,
|
534
|
streaming_component_type2txt(tfs->tfs_type),
|
535
|
pkt->pkt_pts);
|
536
|
}
|
537
|
|
538
|
/* PTS known and no other packets in queue, deliver at once */
|
539
|
if(pkt->pkt_pts != PTS_UNSET && TAILQ_FIRST(&tf->tf_ptsq) == NULL)
|
540
|
normalize_ts(tf, tfs, pkt, 1);
|
541
|
else
|
542
|
recover_pts(tf, tfs, pkt);
|
543
|
}
|
544
|
|
545
|
|
546
|
/**
|
547
|
*
|
548
|
*/
|
549
|
static void
|
550
|
tsfix_input_packet(tsfix_t *tf, streaming_message_t *sm)
|
551
|
{
|
552
|
th_pkt_t *pkt;
|
553
|
tfstream_t *tfs, *tfs2;
|
554
|
int64_t diff, diff2, threshold;
|
555
|
int r;
|
556
|
|
557
|
pkt = pkt_copy_shallow(sm->sm_data);
|
558
|
tfs = tfs_find(tf, pkt);
|
559
|
streaming_msg_free(sm);
|
560
|
|
561
|
if (tfs == NULL || mclk() < tf->tf_start_time) {
|
562
|
tsfix_packet_drop(tfs, pkt, "start time");
|
563
|
return;
|
564
|
}
|
565
|
|
566
|
if (tf->tf_tsref == PTS_UNSET && pkt->pkt_dts != PTS_UNSET &&
|
567
|
((!tf->tf_hasvideo && tfs->tfs_audio) ||
|
568
|
(tfs->tfs_video && pkt->v.pkt_frametype == PKT_I_FRAME))) {
|
569
|
if (pkt->pkt_err) {
|
570
|
tsfix_packet_drop(tfs, pkt, "ref1");
|
571
|
return;
|
572
|
}
|
573
|
threshold = 22500;
|
574
|
LIST_FOREACH(tfs2, &tf->tf_streams, tfs_link)
|
575
|
if (tfs != tfs2 && (tfs2->tfs_audio || tfs2->tfs_video) && !tfs2->tfs_seen) {
|
576
|
threshold = 90000;
|
577
|
break;
|
578
|
}
|
579
|
tf->tf_tsref = pkt->pkt_dts & PTS_MASK;
|
580
|
if (pts_is_greater_or_equal(pkt->pkt_pcr, pkt->pkt_dts) > 0)
|
581
|
tf->tf_tsref = pkt->pkt_pcr & PTS_MASK;
|
582
|
diff = diff2 = tsfix_backlog_diff(tf);
|
583
|
if (diff > threshold) {
|
584
|
if (diff > 160000)
|
585
|
diff = 160000;
|
586
|
tf->tf_tsref = (tf->tf_tsref - diff) % PTS_MASK;
|
587
|
tvhtrace(LS_TSFIX, "reference clock set to %"PRId64" (dts %"PRId64" pcr %"PRId64" backlog %"PRId64")", tf->tf_tsref, pkt->pkt_dts, pkt->pkt_pcr, diff2);
|
588
|
tsfix_backlog(tf);
|
589
|
} else {
|
590
|
tvhtrace(LS_TSFIX, "reference clock set to %"PRId64" (dts %"PRId64" pcr %"PRId64" backlog %"PRId64")", tf->tf_tsref, pkt->pkt_dts, pkt->pkt_pcr, diff2);
|
591
|
}
|
592
|
} else if (txfix_need_to_update_ref(tf, tfs, pkt)) {
|
593
|
r = tsfix_update_ref(tf, tfs, pkt);
|
594
|
if (r != REF_OK) {
|
595
|
tsfix_packet_drop(tfs, pkt, r == REF_ERROR ? "refe" : "refd");
|
596
|
return;
|
597
|
}
|
598
|
}
|
599
|
|
600
|
int pdur = pkt->pkt_duration >> pkt->v.pkt_field;
|
601
|
|
602
|
if (pkt->pkt_dts == PTS_UNSET) {
|
603
|
if (tfs->tfs_last_dts_in == PTS_UNSET) {
|
604
|
if (tfs->tfs_type == SCT_TELETEXT) {
|
605
|
sm = streaming_msg_create_pkt(pkt);
|
606
|
streaming_target_deliver2(tf->tf_output, sm);
|
607
|
}
|
608
|
pkt_ref_dec(pkt);
|
609
|
return;
|
610
|
}
|
611
|
|
612
|
if (pkt->pkt_payload != NULL || pkt->pkt_pts != PTS_UNSET) {
|
613
|
pkt->pkt_dts = (tfs->tfs_last_dts_in + pdur) & PTS_MASK;
|
614
|
tvhtrace(LS_TSFIX, "%-12s DTS set to last %"PRId64" +%d == %"PRId64", PTS = %"PRId64,
|
615
|
streaming_component_type2txt(tfs->tfs_type),
|
616
|
tfs->tfs_last_dts_in, pdur, pkt->pkt_dts, pkt->pkt_pts);
|
617
|
}
|
618
|
}
|
619
|
|
620
|
if (tfs->tfs_parent)
|
621
|
pkt->pkt_dts = pkt->pkt_pts = tfs->tfs_parent->tfs_last_dts_in;
|
622
|
|
623
|
tfs->tfs_last_dts_in = pkt->pkt_dts;
|
624
|
|
625
|
compute_pts(tf, tfs, pkt);
|
626
|
}
|
627
|
|
628
|
|
629
|
/**
|
630
|
*
|
631
|
*/
|
632
|
static void
|
633
|
tsfix_input(void *opaque, streaming_message_t *sm)
|
634
|
{
|
635
|
tsfix_t *tf = opaque;
|
636
|
|
637
|
switch(sm->sm_type) {
|
638
|
case SMT_PACKET:
|
639
|
if (tf->tf_wait_for_video) {
|
640
|
streaming_msg_free(sm);
|
641
|
return;
|
642
|
}
|
643
|
tsfix_input_packet(tf, sm);
|
644
|
return;
|
645
|
case SMT_START:
|
646
|
tsfix_stop(tf);
|
647
|
tsfix_start(tf, sm->sm_data);
|
648
|
if (tf->tf_wait_for_video) {
|
649
|
streaming_msg_free(sm);
|
650
|
return;
|
651
|
}
|
652
|
break;
|
653
|
case SMT_STOP:
|
654
|
tsfix_stop(tf);
|
655
|
break;
|
656
|
case SMT_TIMESHIFT_STATUS:
|
657
|
if(tf->dts_offset == PTS_UNSET) {
|
658
|
timeshift_status_t *status;
|
659
|
status = sm->sm_data;
|
660
|
tf->dts_offset = status->shift;
|
661
|
}
|
662
|
streaming_msg_free(sm);
|
663
|
return;
|
664
|
case SMT_SKIP:
|
665
|
if(tf->dts_offset != PTS_UNSET) {
|
666
|
tf->dts_offset_apply = 1;
|
667
|
}
|
668
|
break;
|
669
|
case SMT_GRACE:
|
670
|
case SMT_EXIT:
|
671
|
case SMT_SERVICE_STATUS:
|
672
|
case SMT_SIGNAL_STATUS:
|
673
|
case SMT_DESCRAMBLE_INFO:
|
674
|
case SMT_NOSTART:
|
675
|
case SMT_NOSTART_WARN:
|
676
|
case SMT_MPEGTS:
|
677
|
case SMT_SPEED:
|
678
|
break;
|
679
|
}
|
680
|
|
681
|
streaming_target_deliver2(tf->tf_output, sm);
|
682
|
}
|
683
|
|
684
|
static htsmsg_t *
|
685
|
tsfix_input_info(void *opaque, htsmsg_t *list)
|
686
|
{
|
687
|
tsfix_t *tf = opaque;
|
688
|
streaming_target_t *st = tf->tf_output;
|
689
|
htsmsg_add_str(list, NULL, "tsfix input");
|
690
|
return st->st_ops.st_info(st->st_opaque, list);
|
691
|
}
|
692
|
|
693
|
static streaming_ops_t tsfix_input_ops = {
|
694
|
.st_cb = tsfix_input,
|
695
|
.st_info = tsfix_input_info
|
696
|
};
|
697
|
|
698
|
|
699
|
/**
|
700
|
*
|
701
|
*/
|
702
|
streaming_target_t *
|
703
|
tsfix_create(streaming_target_t *output)
|
704
|
{
|
705
|
tsfix_t *tf = calloc(1, sizeof(tsfix_t));
|
706
|
|
707
|
TAILQ_INIT(&tf->tf_ptsq);
|
708
|
|
709
|
tf->tf_output = output;
|
710
|
tf->tf_start_time = mclk();
|
711
|
tf->dts_offset = PTS_UNSET;
|
712
|
streaming_target_init(&tf->tf_input, &tsfix_input_ops, tf, 0);
|
713
|
return &tf->tf_input;
|
714
|
}
|
715
|
|
716
|
/**
|
717
|
*
|
718
|
*/
|
719
|
void
|
720
|
tsfix_destroy(streaming_target_t *pad)
|
721
|
{
|
722
|
tsfix_t *tf = (tsfix_t *)pad;
|
723
|
|
724
|
tsfix_destroy_streams(tf);
|
725
|
free(tf);
|
726
|
}
|