/src/vlc/modules/demux/mpeg/ts_hotfixes.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * ts_hotfixes.c : MPEG PMT/PAT less streams fixups |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2014-2016 - VideoLAN Authors |
5 | | * |
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. |
10 | | * |
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. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | *****************************************************************************/ |
19 | | #ifdef HAVE_CONFIG_H |
20 | | # include "config.h" |
21 | | #endif |
22 | | |
23 | | #include <vlc_common.h> |
24 | | #include <vlc_demux.h> |
25 | | #include <vlc_es.h> |
26 | | |
27 | | #ifndef _DVBPSI_DVBPSI_H_ |
28 | | #include <dvbpsi/dvbpsi.h> |
29 | | #endif |
30 | | #include <dvbpsi/descriptor.h> |
31 | | #include <dvbpsi/pat.h> |
32 | | #include <dvbpsi/pmt.h> |
33 | | |
34 | | #include "../../mux/mpeg/streams.h" |
35 | | #include "../../mux/mpeg/tsutil.h" |
36 | | #include "../../mux/mpeg/tables.h" |
37 | | |
38 | | #include "timestamps.h" |
39 | | #include "pes.h" |
40 | | |
41 | | #include "ts_streams.h" |
42 | | #include "ts_psi.h" |
43 | | #include "ts_pid.h" |
44 | | #include "ts_streams_private.h" |
45 | | #include "ts.h" |
46 | | #include "ts_hotfixes.h" |
47 | | #include "ts_packet.h" |
48 | | |
49 | | #include <assert.h> |
50 | | |
51 | | void ProbePES( demux_t *p_demux, ts_pid_t *pid, const block_t *p_pkt ) |
52 | 51.1k | { |
53 | 51.1k | demux_sys_t *p_sys = p_demux->p_sys; |
54 | | |
55 | 51.1k | unsigned i_skip = PKTHeaderAndAFSize( p_pkt ); |
56 | 51.1k | if ( p_pkt->i_buffer < i_skip ) |
57 | 0 | return; |
58 | 51.1k | ts_90khz_t pktpcr = GetPCR( p_pkt ); |
59 | | |
60 | 51.1k | if( pktpcr != TS_90KHZ_INVALID ) |
61 | 6.91k | pid->probed.i_pcr_count++; |
62 | | |
63 | 51.1k | size_t i_data = p_pkt->i_buffer - i_skip; |
64 | 51.1k | const uint8_t *p_pes = &p_pkt->p_buffer[i_skip]; |
65 | | |
66 | 51.1k | ts_pes_header_t pesh; |
67 | 51.1k | ts_pes_header_init( &pesh ); |
68 | 51.1k | if( ParsePESHeader( NULL, p_pes, i_data, &pesh ) != VLC_SUCCESS ) |
69 | 14.4k | return; |
70 | | |
71 | 36.6k | if( pesh.i_dts != TS_90KHZ_INVALID ) |
72 | 5.03k | pid->probed.i_dts_count++; |
73 | | |
74 | 36.6k | if( pid->probed.i_fourcc != 0 ) |
75 | 6.68k | goto codecprobingend; |
76 | | |
77 | 29.9k | if( i_data < pesh.i_size + 4 ) |
78 | 1.95k | return; |
79 | | |
80 | 28.0k | const uint8_t *p_data = &p_pes[pesh.i_size]; |
81 | 28.0k | const uint8_t i_stream_id = pid->probed.i_stream_id = p_pes[3]; |
82 | | /* NON MPEG audio & subpictures STREAM */ |
83 | 28.0k | if(i_stream_id == 0xBD) |
84 | 399 | { |
85 | 399 | if( !memcmp( p_data, "\x7F\xFE\x80\x01", 4 ) ) |
86 | 10 | { |
87 | 10 | pid->probed.i_fourcc = VLC_CODEC_DTS; |
88 | 10 | pid->probed.i_cat = AUDIO_ES; |
89 | 10 | } |
90 | 389 | else if( !memcmp( p_data, "\x0B\x77", 2 ) ) |
91 | 257 | { |
92 | 257 | pid->probed.i_fourcc = VLC_CODEC_EAC3; |
93 | 257 | pid->probed.i_cat = AUDIO_ES; |
94 | 257 | } |
95 | 399 | } |
96 | | /* MPEG AUDIO STREAM */ |
97 | 27.6k | else if(i_stream_id >= 0xC0 && i_stream_id <= 0xDF) |
98 | 1.97k | { |
99 | 1.97k | pid->probed.i_cat = AUDIO_ES; |
100 | 1.97k | if( p_data[0] == 0xFF && (p_data[1] & 0xE0) == 0xE0 && |
101 | 604 | (p_data[1] & 0x18) != 0x08 && (p_data[1] & 0x06) != 0x00 ) |
102 | 366 | { |
103 | 366 | pid->probed.i_fourcc = VLC_CODEC_MPGA; |
104 | 366 | } |
105 | 1.60k | else if( p_data[0] == 0xFF && (p_data[1] & 0xF6) == 0xF0 ) |
106 | 144 | { |
107 | 144 | pid->probed.i_fourcc = VLC_CODEC_MP4A; /* ADTS */ |
108 | 144 | pid->probed.i_original_fourcc = VLC_FOURCC('A','D','T','S'); |
109 | 144 | } |
110 | 1.97k | } |
111 | | /* VIDEO STREAM */ |
112 | 25.6k | else if( i_stream_id >= 0xE0 && i_stream_id <= 0xEF ) |
113 | 631 | { |
114 | 631 | pid->probed.i_cat = VIDEO_ES; |
115 | 631 | if( !memcmp( p_data, "\x00\x00\x00\x01", 4 ) ) |
116 | 32 | { |
117 | 32 | pid->probed.i_fourcc = VLC_CODEC_H264; |
118 | 32 | } |
119 | 599 | else if( !memcmp( p_data, "\x00\x00\x01", 3 ) ) |
120 | 21 | { |
121 | 21 | pid->probed.i_fourcc = VLC_CODEC_MPGV; |
122 | 21 | } |
123 | 631 | } |
124 | | |
125 | 34.7k | codecprobingend: |
126 | | /* Track timestamps and flag missing PAT */ |
127 | 34.7k | if( !p_sys->patfix.i_timesourcepid && pesh.i_dts != TS_90KHZ_INVALID ) |
128 | 715 | { |
129 | 715 | p_sys->patfix.i_first_dts = FROM_SCALE(pesh.i_dts); |
130 | 715 | p_sys->patfix.i_timesourcepid = pid->i_pid; |
131 | 715 | } |
132 | 34.0k | else if( p_sys->patfix.i_timesourcepid == pid->i_pid && pesh.i_dts != TS_90KHZ_INVALID && |
133 | 4.06k | p_sys->patfix.status == PAT_WAITING ) |
134 | 2.46k | { |
135 | 2.46k | if( FROM_SCALE(pesh.i_dts) - p_sys->patfix.i_first_dts > MIN_PAT_INTERVAL ) |
136 | 442 | p_sys->patfix.status = PAT_MISSING; |
137 | 2.46k | } |
138 | | |
139 | 34.7k | } |
140 | | |
141 | | static void BuildPATCallback( void *p_opaque, block_t *p_block ) |
142 | 375 | { |
143 | 375 | ts_pid_t *pat_pid = (ts_pid_t *) p_opaque; |
144 | 375 | ts_psi_Packet_Push( pat_pid, p_block->p_buffer ); |
145 | 375 | block_Release( p_block ); |
146 | 375 | } |
147 | | |
148 | | static void BuildPMTCallback( void *p_opaque, block_t *p_block ) |
149 | 374 | { |
150 | 374 | ts_pid_t *program_pid = (ts_pid_t *) p_opaque; |
151 | 374 | assert(program_pid->type == TYPE_PMT); |
152 | 748 | while( p_block ) |
153 | 374 | { |
154 | 374 | ts_psi_Packet_Push( program_pid, p_block->p_buffer ); |
155 | 374 | block_t *p_next = p_block->p_next; |
156 | 374 | block_Release( p_block ); |
157 | 374 | p_block = p_next; |
158 | 374 | } |
159 | 374 | } |
160 | | |
161 | | void MissingPATPMTFixup( demux_t *p_demux ) |
162 | 400 | { |
163 | 400 | demux_sys_t *p_sys = p_demux->p_sys; |
164 | 400 | int i_program_number = 1234; |
165 | 400 | int i_program_pid = 1337; |
166 | 400 | int i_pcr_pid = 0x1FFF; |
167 | 400 | int i_num_pes = 0; |
168 | | |
169 | 400 | ts_pid_t *p_program_pid = GetPID( p_sys, i_program_pid ); |
170 | 400 | if( SEEN(p_program_pid) ) |
171 | 1 | { |
172 | | /* Find a free one */ |
173 | 1 | for( i_program_pid = MIN_ES_PID; |
174 | 2 | i_program_pid <= MAX_ES_PID && SEEN(p_program_pid); |
175 | 1 | i_program_pid++ ) |
176 | 1 | { |
177 | 1 | p_program_pid = GetPID( p_sys, i_program_pid ); |
178 | 1 | } |
179 | 1 | } |
180 | | |
181 | 400 | const ts_pid_t * candidates[4] = { NULL }; |
182 | 400 | const ts_pid_t *p_pid = NULL; |
183 | 400 | ts_pid_next_context_t pidnextctx = ts_pid_NextContextInitValue; |
184 | 3.40k | while( (p_pid = ts_pid_Next( &p_sys->pids, &pidnextctx )) ) |
185 | 3.00k | { |
186 | 3.00k | if( !SEEN(p_pid) || p_pid->probed.i_fourcc == 0 ) |
187 | 2.44k | continue; |
188 | | |
189 | 557 | if( p_pid->probed.i_pcr_count && candidates[0] == NULL && false ) |
190 | 0 | candidates[0] = p_pid; |
191 | | |
192 | 557 | if( p_pid->probed.i_cat == AUDIO_ES && |
193 | 541 | (candidates[1] == NULL || |
194 | 168 | candidates[1]->probed.i_dts_count > p_pid->probed.i_dts_count) ) |
195 | 495 | candidates[1] = p_pid; |
196 | | |
197 | 557 | if( candidates[2] == NULL && p_pid != candidates[1] && |
198 | 40 | p_pid->probed.i_dts_count > 0 ) |
199 | 16 | candidates[2] = p_pid; |
200 | | |
201 | 557 | if( candidates[3] == NULL ) |
202 | 375 | candidates[3] = p_pid; |
203 | | |
204 | 557 | i_num_pes++; |
205 | 557 | } |
206 | | |
207 | 878 | for(int i=0; i<4; i++) |
208 | 853 | { |
209 | 853 | if(!candidates[i]) |
210 | 478 | continue; |
211 | 375 | i_pcr_pid = candidates[i]->i_pid; |
212 | 375 | p_sys->patfix.b_pcrhasnopcrfield = (candidates[i]->probed.i_pcr_count < 1); |
213 | 375 | break; |
214 | 853 | } |
215 | | |
216 | 400 | if( i_num_pes == 0 ) |
217 | 25 | return; |
218 | | |
219 | 375 | tsmux_stream_t patstream = |
220 | 375 | { |
221 | 375 | .i_pid = 0, |
222 | 375 | .i_continuity_counter = 0x10, |
223 | 375 | .b_discontinuity = false |
224 | 375 | }; |
225 | | |
226 | 375 | tsmux_stream_t pmtprogramstream = |
227 | 375 | { |
228 | 375 | .i_pid = i_program_pid, |
229 | 375 | .i_continuity_counter = 0x0, |
230 | 375 | .b_discontinuity = false |
231 | 375 | }; |
232 | | |
233 | 375 | dvbpsi_t *handle = dvbpsi_new( NULL, DVBPSI_MSG_DEBUG ); |
234 | 375 | if( !handle ) |
235 | 0 | return; |
236 | | |
237 | 375 | BuildPAT( handle, |
238 | 375 | &p_sys->pids.pat, BuildPATCallback, |
239 | 375 | 0, 1, |
240 | 375 | &patstream, |
241 | 375 | 1, &pmtprogramstream, &i_program_number ); |
242 | | |
243 | | /* PAT callback should have been triggered */ |
244 | 375 | if( p_program_pid->type != TYPE_PMT ) |
245 | 1 | { |
246 | 1 | dvbpsi_delete( handle ); |
247 | 1 | msg_Err( p_demux, "PAT creation failed" ); |
248 | 1 | return; |
249 | 1 | } |
250 | | |
251 | 374 | ts_mux_standard mux_standard = (p_sys->standard == TS_STANDARD_ATSC) ? TS_MUX_STANDARD_ATSC |
252 | 374 | : TS_MUX_STANDARD_DVB; |
253 | 374 | struct esstreams_t |
254 | 374 | { |
255 | 374 | pesmux_stream_t pes; |
256 | 374 | tsmux_stream_t ts; |
257 | 374 | es_format_t fmt; |
258 | 374 | }; |
259 | | |
260 | 374 | struct esstreams_t *esstreams = calloc( i_num_pes, sizeof(struct esstreams_t) ); |
261 | 374 | pes_mapped_stream_t *mapped = calloc( i_num_pes, sizeof(pes_mapped_stream_t) ); |
262 | 374 | if( esstreams && mapped ) |
263 | 374 | { |
264 | 374 | int j=0; |
265 | 3.19k | for( int i=0; i<p_sys->pids.i_all; i++ ) |
266 | 2.81k | { |
267 | 2.81k | p_pid = p_sys->pids.pp_all[i]; |
268 | | |
269 | 2.81k | if( !SEEN(p_pid) || |
270 | 2.44k | p_pid->probed.i_fourcc == 0 ) |
271 | 2.26k | continue; |
272 | | |
273 | 556 | es_format_Init(&esstreams[j].fmt, p_pid->probed.i_cat, p_pid->probed.i_fourcc); |
274 | 556 | esstreams[j].fmt.i_original_fourcc = p_pid->probed.i_original_fourcc; |
275 | | |
276 | 556 | if( VLC_SUCCESS != |
277 | 556 | FillPMTESParams(mux_standard, &esstreams[j].fmt, &esstreams[j].ts, &esstreams[j].pes ) ) |
278 | 0 | { |
279 | 0 | es_format_Clean( &esstreams[j].fmt ); |
280 | 0 | continue; |
281 | 0 | } |
282 | | |
283 | | /* Important for correct remapping: Enforce probed PES stream id */ |
284 | 556 | esstreams[j].pes.i_stream_id = p_pid->probed.i_stream_id; |
285 | | |
286 | 556 | esstreams[j].ts.i_pid = p_pid->i_pid; |
287 | 556 | mapped[j].pes = &esstreams[j].pes; |
288 | 556 | mapped[j].ts = &esstreams[j].ts; |
289 | 556 | mapped[j].fmt = &esstreams[j].fmt; |
290 | 556 | j++; |
291 | 556 | } |
292 | | |
293 | 374 | BuildPMT( handle, VLC_OBJECT(p_demux), |
294 | 374 | mux_standard, |
295 | 374 | p_program_pid, BuildPMTCallback, |
296 | 374 | 0, 1, |
297 | 374 | i_pcr_pid, |
298 | 374 | NULL, |
299 | 374 | 1, &pmtprogramstream, &i_program_number, |
300 | 374 | j, mapped ); |
301 | | |
302 | | /* Cleanup */ |
303 | 930 | for( int i=0; i<j; i++ ) |
304 | 556 | es_format_Clean( &esstreams[i].fmt ); |
305 | 374 | } |
306 | 374 | free(esstreams); |
307 | 374 | free(mapped); |
308 | | |
309 | 374 | dvbpsi_delete( handle ); |
310 | 374 | } |