/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 | 37.8k | { |
53 | 37.8k | demux_sys_t *p_sys = p_demux->p_sys; |
54 | | |
55 | 37.8k | unsigned i_skip = PKTHeaderAndAFSize( p_pkt ); |
56 | 37.8k | if ( p_pkt->i_buffer < i_skip ) |
57 | 0 | return; |
58 | 37.8k | ts_90khz_t pktpcr = GetPCR( p_pkt ); |
59 | | |
60 | 37.8k | if( pktpcr != TS_90KHZ_INVALID ) |
61 | 5.01k | pid->probed.i_pcr_count++; |
62 | | |
63 | 37.8k | size_t i_data = p_pkt->i_buffer - i_skip; |
64 | 37.8k | const uint8_t *p_pes = &p_pkt->p_buffer[i_skip]; |
65 | | |
66 | 37.8k | ts_pes_header_t pesh; |
67 | 37.8k | ts_pes_header_init( &pesh ); |
68 | 37.8k | if( ParsePESHeader( NULL, p_pes, i_data, &pesh ) != VLC_SUCCESS ) |
69 | 11.1k | return; |
70 | | |
71 | 26.7k | if( pesh.i_dts != TS_90KHZ_INVALID ) |
72 | 2.28k | pid->probed.i_dts_count++; |
73 | | |
74 | 26.7k | if( pid->probed.i_fourcc != 0 ) |
75 | 6.32k | goto codecprobingend; |
76 | | |
77 | 20.4k | if( i_data < pesh.i_size + 4 ) |
78 | 1.90k | return; |
79 | | |
80 | 18.5k | const uint8_t *p_data = &p_pes[pesh.i_size]; |
81 | 18.5k | const uint8_t i_stream_id = pid->probed.i_stream_id = p_pes[3]; |
82 | | /* NON MPEG audio & subpictures STREAM */ |
83 | 18.5k | if(i_stream_id == 0xBD) |
84 | 250 | { |
85 | 250 | if( !memcmp( p_data, "\x7F\xFE\x80\x01", 4 ) ) |
86 | 1 | { |
87 | 1 | pid->probed.i_fourcc = VLC_CODEC_DTS; |
88 | 1 | pid->probed.i_cat = AUDIO_ES; |
89 | 1 | } |
90 | 249 | else if( !memcmp( p_data, "\x0B\x77", 2 ) ) |
91 | 160 | { |
92 | 160 | pid->probed.i_fourcc = VLC_CODEC_EAC3; |
93 | 160 | pid->probed.i_cat = AUDIO_ES; |
94 | 160 | } |
95 | 250 | } |
96 | | /* MPEG AUDIO STREAM */ |
97 | 18.2k | else if(i_stream_id >= 0xC0 && i_stream_id <= 0xDF) |
98 | 918 | { |
99 | 918 | pid->probed.i_cat = AUDIO_ES; |
100 | 918 | if( p_data[0] == 0xFF && (p_data[1] & 0xE0) == 0xE0 && |
101 | 448 | (p_data[1] & 0x18) != 0x08 && (p_data[1] & 0x06) != 0x00 ) |
102 | 293 | { |
103 | 293 | pid->probed.i_fourcc = VLC_CODEC_MPGA; |
104 | 293 | } |
105 | 625 | else if( p_data[0] == 0xFF && (p_data[1] & 0xF6) == 0xF0 ) |
106 | 153 | { |
107 | 153 | pid->probed.i_fourcc = VLC_CODEC_MP4A; /* ADTS */ |
108 | 153 | pid->probed.i_original_fourcc = VLC_FOURCC('A','D','T','S'); |
109 | 153 | } |
110 | 918 | } |
111 | | /* VIDEO STREAM */ |
112 | 17.3k | else if( i_stream_id >= 0xE0 && i_stream_id <= 0xEF ) |
113 | 570 | { |
114 | 570 | pid->probed.i_cat = VIDEO_ES; |
115 | 570 | if( !memcmp( p_data, "\x00\x00\x00\x01", 4 ) ) |
116 | 38 | { |
117 | 38 | pid->probed.i_fourcc = VLC_CODEC_H264; |
118 | 38 | } |
119 | 532 | else if( !memcmp( p_data, "\x00\x00\x01", 3 ) ) |
120 | 11 | { |
121 | 11 | pid->probed.i_fourcc = VLC_CODEC_MPGV; |
122 | 11 | } |
123 | 570 | } |
124 | | |
125 | 24.8k | codecprobingend: |
126 | | /* Track timestamps and flag missing PAT */ |
127 | 24.8k | if( !p_sys->patfix.i_timesourcepid && pesh.i_dts != TS_90KHZ_INVALID ) |
128 | 515 | { |
129 | 515 | p_sys->patfix.i_first_dts = FROM_SCALE(pesh.i_dts); |
130 | 515 | p_sys->patfix.i_timesourcepid = pid->i_pid; |
131 | 515 | } |
132 | 24.3k | else if( p_sys->patfix.i_timesourcepid == pid->i_pid && pesh.i_dts != TS_90KHZ_INVALID && |
133 | 1.58k | p_sys->patfix.status == PAT_WAITING ) |
134 | 1.02k | { |
135 | 1.02k | if( FROM_SCALE(pesh.i_dts) - p_sys->patfix.i_first_dts > MIN_PAT_INTERVAL ) |
136 | 368 | p_sys->patfix.status = PAT_MISSING; |
137 | 1.02k | } |
138 | | |
139 | 24.8k | } |
140 | | |
141 | | static void BuildPATCallback( void *p_opaque, block_t *p_block ) |
142 | 340 | { |
143 | 340 | ts_pid_t *pat_pid = (ts_pid_t *) p_opaque; |
144 | 340 | ts_psi_Packet_Push( pat_pid, p_block->p_buffer ); |
145 | 340 | block_Release( p_block ); |
146 | 340 | } |
147 | | |
148 | | static void BuildPMTCallback( void *p_opaque, block_t *p_block ) |
149 | 340 | { |
150 | 340 | ts_pid_t *program_pid = (ts_pid_t *) p_opaque; |
151 | 340 | assert(program_pid->type == TYPE_PMT); |
152 | 680 | while( p_block ) |
153 | 340 | { |
154 | 340 | ts_psi_Packet_Push( program_pid, p_block->p_buffer ); |
155 | 340 | block_t *p_next = p_block->p_next; |
156 | 340 | block_Release( p_block ); |
157 | 340 | p_block = p_next; |
158 | 340 | } |
159 | 340 | } |
160 | | |
161 | | void MissingPATPMTFixup( demux_t *p_demux ) |
162 | 356 | { |
163 | 356 | demux_sys_t *p_sys = p_demux->p_sys; |
164 | 356 | int i_program_number = 1234; |
165 | 356 | int i_program_pid = 1337; |
166 | 356 | int i_pcr_pid = 0x1FFF; |
167 | 356 | int i_num_pes = 0; |
168 | | |
169 | 356 | ts_pid_t *p_program_pid = GetPID( p_sys, i_program_pid ); |
170 | 356 | if( SEEN(p_program_pid) ) |
171 | 0 | { |
172 | | /* Find a free one */ |
173 | 0 | for( i_program_pid = MIN_ES_PID; |
174 | 0 | i_program_pid <= MAX_ES_PID && SEEN(p_program_pid); |
175 | 0 | i_program_pid++ ) |
176 | 0 | { |
177 | 0 | p_program_pid = GetPID( p_sys, i_program_pid ); |
178 | 0 | } |
179 | 0 | } |
180 | | |
181 | 356 | const ts_pid_t * candidates[4] = { NULL }; |
182 | 356 | const ts_pid_t *p_pid = NULL; |
183 | 356 | ts_pid_next_context_t pidnextctx = ts_pid_NextContextInitValue; |
184 | 3.24k | while( (p_pid = ts_pid_Next( &p_sys->pids, &pidnextctx )) ) |
185 | 2.88k | { |
186 | 2.88k | if( !SEEN(p_pid) || p_pid->probed.i_fourcc == 0 ) |
187 | 2.42k | continue; |
188 | | |
189 | 466 | if( p_pid->probed.i_pcr_count && candidates[0] == NULL && false ) |
190 | 0 | candidates[0] = p_pid; |
191 | | |
192 | 466 | if( p_pid->probed.i_cat == AUDIO_ES && |
193 | 455 | (candidates[1] == NULL || |
194 | 117 | candidates[1]->probed.i_dts_count > p_pid->probed.i_dts_count) ) |
195 | 426 | candidates[1] = p_pid; |
196 | | |
197 | 466 | if( candidates[2] == NULL && p_pid != candidates[1] && |
198 | 25 | p_pid->probed.i_dts_count > 0 ) |
199 | 9 | candidates[2] = p_pid; |
200 | | |
201 | 466 | if( candidates[3] == NULL ) |
202 | 340 | candidates[3] = p_pid; |
203 | | |
204 | 466 | i_num_pes++; |
205 | 466 | } |
206 | | |
207 | 763 | for(int i=0; i<4; i++) |
208 | 747 | { |
209 | 747 | if(!candidates[i]) |
210 | 407 | continue; |
211 | 340 | i_pcr_pid = candidates[i]->i_pid; |
212 | 340 | p_sys->patfix.b_pcrhasnopcrfield = (candidates[i]->probed.i_pcr_count < 1); |
213 | 340 | break; |
214 | 747 | } |
215 | | |
216 | 356 | if( i_num_pes == 0 ) |
217 | 16 | return; |
218 | | |
219 | 340 | tsmux_stream_t patstream = |
220 | 340 | { |
221 | 340 | .i_pid = 0, |
222 | 340 | .i_continuity_counter = 0x10, |
223 | 340 | .b_discontinuity = false |
224 | 340 | }; |
225 | | |
226 | 340 | tsmux_stream_t pmtprogramstream = |
227 | 340 | { |
228 | 340 | .i_pid = i_program_pid, |
229 | 340 | .i_continuity_counter = 0x0, |
230 | 340 | .b_discontinuity = false |
231 | 340 | }; |
232 | | |
233 | 340 | dvbpsi_t *handle = dvbpsi_new( NULL, DVBPSI_MSG_DEBUG ); |
234 | 340 | if( !handle ) |
235 | 0 | return; |
236 | | |
237 | 340 | BuildPAT( handle, |
238 | 340 | &p_sys->pids.pat, BuildPATCallback, |
239 | 340 | 0, 1, |
240 | 340 | &patstream, |
241 | 340 | 1, &pmtprogramstream, &i_program_number ); |
242 | | |
243 | | /* PAT callback should have been triggered */ |
244 | 340 | if( p_program_pid->type != TYPE_PMT ) |
245 | 0 | { |
246 | 0 | dvbpsi_delete( handle ); |
247 | 0 | msg_Err( p_demux, "PAT creation failed" ); |
248 | 0 | return; |
249 | 0 | } |
250 | | |
251 | 340 | ts_mux_standard mux_standard = (p_sys->standard == TS_STANDARD_ATSC) ? TS_MUX_STANDARD_ATSC |
252 | 340 | : TS_MUX_STANDARD_DVB; |
253 | 340 | struct esstreams_t |
254 | 340 | { |
255 | 340 | pesmux_stream_t pes; |
256 | 340 | tsmux_stream_t ts; |
257 | 340 | es_format_t fmt; |
258 | 340 | }; |
259 | | |
260 | 340 | struct esstreams_t *esstreams = calloc( i_num_pes, sizeof(struct esstreams_t) ); |
261 | 340 | pes_mapped_stream_t *mapped = calloc( i_num_pes, sizeof(pes_mapped_stream_t) ); |
262 | 340 | if( esstreams && mapped ) |
263 | 340 | { |
264 | 340 | int j=0; |
265 | 3.08k | for( int i=0; i<p_sys->pids.i_all; i++ ) |
266 | 2.74k | { |
267 | 2.74k | p_pid = p_sys->pids.pp_all[i]; |
268 | | |
269 | 2.74k | if( !SEEN(p_pid) || |
270 | 2.40k | p_pid->probed.i_fourcc == 0 ) |
271 | 2.28k | continue; |
272 | | |
273 | 466 | es_format_Init(&esstreams[j].fmt, p_pid->probed.i_cat, p_pid->probed.i_fourcc); |
274 | 466 | esstreams[j].fmt.i_original_fourcc = p_pid->probed.i_original_fourcc; |
275 | | |
276 | 466 | if( VLC_SUCCESS != |
277 | 466 | 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 | 466 | esstreams[j].pes.i_stream_id = p_pid->probed.i_stream_id; |
285 | | |
286 | 466 | esstreams[j].ts.i_pid = p_pid->i_pid; |
287 | 466 | mapped[j].pes = &esstreams[j].pes; |
288 | 466 | mapped[j].ts = &esstreams[j].ts; |
289 | 466 | mapped[j].fmt = &esstreams[j].fmt; |
290 | 466 | j++; |
291 | 466 | } |
292 | | |
293 | 340 | BuildPMT( handle, VLC_OBJECT(p_demux), |
294 | 340 | mux_standard, |
295 | 340 | p_program_pid, BuildPMTCallback, |
296 | 340 | 0, 1, |
297 | 340 | i_pcr_pid, |
298 | 340 | NULL, |
299 | 340 | 1, &pmtprogramstream, &i_program_number, |
300 | 340 | j, mapped ); |
301 | | |
302 | | /* Cleanup */ |
303 | 806 | for( int i=0; i<j; i++ ) |
304 | 466 | es_format_Clean( &esstreams[i].fmt ); |
305 | 340 | } |
306 | 340 | free(esstreams); |
307 | 340 | free(mapped); |
308 | | |
309 | 340 | dvbpsi_delete( handle ); |
310 | 340 | } |