contrib: cargo: use the 0.6.13 cargo-c version
[vlc.git] / modules / access / live555_dtsgen.h
blobd80c5cc0793b800a4dffb61990e29736884b0d08
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
24 struct dtsgen_t
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;
31 unsigned count;
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;
38 else
39 return -1;
42 static void dtsgen_Init(struct dtsgen_t *d)
44 d->count = 0;
45 d->reorderdepth = 0;
48 static void dtsgen_Resync(struct dtsgen_t *d)
50 d->count = 0;
51 d->reorderdepth = 0;
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)
83 * We need then to:
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)
105 unsigned i;
106 if(d->count > (1 + d->reorderdepth))
107 i = d->count - (1 + d->reorderdepth);
108 else
109 i = 0;
111 for(; i < d->count; i++)
113 if(d->history[i] > i_pts)
115 if(d->reorderdepth < DTSGEN_REORDER_MAX)
116 d->reorderdepth++;
118 break;
122 /* insert current */
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));
129 else
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)
153 d->i_startingdts =
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] -
160 d->ordereddts[0];
161 i_diff = __MIN(d->i_startingdiff, i_diff);
162 d->i_startingdts += i_diff / DTSGEN_REORDER_MAX;
163 i_dts = d->i_startingdts;
166 return i_dts;
169 #ifdef DTSGEN_DEBUG
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)
174 return;
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);
182 #else
183 #define dtsgen_Debug(a,b,c,d)
184 #endif