]> git.sesse.net Git - vlc/blob - src/input/input_dec.c
* all: ported/cleaned up/renabled dvb subtitle decoder. But it is untested.
[vlc] / src / input / input_dec.c
1 /*****************************************************************************
2  * input_dec.c: Functions for the management of decoders
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: input_dec.c,v 1.77 2003/11/24 02:35:50 fenrir Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Gildas Bazin <gbazin@netcourrier.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <string.h>                                    /* memcpy(), memset() */
30
31 #include <vlc/vlc.h>
32 #include <vlc/decoder.h>
33 #include <vlc/vout.h>
34
35 #include "stream_output.h"
36
37 #include "input_ext-intf.h"
38 #include "input_ext-plugins.h"
39
40 #include "codecs.h"
41
42 static decoder_t * CreateDecoder( input_thread_t *, es_descriptor_t *, int );
43 static int         DecoderThread( decoder_t * );
44 static void        DeleteDecoder( decoder_t * );
45
46 /* Buffers allocation callbacks for the decoders */
47 static aout_buffer_t *aout_new_buffer( decoder_t *, int );
48 static void aout_del_buffer( decoder_t *, aout_buffer_t * );
49
50 static picture_t *vout_new_buffer( decoder_t * );
51 static void vout_del_buffer( decoder_t *, picture_t * );
52
53 static es_format_t null_es_format = {0};
54
55 struct decoder_owner_sys_t
56 {
57     aout_instance_t *p_aout;
58     aout_input_t    *p_aout_input;
59
60     vout_thread_t   *p_vout;
61
62     sout_packetizer_input_t *p_sout;
63
64     /* Current format in use by the output */
65     video_format_t video;
66     audio_format_t audio;
67     es_format_t    sout;
68
69     /* fifo */
70     block_fifo_t *p_fifo;
71 };
72
73
74 /*****************************************************************************
75  * input_RunDecoder: spawns a new decoder thread
76  *****************************************************************************/
77 decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
78 {
79     decoder_t      *p_dec = NULL;
80     vlc_value_t    val;
81     int            i_priority;
82
83     /* If we are in sout mode, search for packetizer module */
84     var_Get( p_input, "sout", &val );
85     if( !p_es->b_force_decoder && val.psz_string && *val.psz_string )
86     {
87         free( val.psz_string );
88         val.b_bool = VLC_TRUE;
89
90         if( p_es->i_cat == AUDIO_ES )
91         {
92             var_Get( p_input, "sout-audio", &val );
93         }
94         else if( p_es->i_cat == VIDEO_ES )
95         {
96             var_Get( p_input, "sout-video", &val );
97         }
98
99         if( val.b_bool )
100         {
101             /* Create the decoder configuration structure */
102             p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_PACKETIZER );
103             if( p_dec == NULL )
104             {
105                 msg_Err( p_input, "could not create packetizer" );
106                 return NULL;
107             }
108
109             p_dec->p_module =
110                 module_Need( p_dec, "packetizer", "$packetizer" );
111         }
112     }
113     else
114     {
115         /* Create the decoder configuration structure */
116         p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_DECODER );
117         if( p_dec == NULL )
118         {
119             msg_Err( p_input, "could not create decoder" );
120             return NULL;
121         }
122
123         /* default Get a suitable decoder module */
124         p_dec->p_module = module_Need( p_dec, "decoder", "$codec" );
125
126         if( val.psz_string ) free( val.psz_string );
127     }
128
129     if( !p_dec || !p_dec->p_module )
130     {
131         msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
132                  "VLC probably does not support this sound or video format.",
133                  (char*)&p_dec->fmt_in.i_codec );
134
135         DeleteDecoder( p_dec );
136         vlc_object_destroy( p_dec );
137         return NULL;
138     }
139
140     if ( p_es->i_cat == AUDIO_ES )
141     {
142         i_priority = VLC_THREAD_PRIORITY_AUDIO;
143     }
144     else
145     {
146         i_priority = VLC_THREAD_PRIORITY_VIDEO;
147     }
148
149     /* Spawn the decoder thread */
150     if( vlc_thread_create( p_dec, "decoder", DecoderThread,
151                            i_priority, VLC_FALSE ) )
152     {
153         msg_Err( p_dec, "cannot spawn decoder thread \"%s\"",
154                          p_dec->p_module->psz_object_name );
155         module_Unneed( p_dec, p_dec->p_module );
156         DeleteDecoder( p_dec );
157         vlc_object_destroy( p_dec );
158         return NULL;
159     }
160
161     p_input->stream.b_changed = 1;
162
163     return p_dec;
164 }
165
166 /*****************************************************************************
167  * input_EndDecoder: kills a decoder thread and waits until it's finished
168  *****************************************************************************/
169 void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
170 {
171     decoder_t *p_dec = p_es->p_dec;
172     int i_dummy;
173
174     p_dec->b_die = VLC_TRUE;
175
176     /* Make sure the thread leaves the NextDataPacket() function by
177      * sending it a few null packets. */
178     for( i_dummy = 0; i_dummy < PADDING_PACKET_NUMBER; i_dummy++ )
179     {
180         input_NullPacket( p_input, p_es );
181     }
182
183     if( p_es->p_pes != NULL )
184     {
185         input_DecodePES( p_es->p_dec, p_es->p_pes );
186     }
187
188     /* Waiting for the thread to exit */
189     /* I thought that unlocking was better since thread join can be long
190      * but it actually creates late pictures and freezes --stef */
191     /* vlc_mutex_unlock( &p_input->stream.stream_lock ); */
192     vlc_thread_join( p_dec );
193     /* vlc_mutex_lock( &p_input->stream.stream_lock ); */
194
195 #if 0
196     /* XXX We don't do it here because of dll loader that want close in the
197      * same thread than open/decode */
198     /* Unneed module */
199     module_Unneed( p_dec, p_dec->p_module );
200 #endif
201
202     /* Delete decoder configuration */
203     DeleteDecoder( p_dec );
204
205     /* Delete the decoder */
206     vlc_object_destroy( p_dec );
207
208     /* Tell the input there is no more decoder */
209     p_es->p_dec = NULL;
210
211     p_input->stream.b_changed = 1;
212 }
213
214 /*****************************************************************************
215  * input_DecodePES
216  *****************************************************************************
217  * Put a PES in the decoder's fifo.
218  *****************************************************************************/
219 void input_DecodePES( decoder_t * p_dec, pes_packet_t * p_pes )
220 {
221     data_packet_t *p_data;
222     int     i_size = 0;
223
224     for( p_data = p_pes->p_first; p_data != NULL; p_data = p_data->p_next )
225     {
226         i_size += p_data->p_payload_end - p_data->p_payload_start;
227     }
228     if( i_size > 0 )
229     {
230         block_t *p_block = block_New( p_dec, i_size );
231         if( p_block )
232         {
233             uint8_t *p_buffer = p_block->p_buffer;
234
235             for( p_data = p_pes->p_first; p_data != NULL; p_data = p_data->p_next )
236             {
237                 int i_copy = p_data->p_payload_end - p_data->p_payload_start;
238
239                 memcpy( p_buffer, p_data->p_payload_start, i_copy );
240
241                 p_buffer += i_copy;
242             }
243             p_block->i_pts = p_pes->i_pts;
244             p_block->i_dts = p_pes->i_dts;
245             p_block->b_discontinuity = p_pes->b_discontinuity;
246
247             block_FifoPut( p_dec->p_owner->p_fifo, p_block );
248         }
249     }
250 }
251 /*****************************************************************************
252  * input_DecodeBlock
253  *****************************************************************************
254  * Put a block_t in the decoder's fifo.
255  *****************************************************************************/
256 void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
257 {
258     block_FifoPut( p_dec->p_owner->p_fifo, p_block );
259 }
260
261 /*****************************************************************************
262  * Create a NULL packet for padding in case of a data loss
263  *****************************************************************************/
264 void input_NullPacket( input_thread_t * p_input,
265                        es_descriptor_t * p_es )
266 {
267     data_packet_t *             p_pad_data;
268     pes_packet_t *              p_pes;
269
270     if( (p_pad_data = input_NewPacketForce( p_input->p_method_data,
271                     PADDING_PACKET_SIZE)) == NULL )
272     {
273         msg_Err( p_input, "no new packet" );
274         p_input->b_error = 1;
275         return;
276     }
277
278     memset( p_pad_data->p_payload_start, 0, PADDING_PACKET_SIZE );
279     p_pad_data->b_discard_payload = 1;
280     p_pes = p_es->p_pes;
281
282     if( p_pes != NULL )
283     {
284         p_pes->b_discontinuity = 1;
285         p_pes->p_last->p_next = p_pad_data;
286         p_pes->p_last = p_pad_data;
287         p_pes->i_nb_data++;
288     }
289     else
290     {
291         if( (p_pes = input_NewPES( p_input->p_method_data )) == NULL )
292         {
293             msg_Err( p_input, "no PES packet" );
294             p_input->b_error = 1;
295             return;
296         }
297
298         p_pes->i_rate = p_input->stream.control.i_rate;
299         p_pes->p_first = p_pes->p_last = p_pad_data;
300         p_pes->i_nb_data = 1;
301         p_pes->b_discontinuity = 1;
302         input_DecodePES( p_es->p_dec, p_pes );
303     }
304 }
305
306 /*****************************************************************************
307  * input_EscapeDiscontinuity: send a NULL packet to the decoders
308  *****************************************************************************/
309 void input_EscapeDiscontinuity( input_thread_t * p_input )
310 {
311     unsigned int i_es, i;
312
313     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
314     {
315         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
316
317         if( p_es->p_dec != NULL )
318         {
319             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
320             {
321                 input_NullPacket( p_input, p_es );
322             }
323         }
324     }
325 }
326
327 /*****************************************************************************
328  * input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders
329  *****************************************************************************/
330 void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
331 {
332     unsigned int i_es, i;
333
334     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
335     {
336         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
337
338         if( p_es->p_dec != NULL && p_es->i_cat == AUDIO_ES )
339         {
340             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
341             {
342                 input_NullPacket( p_input, p_es );
343             }
344         }
345     }
346 }
347
348 /*****************************************************************************
349  * CreateDecoder: create a decoder object
350  *****************************************************************************/
351 static decoder_t * CreateDecoder( input_thread_t * p_input,
352                                   es_descriptor_t * p_es, int i_object_type )
353 {
354     decoder_t *p_dec;
355
356     p_dec = vlc_object_create( p_input, i_object_type );
357     if( p_dec == NULL )
358     {
359         msg_Err( p_input, "out of memory" );
360         return NULL;
361     }
362
363     p_dec->pf_decode_audio = 0;
364     p_dec->pf_decode_video = 0;
365     p_dec->pf_decode_sub = 0;
366     p_dec->pf_packetize = 0;
367
368     /* Select a new ES */
369     INSERT_ELEM( p_input->stream.pp_selected_es,
370                  p_input->stream.i_selected_es_number,
371                  p_input->stream.i_selected_es_number,
372                  p_es );
373
374     /* Initialize the decoder fifo */
375     p_dec->p_module = NULL;
376
377     p_dec->fmt_in = p_es->fmt;
378
379     if( p_es->p_waveformatex )
380     {
381 #define p_wf ((WAVEFORMATEX *)p_es->p_waveformatex)
382         p_dec->fmt_in.audio.i_channels = p_wf->nChannels;
383         p_dec->fmt_in.audio.i_rate = p_wf->nSamplesPerSec;
384         p_dec->fmt_in.i_bitrate = p_wf->nAvgBytesPerSec * 8;
385         p_dec->fmt_in.audio.i_blockalign = p_wf->nBlockAlign;
386         p_dec->fmt_in.audio.i_bitspersample = p_wf->wBitsPerSample;
387         p_dec->fmt_in.i_extra = p_wf->cbSize;
388         p_dec->fmt_in.p_extra = NULL;
389         if( p_wf->cbSize )
390         {
391             p_dec->fmt_in.p_extra = malloc( p_wf->cbSize );
392             memcpy( p_dec->fmt_in.p_extra, &p_wf[1], p_wf->cbSize );
393         }
394     }
395
396     if( p_es->p_bitmapinfoheader )
397     {
398 #define p_bih ((BITMAPINFOHEADER *) p_es->p_bitmapinfoheader)
399         p_dec->fmt_in.i_extra = p_bih->biSize - sizeof(BITMAPINFOHEADER);
400         p_dec->fmt_in.p_extra = NULL;
401         if( p_dec->fmt_in.i_extra )
402         {
403             p_dec->fmt_in.p_extra = malloc( p_dec->fmt_in.i_extra );
404             memcpy( p_dec->fmt_in.p_extra, &p_bih[1], p_dec->fmt_in.i_extra );
405         }
406
407         p_dec->fmt_in.video.i_width = p_bih->biWidth;
408         p_dec->fmt_in.video.i_height = p_bih->biHeight;
409     }
410
411     /* FIXME
412      *  - 1: beurk
413      *  - 2: I'm not sure there isn't any endian problem here (spu)... */
414     if( p_es->i_cat == SPU_ES && p_es->p_demux_data )
415     {
416         if( ( p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', ' ' ) ||
417               p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', 'b' ) ) &&
418             *((uint32_t*)p_es->p_demux_data) == 0xBeef )
419         {
420             memcpy( p_dec->fmt_in.subs.spu.palette,
421                     p_es->p_demux_data, 17 * 4 );
422         }
423         else if( p_es->i_fourcc == VLC_FOURCC( 'd', 'v', 'b', 's' ) )
424         {
425             dvb_spuinfo_t *p_dvbs = (dvb_spuinfo_t*)p_es->p_demux_data;
426
427             p_dec->fmt_in.subs.dvb.i_id = p_dvbs->i_id;
428         }
429     }
430
431     p_dec->fmt_in.i_cat = p_es->i_cat;
432     p_dec->fmt_in.i_codec = p_es->i_fourcc;
433
434     p_dec->fmt_out = null_es_format;
435
436     /* Allocate our private structure for the decoder */
437     p_dec->p_owner = (decoder_owner_sys_t*)malloc(sizeof(decoder_owner_sys_t));
438     if( p_dec->p_owner == NULL )
439     {
440         msg_Err( p_dec, "out of memory" );
441         return NULL;
442     }
443     p_dec->p_owner->p_aout = NULL;
444     p_dec->p_owner->p_aout_input = NULL;
445     p_dec->p_owner->p_vout = NULL;
446     p_dec->p_owner->p_sout = NULL;
447     /* decoder fifo */
448     if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL )
449     {
450         msg_Err( p_dec, "out of memory" );
451         return NULL;
452     }
453
454     /* Set buffers allocation callbacks for the decoders */
455     p_dec->pf_aout_buffer_new = aout_new_buffer;
456     p_dec->pf_aout_buffer_del = aout_del_buffer;
457     p_dec->pf_vout_buffer_new = vout_new_buffer;
458     p_dec->pf_vout_buffer_del = vout_del_buffer;
459
460     vlc_object_attach( p_dec, p_input );
461
462     return p_dec;
463 }
464
465 /*****************************************************************************
466  * DecoderThread: the decoding main loop
467  *****************************************************************************/
468 static int DecoderThread( decoder_t * p_dec )
469 {
470     block_t       *p_block;
471
472     /* The decoder's main loop */
473     while( !p_dec->b_die && !p_dec->b_error )
474     {
475         if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL )
476         {
477             p_dec->b_error = 1;
478             break;
479         }
480
481         if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER )
482         {
483             block_t *p_sout_block;
484
485             while( (p_sout_block = p_dec->pf_packetize( p_dec, &p_block )) )
486             {
487                 if( !p_dec->p_owner->p_sout )
488                 {
489                     es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out );
490
491                     p_dec->p_owner->p_sout =
492                         sout_InputNew( p_dec, &p_dec->p_owner->sout );
493
494                     if( p_dec->p_owner->p_sout == NULL )
495                     {
496                         msg_Err( p_dec, "cannot create packetizer output" );
497                         p_dec->b_error = VLC_TRUE;
498
499                         while( p_sout_block )
500                         {
501                             block_t       *p_next = p_sout_block->p_next;
502                             block_Release( p_sout_block );
503                             p_sout_block = p_next;
504                         }
505                         break;
506                     }
507                 }
508
509                 while( p_sout_block )
510                 {
511                     block_t       *p_next = p_sout_block->p_next;
512                     sout_buffer_t *p_sout_buffer;
513
514                     p_sout_buffer =
515                         sout_BufferNew( p_dec->p_owner->p_sout->p_sout,
516                                         p_sout_block->i_buffer );
517                     if( p_sout_buffer == NULL )
518                     {
519                         msg_Err( p_dec, "cannot get sout buffer" );
520                         break;
521                     }
522
523                     memcpy( p_sout_buffer->p_buffer, p_sout_block->p_buffer,
524                             p_sout_block->i_buffer );
525
526                     p_sout_buffer->i_pts = p_sout_block->i_pts;
527                     p_sout_buffer->i_dts = p_sout_block->i_dts;
528                     p_sout_buffer->i_length = p_sout_block->i_length;
529
530                     block_Release( p_sout_block );
531
532                     sout_InputSendBuffer( p_dec->p_owner->p_sout, p_sout_buffer );
533
534                     p_sout_block = p_next;
535                 }
536             }
537         }
538         else if( p_dec->fmt_in.i_cat == AUDIO_ES )
539         {
540             aout_buffer_t *p_aout_buf;
541
542             while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
543             {
544                 aout_DecPlay( p_dec->p_owner->p_aout,
545                               p_dec->p_owner->p_aout_input, p_aout_buf );
546             }
547         }
548         else if( p_dec->fmt_in.i_cat == VIDEO_ES )
549         {
550             picture_t *p_pic;
551
552             while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
553             {
554                 vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date );
555                 vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
556             }
557         }
558         else if( p_dec->fmt_in.i_cat == SPU_ES )
559         {
560             p_dec->pf_decode_sub( p_dec, &p_block );
561         }
562         else
563         {
564             msg_Err( p_dec, "unknown ES format !!" );
565             p_dec->b_error = 1;
566             break;
567         }
568     }
569
570     while( !p_dec->b_die )
571     {
572         /* Trash all received PES packets */
573         p_block = block_FifoGet( p_dec->p_owner->p_fifo );
574         if( p_block )
575         {
576             block_Release( p_block );
577         }
578     }
579
580     /* XXX We do it here because of dll loader that want close in the
581      * same thread than open/decode */
582     /* Unneed module */
583     module_Unneed( p_dec, p_dec->p_module );
584
585     return 0;
586 }
587
588 /*****************************************************************************
589  * DeleteDecoder: destroys a decoder object
590  *****************************************************************************/
591 static void DeleteDecoder( decoder_t * p_dec )
592 {
593     vlc_object_detach( p_dec );
594
595     msg_Dbg( p_dec,
596              "killing decoder fourcc `%4.4s', %d PES in FIFO",
597              (char*)&p_dec->fmt_in.i_codec,
598              p_dec->p_owner->p_fifo->i_depth );
599
600     /* Free all packets still in the decoder fifo. */
601     block_FifoEmpty( p_dec->p_owner->p_fifo );
602     block_FifoRelease( p_dec->p_owner->p_fifo );
603
604    /* Cleanup */
605     if( p_dec->p_owner->p_aout_input )
606         aout_DecDelete( p_dec->p_owner->p_aout, p_dec->p_owner->p_aout_input );
607
608     if( p_dec->p_owner->p_vout )
609     {
610         int i_pic;
611
612         /* Hack to make sure all the the pictures are freed by the decoder */
613         for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
614              i_pic++ )
615         {
616             if( p_dec->p_owner->p_vout->render.pp_picture[i_pic]->i_status ==
617                 RESERVED_PICTURE )
618                 vout_DestroyPicture( p_dec->p_owner->p_vout,
619                     p_dec->p_owner->p_vout->render.pp_picture[i_pic] );
620             if( p_dec->p_owner->p_vout->render.pp_picture[i_pic]->i_refcount
621                 > 0 )
622                 vout_UnlinkPicture( p_dec->p_owner->p_vout,
623                     p_dec->p_owner->p_vout->render.pp_picture[i_pic] );
624         }
625
626         /* We are about to die. Reattach video output to p_vlc. */
627         vout_Request( p_dec, p_dec->p_owner->p_vout, 0, 0, 0, 0 );
628     }
629
630     if( p_dec->p_owner->p_sout )
631         sout_InputDelete( p_dec->p_owner->p_sout );
632
633     free( p_dec->p_owner );
634 }
635
636 /*****************************************************************************
637  * Buffers allocation callbacks for the decoders
638  *****************************************************************************/
639 static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
640 {
641     decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
642     aout_buffer_t *p_buffer;
643
644     if( p_sys->p_aout_input != NULL &&
645         ( p_dec->fmt_out.audio.i_rate != p_sys->audio.i_rate ||
646           p_dec->fmt_out.audio.i_original_channels !=
647               p_sys->audio.i_original_channels ||
648           p_dec->fmt_out.audio.i_bytes_per_frame !=
649               p_sys->audio.i_bytes_per_frame ) )
650     {
651         /* Parameters changed, restart the aout */
652         aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
653         p_sys->p_aout_input = NULL;
654     }
655
656     if( p_sys->p_aout_input == NULL )
657     {
658         p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
659         p_sys->audio = p_dec->fmt_out.audio;
660         p_sys->p_aout_input =
661             aout_DecNew( p_dec, &p_sys->p_aout, &p_sys->audio );
662         if( p_sys->p_aout_input == NULL )
663         {
664             msg_Err( p_dec, "failed to create audio output" );
665             p_dec->b_error = VLC_TRUE;
666             return NULL;
667         }
668         p_dec->fmt_out.audio.i_bytes_per_frame =
669             p_sys->audio.i_bytes_per_frame;
670     }
671
672     p_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
673                                   i_samples );
674
675     return p_buffer;
676 }
677
678 static void aout_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
679 {
680     aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
681                           p_dec->p_owner->p_aout_input, p_buffer );
682 }
683
684 static picture_t *vout_new_buffer( decoder_t *p_dec )
685 {
686     decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
687     picture_t *p_pic;
688
689     if( p_sys->p_vout == NULL ||
690         p_dec->fmt_out.video.i_width != p_sys->video.i_width ||
691         p_dec->fmt_out.video.i_height != p_sys->video.i_height ||
692         p_dec->fmt_out.video.i_chroma != p_sys->video.i_chroma ||
693         p_dec->fmt_out.video.i_aspect != p_sys->video.i_aspect )
694     {
695         if( !p_dec->fmt_out.video.i_width ||
696             !p_dec->fmt_out.video.i_height )
697         {
698             /* Can't create a new vout without display size */
699             return NULL;
700         }
701
702         p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
703         p_sys->video = p_dec->fmt_out.video;
704
705         p_sys->p_vout = vout_Request( p_dec, p_sys->p_vout,
706                                       p_sys->video.i_width,
707                                       p_sys->video.i_height,
708                                       p_sys->video.i_chroma,
709                                       p_sys->video.i_aspect );
710
711         if( p_sys->p_vout == NULL )
712         {
713             msg_Err( p_dec, "failed to create video output" );
714             p_dec->b_error = VLC_TRUE;
715             return NULL;
716         }
717     }
718
719     /* Get a new picture */
720     while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
721     {
722         if( p_dec->b_die || p_dec->b_error )
723         {
724             return NULL;
725         }
726         msleep( VOUT_OUTMEM_SLEEP );
727     }
728
729     return p_pic;
730 }
731
732 static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic )
733 {
734     vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
735 }