]> git.sesse.net Git - vlc/blob - plugins/ffmpeg/ffmpeg.c
* include/video.h : added new fourcc code for avi
[vlc] / plugins / ffmpeg / ffmpeg.c
1 /*****************************************************************************
2  * ffmpeg.c: video decoder using ffmpeg library
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: ffmpeg.c,v 1.9 2002/05/13 21:55:30 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <videolan/vlc.h>
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>                                              /* getpid() */
33 #endif
34
35 #include <errno.h>
36 #include <string.h>
37
38 #ifdef HAVE_SYS_TIMES_H
39 #   include <sys/times.h>
40 #endif
41
42 #include "video.h"
43 #include "video_output.h"
44
45 #include "stream_control.h"
46 #include "input_ext-dec.h"
47 #include "input_ext-intf.h"
48 #include "input_ext-plugins.h"
49
50
51 #include "vdec_ext-plugins.h"
52 #include "avcodec.h"                                            /* ffmpeg */
53 #include "ffmpeg.h"
54
55 /*
56  * Local prototypes
57  */
58 static int      decoder_Probe   ( u8 * );
59 static int      decoder_Run     ( decoder_config_t * );
60 static int      InitThread      ( videodec_thread_t * );
61 static void     EndThread       ( videodec_thread_t * );
62 static void     DecodeThread    ( videodec_thread_t * );
63
64
65 static int      b_ffmpeginit = 0;
66
67 /*****************************************************************************
68  * Capabilities
69  *****************************************************************************/
70 void _M( vdec_getfunctions )( function_list_t * p_function_list )
71 {
72     p_function_list->functions.dec.pf_probe = decoder_Probe;
73     p_function_list->functions.dec.pf_run   = decoder_Run;
74 }
75
76 /*****************************************************************************
77  * Build configuration tree.
78  *****************************************************************************/
79
80 MODULE_CONFIG_START
81 MODULE_CONFIG_STOP
82
83 MODULE_INIT_START
84     SET_DESCRIPTION( "ffmpeg video decoder (MSMPEG4v123,MPEG4)" )
85     ADD_CAPABILITY( DECODER, 70 )
86     ADD_SHORTCUT( "ffmpeg" )
87 MODULE_INIT_STOP
88
89 MODULE_ACTIVATE_START
90     _M( vdec_getfunctions )( &p_module->p_functions->dec );
91 MODULE_ACTIVATE_STOP
92
93 MODULE_DEACTIVATE_START
94 MODULE_DEACTIVATE_STOP
95
96
97 static __inline__ u16 __GetWordLittleEndianFromBuff( byte_t *p_buff )
98 {
99     u16 i;
100     i = (*p_buff) + ( *(p_buff + 1) <<8 );
101     return ( i );
102 }
103
104 static __inline__ u32 __GetDoubleWordLittleEndianFromBuff( byte_t *p_buff )
105 {
106     u32 i;
107     i = (*p_buff) + ( *(p_buff + 1) <<8 ) + 
108                 ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 );
109     return ( i );
110 }
111
112 /*****************************************************************************
113  * decoder_Probe: probe the decoder and return score
114  *****************************************************************************
115  * Tries to launch a decoder and return score so that the interface is able 
116  * to chose.
117  *****************************************************************************/
118 static int decoder_Probe( u8 *pi_type )
119 {
120     switch( *pi_type )
121     {
122 #if LIBAVCODEC_BUILD >= 4608
123         case( MSMPEG4v1_VIDEO_ES):
124         case( MSMPEG4v2_VIDEO_ES):
125 #endif
126         case( MSMPEG4v3_VIDEO_ES):
127         case( MPEG4_VIDEO_ES ):
128             return( 0 );
129         default:
130             return( -1 );
131     }
132 }
133
134 /*****************************************************************************
135  * Functions locales 
136  *****************************************************************************/
137
138 static void __ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
139 {
140     h->i_size          = __GetDoubleWordLittleEndianFromBuff( p_data );
141     h->i_width         = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
142     h->i_height        = __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
143     h->i_planes        = __GetWordLittleEndianFromBuff( p_data + 12 );
144     h->i_bitcount      = __GetWordLittleEndianFromBuff( p_data + 14 );
145     h->i_compression   = __GetDoubleWordLittleEndianFromBuff( p_data + 16 );
146     h->i_sizeimage     = __GetDoubleWordLittleEndianFromBuff( p_data + 20 );
147     h->i_xpelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 24 );
148     h->i_ypelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 28 );
149     h->i_clrused       = __GetDoubleWordLittleEndianFromBuff( p_data + 32 );
150     h->i_clrimportant  = __GetDoubleWordLittleEndianFromBuff( p_data + 36 );
151 }
152 /* get the first pes from fifo */
153 static pes_packet_t *__PES_GET( decoder_fifo_t *p_fifo )
154 {
155     pes_packet_t *p_pes;
156
157     vlc_mutex_lock( &p_fifo->data_lock );
158
159     /* if fifo is emty wait */
160     while( !p_fifo->p_first )
161     {
162         if( p_fifo->b_die )
163         {
164             vlc_mutex_unlock( &p_fifo->data_lock );
165             return( NULL );
166         }
167         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
168     }
169     p_pes = p_fifo->p_first;
170
171     vlc_mutex_unlock( &p_fifo->data_lock );
172
173     return( p_pes );
174 }
175 /* free the first pes and go to next */
176 static void __PES_NEXT( decoder_fifo_t *p_fifo )
177 {
178     pes_packet_t *p_next;
179
180     vlc_mutex_lock( &p_fifo->data_lock );
181     
182     p_next = p_fifo->p_first->p_next;
183     p_fifo->p_first->p_next = NULL;
184     input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
185     p_fifo->p_first = p_next;
186     p_fifo->i_depth--;
187
188     if( !p_fifo->p_first )
189     {
190         /* No PES in the fifo */
191         /* pp_last no longer valid */
192         p_fifo->pp_last = &p_fifo->p_first;
193         while( !p_fifo->p_first )
194         {
195             vlc_cond_signal( &p_fifo->data_wait );
196             vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
197         }
198     }
199     vlc_mutex_unlock( &p_fifo->data_lock );
200 }
201
202 static __inline__ void __GetFrame( videodec_thread_t *p_vdec )
203 {
204     pes_packet_t  *p_pes;
205     data_packet_t *p_data;
206     byte_t        *p_buffer;
207
208     p_pes = __PES_GET( p_vdec->p_fifo );
209     p_vdec->i_pts = p_pes->i_pts;
210
211     while( ( !p_pes->i_nb_data )||( !p_pes->i_pes_size ) )
212     {
213         __PES_NEXT( p_vdec->p_fifo );
214         p_pes = __PES_GET( p_vdec->p_fifo );
215     }
216     p_vdec->i_framesize = p_pes->i_pes_size;
217     if( p_pes->i_nb_data == 1 )
218     {
219         p_vdec->p_framedata = p_pes->p_first->p_payload_start;
220         return;    
221     }
222     /* get a buffer and gather all data packet */
223     p_vdec->p_framedata = p_buffer = malloc( p_pes->i_pes_size );
224     p_data = p_pes->p_first;
225     do
226     {
227         FAST_MEMCPY( p_buffer, 
228                      p_data->p_payload_start, 
229                      p_data->p_payload_end - p_data->p_payload_start );
230         p_buffer += p_data->p_payload_end - p_data->p_payload_start;
231         p_data = p_data->p_next;
232     } while( p_data );
233 }
234
235 static __inline__ void __NextFrame( videodec_thread_t *p_vdec )
236 {
237     pes_packet_t  *p_pes;
238
239     p_pes = __PES_GET( p_vdec->p_fifo );
240     if( p_pes->i_nb_data != 1 )
241     {
242         free( p_vdec->p_framedata ); /* FIXME keep this buffer */
243     }
244     __PES_NEXT( p_vdec->p_fifo );
245 }
246
247
248
249 /*****************************************************************************
250  * decoder_Run: this function is called just after the thread is created
251  *****************************************************************************/
252 static int decoder_Run ( decoder_config_t * p_config )
253 {
254     videodec_thread_t   *p_vdec;
255     int b_error;
256     
257     if ( (p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t))) 
258                     == NULL )
259     {
260         intf_ErrMsg( "vdec error: not enough memory "
261                      "for vdec_CreateThread() to create the new thread");
262         DecoderError( p_config->p_decoder_fifo );
263         return( -1 );
264     }
265     memset( p_vdec, 0, sizeof( videodec_thread_t ) );
266
267     p_vdec->p_fifo = p_config->p_decoder_fifo;
268     p_vdec->p_config = p_config;
269
270     if( InitThread( p_vdec ) != 0 )
271     {
272         DecoderError( p_config->p_decoder_fifo );
273         return( -1 );
274     }
275      
276     while( (!p_vdec->p_fifo->b_die) && (!p_vdec->p_fifo->b_error) )
277     {
278         /* decode a picture */
279         DecodeThread( p_vdec );
280     }
281
282     if( ( b_error = p_vdec->p_fifo->b_error ) )
283     {
284         DecoderError( p_vdec->p_fifo );
285     }
286
287     EndThread( p_vdec );
288
289     if( b_error )
290     {
291         return( -1 );
292     }
293    
294     return( 0 );
295
296
297 /*****************************************************************************
298  * InitThread: initialize vdec output thread
299  *****************************************************************************
300  * This function is called from decoder_Run and performs the second step 
301  * of the initialization. It returns 0 on success. Note that the thread's 
302  * flag are not modified inside this function.
303  *****************************************************************************/
304 static int InitThread( videodec_thread_t *p_vdec )
305 {
306     
307     if( p_vdec->p_config->p_demux_data != NULL )
308     {
309         __ParseBitMapInfoHeader( &p_vdec->format, 
310                                 (byte_t*)p_vdec->p_config->p_demux_data );
311     }
312     else
313     {
314         intf_ErrMsg( "vdec error: cannot get informations" );
315         return( -1 );
316     }
317
318     /*init ffmpeg */
319     if( !b_ffmpeginit )
320     {
321         avcodec_init();
322         avcodec_register_all();
323         b_ffmpeginit = 1;
324         intf_WarnMsg( 1, "vdec init: library ffmpeg initialised" );
325    }
326    else
327    {
328         intf_WarnMsg( 1, "vdec init: library ffmpeg already initialised" );
329    }
330
331     switch( p_vdec->p_config->i_type)
332     {
333 #if LIBAVCODEC_BUILD >= 4608 /* what is the true version */
334         case( MSMPEG4v1_VIDEO_ES):
335             p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MSMPEG4V1 );
336             p_vdec->psz_namecodec = "MS MPEG-4 v1";
337             break;
338         case( MSMPEG4v2_VIDEO_ES):
339             p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MSMPEG4V2 );
340             p_vdec->psz_namecodec = "MS MPEG-4 v2";
341             break;
342         case( MSMPEG4v3_VIDEO_ES):
343             p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MSMPEG4V3 );
344             p_vdec->psz_namecodec = "MS MPEG-4 v3";
345             break;
346 #else            
347             /* fallback on this */
348             case( MSMPEG4v3_VIDEO_ES):
349             p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MSMPEG4 );
350             p_vdec->psz_namecodec = "MS MPEG-4";
351             break;
352 #endif
353         case( MPEG4_VIDEO_ES):
354             p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MPEG4 );
355             p_vdec->psz_namecodec = "MPEG-4";
356             break;
357         default:
358             p_vdec->p_codec = NULL;
359             p_vdec->psz_namecodec = "Unknown";
360     }
361
362     if( !p_vdec->p_codec )
363     {
364         intf_ErrMsg( "vdec error: codec not found (%s)",
365                      p_vdec->psz_namecodec );
366         return( -1 );
367     }
368
369     p_vdec->p_context = &p_vdec->context;
370     memset( p_vdec->p_context, 0, sizeof( AVCodecContext ) );
371
372     p_vdec->p_context->width  = p_vdec->format.i_width;
373     p_vdec->p_context->height = p_vdec->format.i_height;
374     p_vdec->p_context->pix_fmt = PIX_FMT_YUV420P; /* I420 */
375
376     if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0)
377     {
378         intf_ErrMsg( "vdec error: cannot open codec (%s)",
379                      p_vdec->psz_namecodec );
380         return( -1 );
381     }
382     else
383     {
384         intf_WarnMsg( 1, "vdec info: ffmpeg codec (%s) started",
385                          p_vdec->psz_namecodec );
386     }
387     /* create vout */
388
389      p_vdec->p_vout = vout_CreateThread( 
390                                 NULL,
391                                 p_vdec->format.i_width,
392                                 p_vdec->format.i_height,
393                                 FOURCC_I420,
394                                 VOUT_ASPECT_FACTOR * p_vdec->format.i_width /
395                                     p_vdec->format.i_height );
396
397     if( !p_vdec->p_vout )
398     {
399         intf_ErrMsg( "vdec error: can't open vout, aborting" );
400         avcodec_close( p_vdec->p_context );
401         intf_WarnMsg(1, "vdec info: ffmpeg codec (%s) stopped",
402                             p_vdec->psz_namecodec);
403         return( -1 );
404     }
405
406     vlc_mutex_lock( &p_vout_bank->lock );
407     if( p_vout_bank->i_count != 0 )
408     {
409         vlc_mutex_unlock( &p_vout_bank->lock );
410         vout_DestroyThread( p_vout_bank->pp_vout[ 0 ], NULL );
411         vlc_mutex_lock( &p_vout_bank->lock );
412         p_vout_bank->i_count--;
413     }
414     p_vout_bank->i_count++;
415     p_vout_bank->pp_vout[0] = p_vdec->p_vout;
416     vlc_mutex_unlock( &p_vout_bank->lock );
417
418     return( 0 );
419 }
420
421 /*****************************************************************************
422  * EndThread: thread destruction
423  *****************************************************************************
424  * This function is called when the thread ends after a sucessful
425  * initialization.
426  *****************************************************************************/
427 static void EndThread( videodec_thread_t *p_vdec )
428 {
429     if( p_vdec == NULL )
430     {
431         intf_ErrMsg( "vdec error: cannot free structures" );
432         return;
433     }
434
435     if( p_vdec->p_context != NULL)
436     {
437         avcodec_close( p_vdec->p_context );
438         intf_WarnMsg(1, "vdec info: ffmpeg codec (%s) stopped",
439                         p_vdec->psz_namecodec);
440     }
441
442     vlc_mutex_lock( &p_vout_bank->lock );
443     if( p_vout_bank->i_count != 0 )
444     {
445         vlc_mutex_unlock( &p_vout_bank->lock );
446         vout_DestroyThread( p_vout_bank->pp_vout[ 0 ], NULL );
447         vlc_mutex_lock( &p_vout_bank->lock );
448         p_vout_bank->i_count--; 
449         p_vout_bank->pp_vout[ 0 ] = NULL;
450     }
451     vlc_mutex_unlock( &p_vout_bank->lock );
452
453     free( p_vdec );
454 }
455
456 static void  DecodeThread( videodec_thread_t *p_vdec )
457 {
458     int     i_plane;
459     int     i_status;
460     int     b_gotpicture;
461     AVPicture avpicture;  /* ffmpeg picture */
462     picture_t *p_pic; /* videolan picture */
463     /* we have to get a frame stored in a pes 
464        give it to ffmpeg decoder 
465        and send the image to the output */ 
466
467     __GetFrame( p_vdec );
468
469     i_status = avcodec_decode_video( p_vdec->p_context,
470                                      &avpicture,
471                                      &b_gotpicture,
472                                      p_vdec->p_framedata,
473                                      p_vdec->i_framesize);
474     __NextFrame( p_vdec );
475                                          
476     if( i_status < 0 )
477     {
478         intf_WarnMsg( 2, "vdec error: cannot decode one frame (%d bytes)",
479                          p_vdec->i_framesize );
480         return;
481     }
482     if( !b_gotpicture )
483     {
484         return;
485     }    
486
487     /* Send decoded frame to vout */
488
489     while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
490     {
491         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
492         {
493             return;
494         }
495         msleep( VOUT_OUTMEM_SLEEP );
496     }
497
498     for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
499     {
500         int i_size;
501         int i_line;
502         byte_t *p_dest = p_pic->p[i_plane].p_pixels;
503         byte_t *p_src  = avpicture.data[i_plane];
504         if( ( !p_dest )||( !p_src )) 
505         { 
506             break; 
507         }
508         i_size = __MIN( p_pic->p[i_plane].i_pitch,
509                                  avpicture.linesize[i_plane] );
510         for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
511         {
512             FAST_MEMCPY( p_dest, p_src, i_size );
513             p_dest += p_pic->p[i_plane].i_pitch;
514             p_src  += avpicture.linesize[i_plane];
515         }
516     }
517
518     vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->i_pts);
519     vout_DisplayPicture( p_vdec->p_vout, p_pic );
520     
521     return;
522 }
523