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