demux: mp4: use struct for coreaudio layout params
[vlc.git] / modules / demux / pva.c
blobdaf0b42ad67d435a44933cbdfb255570b57f68c8
1 /*****************************************************************************
2 * pva.c: PVA demuxer
3 *****************************************************************************
4 * Copyright (C) 2004 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
36 #include "mpeg/pes.h"
38 /*****************************************************************************
39 * Module descriptor
40 *****************************************************************************/
41 static int Open ( vlc_object_t * );
42 static void Close ( vlc_object_t * );
44 vlc_module_begin ()
45 set_description( N_("PVA demuxer" ) )
46 set_capability( "demux", 10 )
47 set_category( CAT_INPUT )
48 set_subcategory( SUBCAT_INPUT_DEMUX )
49 set_callbacks( Open, Close )
50 add_shortcut( "pva" )
51 vlc_module_end ()
53 /*****************************************************************************
54 * Local prototypes
55 *****************************************************************************/
57 typedef struct
59 es_out_id_t *p_video;
60 es_out_id_t *p_audio;
62 /* counter */
63 int i_vc;
64 int i_ac;
66 /* audio/video block */
67 block_t *p_pes; /* audio */
68 block_t *p_es; /* video */
70 int64_t b_pcr_audio;
71 } demux_sys_t;
73 static int Demux ( demux_t *p_demux );
74 static int Control ( demux_t *p_demux, int i_query, va_list args );
76 static int ReSynch ( demux_t * );
77 static void ParsePES( demux_t * );
79 /*****************************************************************************
80 * Open
81 *****************************************************************************/
82 static int Open( vlc_object_t *p_this )
84 demux_t *p_demux = (demux_t*)p_this;
85 demux_sys_t *p_sys;
86 es_format_t fmt;
87 const uint8_t *p_peek;
89 if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 ) return VLC_EGENERIC;
90 if( p_peek[0] != 'A' || p_peek[1] != 'V' || p_peek[4] != 0x55 )
92 /* In case we had forced this demuxer we try to resynch */
93 if( !p_demux->obj.force || ReSynch( p_demux ) )
94 return VLC_EGENERIC;
97 p_sys = malloc( sizeof( demux_sys_t ) );
98 if( unlikely(p_sys == NULL) )
99 return VLC_ENOMEM;
101 /* Fill p_demux field */
102 p_demux->pf_demux = Demux;
103 p_demux->pf_control = Control;
104 p_demux->p_sys = p_sys;
106 /* Register one audio and one video stream */
107 es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_MPGA );
108 fmt.b_packetized = false;
109 p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
111 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_MPGV );
112 fmt.b_packetized = false;
113 p_sys->p_video = es_out_Add( p_demux->out, &fmt );
115 p_sys->i_vc = -1;
116 p_sys->i_ac = -1;
117 p_sys->p_pes = NULL;
118 p_sys->p_es = NULL;
120 p_sys->b_pcr_audio = false;
122 return VLC_SUCCESS;
125 /*****************************************************************************
126 * Close
127 *****************************************************************************/
128 static void Close( vlc_object_t *p_this )
130 demux_t *p_demux = (demux_t*)p_this;
131 demux_sys_t *p_sys = p_demux->p_sys;
133 block_ChainRelease( p_sys->p_es );
134 block_ChainRelease( p_sys->p_pes );
136 free( p_sys );
140 /*****************************************************************************
141 * Demux:
142 *****************************************************************************
143 * See http://multimedia.cx/mirror/av_format_v1.pdf
144 *****************************************************************************/
145 static int Demux( demux_t *p_demux )
147 demux_sys_t *p_sys = p_demux->p_sys;
149 const uint8_t *p_peek;
150 int i_size;
151 block_t *p_frame;
152 int64_t i_pts;
153 int i_skip;
155 if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
157 msg_Warn( p_demux, "eof ?" );
158 return VLC_DEMUXER_EOF;
160 if( p_peek[0] != 'A' || p_peek[1] != 'V' || p_peek[4] != 0x55 )
162 msg_Warn( p_demux, "lost synchro" );
163 if( ReSynch( p_demux ) )
165 return VLC_DEMUXER_EGENERIC;
167 if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
169 msg_Warn( p_demux, "eof ?" );
170 return VLC_DEMUXER_EOF;
174 i_size = GetWBE( &p_peek[6] );
175 switch( p_peek[2] )
177 case 0x01: /* VideoStream */
178 if( p_sys->i_vc < 0 )
180 msg_Dbg( p_demux, "first packet for video" );
182 else if( ((p_sys->i_vc + 1)&0xff) != p_peek[3] )
184 msg_Dbg( p_demux, "packet lost (video)" );
185 if( p_sys->p_es )
187 block_ChainRelease( p_sys->p_es );
188 p_sys->p_es = NULL;
191 p_sys->i_vc = p_peek[3];
193 /* read the PTS and potential extra bytes TODO: make it a bit more optimised */
194 i_pts = -1;
195 i_skip = 8;
196 if( p_peek[5]&0x10 )
198 int i_pre = p_peek[5]&0x3;
200 if( ( p_frame = vlc_stream_Block( p_demux->s, 8 + 4 + i_pre ) ) )
202 i_pts = GetDWBE( &p_frame->p_buffer[8] );
203 if( p_frame->i_buffer > 12 )
205 p_frame->p_buffer += 12;
206 p_frame->i_buffer -= 12;
207 block_ChainAppend( &p_sys->p_es, p_frame );
209 else
211 block_Release( p_frame );
214 i_size -= 4 + i_pre;
215 i_skip = 0;
216 /* Set PCR */
217 if( ( p_frame = p_sys->p_es ) )
220 if( p_frame->i_pts != VLC_TICK_INVALID && !p_sys->b_pcr_audio )
222 es_out_SetPCR( p_demux->out, p_frame->i_pts);
225 p_frame = block_ChainGather( p_frame );
226 if( likely(p_frame) )
227 es_out_Send( p_demux->out, p_sys->p_video, p_frame );
229 p_sys->p_es = NULL;
233 if( ( p_frame = vlc_stream_Block( p_demux->s, i_size + i_skip ) ) )
235 p_frame->p_buffer += i_skip;
236 p_frame->i_buffer -= i_skip;
237 if( i_pts >= 0 )
238 p_frame->i_pts = FROM_SCALE(i_pts);
239 block_ChainAppend( &p_sys->p_es, p_frame );
241 break;
243 case 0x02: /* MainAudioStream */
244 if( p_sys->i_ac < 0 )
246 msg_Dbg( p_demux, "first packet for audio" );
248 else if( ((p_sys->i_ac + 1)&0xff) != p_peek[3] )
250 msg_Dbg( p_demux, "packet lost (audio)" );
251 if( p_sys->p_pes )
253 block_ChainRelease( p_sys->p_pes );
254 p_sys->p_pes = NULL;
257 p_sys->i_ac = p_peek[3];
259 if( p_peek[5]&0x10 && p_sys->p_pes )
261 ParsePES( p_demux );
263 if( ( p_frame = vlc_stream_Block( p_demux->s, i_size + 8 ) ) )
265 p_frame->p_buffer += 8;
266 p_frame->i_buffer -= 8;
267 /* XXX this a hack, some streams aren't compliant and
268 * don't set pes_start flag */
269 if( p_sys->p_pes && p_frame->i_buffer > 4 &&
270 p_frame->p_buffer[0] == 0x00 &&
271 p_frame->p_buffer[1] == 0x00 &&
272 p_frame->p_buffer[2] == 0x01 )
274 ParsePES( p_demux );
276 block_ChainAppend( &p_sys->p_pes, p_frame );
278 break;
280 default:
281 msg_Warn( p_demux, "unknown id=0x%x", p_peek[2] );
282 if( vlc_stream_Read( p_demux->s, NULL, i_size + 8 ) < i_size + 8 )
283 return VLC_DEMUXER_EOF;
284 break;
286 return VLC_DEMUXER_SUCCESS;
289 /*****************************************************************************
290 * Control:
291 *****************************************************************************/
292 static int Control( demux_t *p_demux, int i_query, va_list args )
294 /* demux_sys_t *p_sys = p_demux->p_sys; */
295 double f, *pf;
296 int64_t i64;
297 switch( i_query )
299 case DEMUX_CAN_SEEK:
300 return vlc_stream_vaControl( p_demux->s, i_query, args );
302 case DEMUX_GET_POSITION:
303 if( ( i64 = stream_Size( p_demux->s ) ) > 0 )
305 pf = va_arg( args, double * );
306 double current = vlc_stream_Tell( p_demux->s );
307 *pf = current / (double)i64;
308 return VLC_SUCCESS;
310 return VLC_EGENERIC;
312 case DEMUX_SET_POSITION:
313 f = va_arg( args, double );
314 i64 = stream_Size( p_demux->s );
316 if( vlc_stream_Seek( p_demux->s, (int64_t)(i64 * f) ) || ReSynch( p_demux ) )
318 return VLC_EGENERIC;
320 return VLC_SUCCESS;
322 #if 0
323 case DEMUX_GET_TIME:
324 pi64 = va_arg( args, vlc_tick_t * );
325 if( p_sys->i_time < 0 )
327 *pi64 = 0;
328 return VLC_EGENERIC;
330 *pi64 = p_sys->i_time;
331 return VLC_SUCCESS;
333 #if 0
334 case DEMUX_GET_LENGTH:
335 pi64 = va_arg( args, vlc_tick_t * );
336 if( p_sys->i_mux_rate > 0 )
338 *pi64 = vlc_tick_from_samples( stream_Size( p_demux->s ) / 50, p_sys->i_mux_rate);
339 return VLC_SUCCESS;
341 *pi64 = 0;
342 return VLC_EGENERIC;
344 #endif
345 case DEMUX_GET_FPS:
346 pf = va_arg( args, double * );
347 *pf = (double)1000000.0 / (double)p_sys->i_pcr_inc;
348 return VLC_SUCCESS;
349 #endif
350 case DEMUX_CAN_PAUSE:
351 case DEMUX_SET_PAUSE_STATE:
352 case DEMUX_CAN_CONTROL_PACE:
353 case DEMUX_GET_PTS_DELAY:
354 return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );
356 case DEMUX_SET_TIME:
357 default:
358 return VLC_EGENERIC;
362 /*****************************************************************************
363 * ReSynch:
364 *****************************************************************************/
365 static int ReSynch( demux_t *p_demux )
367 for( ;; )
369 const uint8_t *p_peek;
370 int i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 1024 );
371 if( i_peek < 8 )
372 break;
374 int i_skip = 0;
376 while( i_skip < i_peek - 5 )
378 if( p_peek[0] == 'A' && p_peek[1] == 'V' && p_peek[4] == 0x55 )
380 if( i_skip > 0
381 && vlc_stream_Read( p_demux->s, NULL, i_skip ) < i_skip )
382 return VLC_EGENERIC;
383 return VLC_SUCCESS;
385 p_peek++;
386 i_skip++;
389 if( vlc_stream_Read( p_demux->s, NULL, i_skip ) < i_skip )
390 break;
393 return VLC_EGENERIC;
396 static void ParsePES( demux_t *p_demux )
398 demux_sys_t *p_sys = p_demux->p_sys;
399 block_t *p_pes = p_sys->p_pes;
400 uint8_t hdr[30];
402 unsigned i_skip;
403 stime_t i_dts = -1;
404 stime_t i_pts = -1;
406 p_sys->p_pes = NULL;
408 /* FIXME find real max size */
409 block_ChainExtract( p_pes, hdr, 30 );
411 /* See ยง2.4.3.6 of ISO 13818-1 */
412 if( hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 1 )
414 msg_Warn( p_demux, "invalid hdr [0x%2.2x:%2.2x:%2.2x:%2.2x]",
415 hdr[0], hdr[1],hdr[2],hdr[3] );
416 block_ChainRelease( p_pes );
417 return;
419 // hdr[4] i_pes_size, 2 bytes
420 // hdr[6] Marker -> original_or_copy
422 /* we assume mpeg2 PES */
423 i_skip = hdr[8] + 9;
424 if( hdr[7]&0x80 ) /* has pts */
426 i_pts = GetPESTimestamp( &hdr[9] );
428 if( hdr[7]&0x40 ) /* has dts */
430 i_dts = GetPESTimestamp( &hdr[14] );
434 p_pes = block_ChainGather( p_pes );
435 if( unlikely(p_pes == NULL) )
436 return;
437 if( p_pes->i_buffer <= i_skip )
439 block_ChainRelease( p_pes );
440 return;
443 p_pes->i_buffer -= i_skip;
444 p_pes->p_buffer += i_skip;
446 if( i_dts >= 0 )
447 p_pes->i_dts = FROM_SCALE(i_dts);
448 if( i_pts >= 0 )
449 p_pes->i_pts = FROM_SCALE(i_pts);
451 /* Set PCR */
452 if( p_pes->i_pts != VLC_TICK_INVALID )
454 es_out_SetPCR( p_demux->out, p_pes->i_pts);
455 p_sys->b_pcr_audio = true;
457 es_out_Send( p_demux->out, p_sys->p_audio, p_pes );