1 /*****************************************************************************
2 * live555_dtsgen.h : DTS rebuilder for pts only streams
3 *****************************************************************************
4 * Copyright (C) 2018 VideoLabs, VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
20 #define DTSGEN_REORDER_MAX 4 /* should be enough */
21 #define DTSGEN_HISTORY_COUNT (DTSGEN_REORDER_MAX + 2)
22 //#define DTSGEN_DEBUG
26 vlc_tick_t history
[DTSGEN_HISTORY_COUNT
];
27 vlc_tick_t ordereddts
[DTSGEN_HISTORY_COUNT
];
28 vlc_tick_t i_startingdts
;
29 vlc_tick_t i_startingdiff
;
30 unsigned reorderdepth
;
34 static int cmpvlctickp(const void *p1
, const void *p2
)
36 if(*((vlc_tick_t
*)p1
) >= *((vlc_tick_t
*)p2
))
37 return *((vlc_tick_t
*)p1
) > *((vlc_tick_t
*)p2
) ? 1 : 0;
42 static void dtsgen_Init(struct dtsgen_t
*d
)
48 static void dtsgen_Resync(struct dtsgen_t
*d
)
54 #define dtsgen_Clean(d)
57 * RTSP sends in decode order, but only provides PTS as timestamp
58 * P0 P2 P3 P1 P5 P7 P8 P6
59 * D0 D2 D3 D1 D5 D7 D8 D6 <- wrong !
60 * creating a non monotonical sequence when used as DTS, then PCR
62 * We need to have a suitable DTS for proper PCR and transcoding
63 * with the usual requirements DTS0 < DTS1 and DTSN < PTSN
65 * So we want to find the closest DTS matching those conditions
66 * P0 P2 P3[P1]P5 P7 P8 P6
67 * [D0]D1 D2 D3 D4 D5 D6 D7
69 * Which means that within a reorder window,
70 * we want the PTS time index after reorder as DTS
71 * [P0 P2 P3 P1]P5 P7 P8 P6
72 * [P0 P1 P2 P3] reordered
73 * [D0 D1 D2 D3]D4 D5 D6 D7
74 * we need to pick then N frames before in reordered order (== reorder depth)
75 * P0 P2 P3[P1]P5 P7 P8 P6
76 * [D0]D1 D2 D3 D4 D5 D6 D7
77 * so D0 < P1 (we can also pick D1 if we want DTSN <= PTSN)
79 * Since it would create big delays with low fps streams we need
80 * - to avoid buffering packets
81 * - to detect real reorder depth (low fps usually have no reorder)
84 * - Detect reorder depth
85 * - Keep track of last of N past timestamps, > maximum possible reorder
86 * - Make sure a suitable dts is still created while detecting reorder depth
88 * While receiving the N first packets (N>max reorder):
89 * - check if it needs reorder, or increase depth
90 * - create slow increments in DTS while taking any frame as a start,
91 * substracting the total difference between first and last packet,
92 * and removing the possible offset after reorder,
93 * divided by max possible frames.
95 * Once reorder depth is fully known,
96 * - use N previous frames reordered PTS as DTS for current PTS.
97 * (with mandatory gap/increase in DTS caused by previous step)
100 static void dtsgen_AddNextPTS(struct dtsgen_t
*d
, vlc_tick_t i_pts
)
102 /* Check saved pts in reception order to find reordering depth */
103 if(d
->count
> 0 && d
->count
< DTSGEN_HISTORY_COUNT
)
106 if(d
->count
> (1 + d
->reorderdepth
))
107 i
= d
->count
- (1 + d
->reorderdepth
);
111 for(; i
< d
->count
; i
++)
113 if(d
->history
[i
] > i_pts
)
115 if(d
->reorderdepth
< DTSGEN_REORDER_MAX
)
123 if(d
->count
== DTSGEN_HISTORY_COUNT
)
125 d
->ordereddts
[0] = i_pts
; /* remove lowest */
126 memmove(d
->history
, &d
->history
[1],
127 sizeof(d
->history
[0]) * (d
->count
- 1));
131 d
->history
[d
->count
] = i_pts
;
132 d
->ordereddts
[d
->count
++] = i_pts
;
135 /* order pts in second list, will be used as dts */
136 qsort(&d
->ordereddts
, d
->count
, sizeof(d
->ordereddts
[0]), cmpvlctickp
);
139 static vlc_tick_t
dtsgen_GetDTS(struct dtsgen_t
*d
)
141 vlc_tick_t i_dts
= VLC_TICK_INVALID
;
143 /* When we have inspected enough packets,
144 * use the reorderdepth th packet as dts offset */
145 if(d
->count
> DTSGEN_REORDER_MAX
)
147 i_dts
= d
->ordereddts
[d
->count
- d
->reorderdepth
- 1];
149 /* When starting, we craft a slow incrementing DTS to ensure
150 we can't go backward due to reorder need */
151 else if(d
->count
== 1)
154 i_dts
= __MAX(d
->history
[0] - VLC_TICK_FROM_MS(150), VLC_TICK_0
);
155 d
->i_startingdiff
= d
->history
[0] - i_dts
;
157 else if(d
->count
> 1)
159 vlc_tick_t i_diff
= d
->ordereddts
[d
->count
- 1] -
161 i_diff
= __MIN(d
->i_startingdiff
, i_diff
);
162 d
->i_startingdts
+= i_diff
/ DTSGEN_REORDER_MAX
;
163 i_dts
= d
->i_startingdts
;
170 static void dtsgen_Debug(vlc_object_t
*p_demux
, struct dtsgen_t
*d
,
171 vlc_tick_t dts
, vlc_tick_t pts
)
173 if(pts
== VLC_TICK_INVALID
)
175 msg_Dbg(p_demux
, "dtsgen %" PRId64
" / pts %" PRId64
" diff %" PRId64
", "
176 "pkt count %u, reorder %u",
177 dts
% (10 * CLOCK_FREQ
),
178 pts
% (10 * CLOCK_FREQ
),
179 (pts
- dts
) % (10 * CLOCK_FREQ
),
180 d
->count
, d
->reorderdepth
);
183 #define dtsgen_Debug(a,b,c,d)