qml: Create MediaGroupDisplay
[vlc.git] / modules / demux / mpeg / ts_hotfixes.c
blob1593eec4e3e8808f3fbb820512d6562b8acc7fd5
1 /*****************************************************************************
2 * ts_hotfixes.c : MPEG PMT/PAT less streams fixups
3 *****************************************************************************
4 * Copyright (C) 2014-2016 - VideoLAN Authors
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 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
23 #include <vlc_common.h>
24 #include <vlc_demux.h>
25 #include <vlc_es.h>
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>
34 #include "../../mux/mpeg/streams.h"
35 #include "../../mux/mpeg/tsutil.h"
36 #include "../../mux/mpeg/tables.h"
38 #include "timestamps.h"
39 #include "pes.h"
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"
48 #include <assert.h>
50 void ProbePES( demux_t *p_demux, ts_pid_t *pid, const uint8_t *p_pesstart, size_t i_data, bool b_adaptfield )
52 demux_sys_t *p_sys = p_demux->p_sys;
53 const uint8_t *p_pes = p_pesstart;
55 if( b_adaptfield )
57 if ( i_data < 2 )
58 return;
60 uint8_t len = *p_pes;
61 p_pes++; i_data--;
63 if(len == 0)
65 p_pes++; i_data--;/* stuffing */
67 else
69 if( i_data < len )
70 return;
71 if( len >= 7 && (p_pes[0] & 0x10) )
72 pid->probed.i_pcr_count++;
73 p_pes += len;
74 i_data -= len;
78 if( i_data < 9 )
79 return;
81 if( p_pes[0] != 0 || p_pes[1] != 0 || p_pes[2] != 1 )
82 return;
84 size_t i_pesextoffset = 8;
85 stime_t i_dts = -1;
86 if( p_pes[7] & 0x80 ) // PTS
88 i_pesextoffset += 5;
89 if ( i_data < i_pesextoffset ||
90 !ExtractPESTimestamp( &p_pes[9], p_pes[7] >> 6, &i_dts ) )
91 return;
92 pid->probed.i_dts_count++;
94 if( p_pes[7] & 0x40 ) // DTS
96 i_pesextoffset += 5;
97 if ( i_data < i_pesextoffset ||
98 !ExtractPESTimestamp( &p_pes[14], 0x01, &i_dts ) )
99 return;
101 if( p_pes[7] & 0x20 ) // ESCR
102 i_pesextoffset += 6;
103 if( p_pes[7] & 0x10 ) // ESrate
104 i_pesextoffset += 3;
105 if( p_pes[7] & 0x08 ) // DSM
106 i_pesextoffset += 1;
107 if( p_pes[7] & 0x04 ) // CopyInfo
108 i_pesextoffset += 1;
109 if( p_pes[7] & 0x02 ) // PESCRC
110 i_pesextoffset += 2;
112 if( pid->probed.i_fourcc != 0 )
113 goto codecprobingend;
115 if ( i_data < i_pesextoffset )
116 return;
118 /* HeaderdataLength */
119 const size_t i_payloadoffset = 8 + 1 + p_pes[8];
120 i_pesextoffset += 1;
122 if ( i_data < i_pesextoffset || i_data < i_payloadoffset )
123 return;
125 i_data -= 8 + 1 + p_pes[8];
127 if( p_pes[7] & 0x01 ) // PESExt
129 size_t i_extension2_offset = 1;
130 if ( p_pes[i_pesextoffset] & 0x80 ) // private data
131 i_extension2_offset += 16;
132 if ( p_pes[i_pesextoffset] & 0x40 ) // pack
133 i_extension2_offset += 1;
134 if ( p_pes[i_pesextoffset] & 0x20 ) // seq
135 i_extension2_offset += 2;
136 if ( p_pes[i_pesextoffset] & 0x10 ) // P-STD
137 i_extension2_offset += 2;
138 if ( p_pes[i_pesextoffset] & 0x01 ) // Extension 2
140 uint8_t i_len = p_pes[i_pesextoffset + i_extension2_offset] & 0x7F;
141 i_extension2_offset += i_len;
143 if( i_data < i_extension2_offset )
144 return;
146 i_data -= i_extension2_offset;
148 /* (i_payloadoffset - i_pesextoffset) 0xFF stuffing */
150 if ( i_data < 4 )
151 return;
153 const uint8_t *p_data = &p_pes[i_payloadoffset];
154 const uint8_t i_stream_id = pid->probed.i_stream_id = p_pes[3];
155 /* NON MPEG audio & subpictures STREAM */
156 if(i_stream_id == 0xBD)
158 if( !memcmp( p_data, "\x7F\xFE\x80\x01", 4 ) )
160 pid->probed.i_fourcc = VLC_CODEC_DTS;
161 pid->probed.i_cat = AUDIO_ES;
163 else if( !memcmp( p_data, "\x0B\x77", 2 ) )
165 pid->probed.i_fourcc = VLC_CODEC_EAC3;
166 pid->probed.i_cat = AUDIO_ES;
169 /* MPEG AUDIO STREAM */
170 else if(i_stream_id >= 0xC0 && i_stream_id <= 0xDF)
172 pid->probed.i_cat = AUDIO_ES;
173 if( p_data[0] == 0xFF && (p_data[1] & 0xE0) == 0xE0 &&
174 (p_data[1] & 0x18) != 0x08 && (p_data[1] & 0x06) != 0x00 )
176 pid->probed.i_fourcc = VLC_CODEC_MPGA;
178 else if( p_data[0] == 0xFF && (p_data[1] & 0xF6) == 0xF0 )
180 pid->probed.i_fourcc = VLC_CODEC_MP4A; /* ADTS */
181 pid->probed.i_original_fourcc = VLC_FOURCC('A','D','T','S');
184 /* VIDEO STREAM */
185 else if( i_stream_id >= 0xE0 && i_stream_id <= 0xEF )
187 pid->probed.i_cat = VIDEO_ES;
188 if( !memcmp( p_data, "\x00\x00\x00\x01", 4 ) )
190 pid->probed.i_fourcc = VLC_CODEC_H264;
192 else if( !memcmp( p_data, "\x00\x00\x01", 4 ) )
194 pid->probed.i_fourcc = VLC_CODEC_MPGV;
198 codecprobingend:
199 /* Track timestamps and flag missing PAT */
200 if( !p_sys->patfix.i_timesourcepid && i_dts > -1 )
202 p_sys->patfix.i_first_dts = i_dts;
203 p_sys->patfix.i_timesourcepid = pid->i_pid;
205 else if( p_sys->patfix.i_timesourcepid == pid->i_pid && i_dts > -1 &&
206 p_sys->patfix.status == PAT_WAITING )
208 if( i_dts - p_sys->patfix.i_first_dts > TO_SCALE(MIN_PAT_INTERVAL) )
209 p_sys->patfix.status = PAT_MISSING;
214 static void BuildPATCallback( void *p_opaque, block_t *p_block )
216 ts_pid_t *pat_pid = (ts_pid_t *) p_opaque;
217 dvbpsi_packet_push( pat_pid->u.p_pat->handle, p_block->p_buffer );
218 block_Release( p_block );
221 static void BuildPMTCallback( void *p_opaque, block_t *p_block )
223 ts_pid_t *program_pid = (ts_pid_t *) p_opaque;
224 assert(program_pid->type == TYPE_PMT);
225 while( p_block )
227 dvbpsi_packet_push( program_pid->u.p_pmt->handle,
228 p_block->p_buffer );
229 block_t *p_next = p_block->p_next;
230 block_Release( p_block );
231 p_block = p_next;
235 void MissingPATPMTFixup( demux_t *p_demux )
237 demux_sys_t *p_sys = p_demux->p_sys;
238 int i_program_number = 1234;
239 int i_program_pid = 1337;
240 int i_pcr_pid = 0x1FFF;
241 int i_num_pes = 0;
243 ts_pid_t *p_program_pid = GetPID( p_sys, i_program_pid );
244 if( SEEN(p_program_pid) )
246 /* Find a free one */
247 for( i_program_pid = MIN_ES_PID;
248 i_program_pid <= MAX_ES_PID && SEEN(p_program_pid);
249 i_program_pid++ )
251 p_program_pid = GetPID( p_sys, i_program_pid );
255 const ts_pid_t * candidates[4] = { NULL };
256 const ts_pid_t *p_pid = NULL;
257 ts_pid_next_context_t pidnextctx = ts_pid_NextContextInitValue;
258 while( (p_pid = ts_pid_Next( &p_sys->pids, &pidnextctx )) )
260 if( !SEEN(p_pid) || p_pid->probed.i_fourcc == 0 )
261 continue;
263 if( p_pid->probed.i_pcr_count && candidates[0] == NULL && false )
264 candidates[0] = p_pid;
266 if( p_pid->probed.i_cat == AUDIO_ES &&
267 (candidates[1] == NULL ||
268 candidates[1]->probed.i_dts_count > p_pid->probed.i_dts_count) )
269 candidates[1] = p_pid;
271 if( candidates[2] == NULL && p_pid != candidates[1] &&
272 p_pid->probed.i_dts_count > 0 )
273 candidates[2] = p_pid;
275 if( candidates[3] == NULL )
276 candidates[3] = p_pid;
278 i_num_pes++;
281 for(int i=0; i<4; i++)
283 if(!candidates[i])
284 continue;
285 i_pcr_pid = candidates[i]->i_pid;
286 p_sys->patfix.b_pcrhasnopcrfield = (candidates[i]->probed.i_pcr_count < 1);
287 break;
290 if( i_num_pes == 0 )
291 return;
293 tsmux_stream_t patstream =
295 .i_pid = 0,
296 .i_continuity_counter = 0x10,
297 .b_discontinuity = false
300 tsmux_stream_t pmtprogramstream =
302 .i_pid = i_program_pid,
303 .i_continuity_counter = 0x0,
304 .b_discontinuity = false
307 BuildPAT( GetPID(p_sys, 0)->u.p_pat->handle,
308 &p_sys->pids.pat, BuildPATCallback,
309 0, 1,
310 &patstream,
311 1, &pmtprogramstream, &i_program_number );
313 /* PAT callback should have been triggered */
314 if( p_program_pid->type != TYPE_PMT )
316 msg_Err( p_demux, "PAT creation failed" );
317 return;
320 ts_mux_standard mux_standard = (p_sys->standard == TS_STANDARD_ATSC) ? TS_MUX_STANDARD_ATSC
321 : TS_MUX_STANDARD_DVB;
322 struct esstreams_t
324 pesmux_stream_t pes;
325 tsmux_stream_t ts;
326 es_format_t fmt;
329 struct esstreams_t *esstreams = calloc( i_num_pes, sizeof(struct esstreams_t) );
330 pes_mapped_stream_t *mapped = calloc( i_num_pes, sizeof(pes_mapped_stream_t) );
331 if( esstreams && mapped )
333 int j=0;
334 for( int i=0; i<p_sys->pids.i_all; i++ )
336 p_pid = p_sys->pids.pp_all[i];
338 if( !SEEN(p_pid) ||
339 p_pid->probed.i_fourcc == 0 )
340 continue;
342 es_format_Init(&esstreams[j].fmt, p_pid->probed.i_cat, p_pid->probed.i_fourcc);
343 esstreams[j].fmt.i_original_fourcc = p_pid->probed.i_original_fourcc;
345 if( VLC_SUCCESS !=
346 FillPMTESParams(mux_standard, &esstreams[j].fmt, &esstreams[j].ts, &esstreams[j].pes ) )
348 es_format_Clean( &esstreams[j].fmt );
349 continue;
352 /* Important for correct remapping: Enforce probed PES stream id */
353 esstreams[j].pes.i_stream_id = p_pid->probed.i_stream_id;
355 esstreams[j].ts.i_pid = p_pid->i_pid;
356 mapped[j].pes = &esstreams[j].pes;
357 mapped[j].ts = &esstreams[j].ts;
358 mapped[j].fmt = &esstreams[j].fmt;
359 j++;
362 BuildPMT( GetPID(p_sys, 0)->u.p_pat->handle, VLC_OBJECT(p_demux),
363 mux_standard,
364 p_program_pid, BuildPMTCallback,
365 0, 1,
366 i_pcr_pid,
367 NULL,
368 1, &pmtprogramstream, &i_program_number,
369 j, mapped );
371 /* Cleanup */
372 for( int i=0; i<j; i++ )
373 es_format_Clean( &esstreams[i].fmt );
375 free(esstreams);
376 free(mapped);