]> git.sesse.net Git - vlc/blob - modules/codec/ffmpeg/ffmpeg.c
(A few minor pending patches I had around)
[vlc] / modules / codec / 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.6 2002/08/26 09:12:46 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 "avcodec.h"                                            /* ffmpeg */
46
47 #include "postprocessing/postprocessing.h"
48
49 #include "ffmpeg.h"
50
51 /*
52  * Local prototypes
53  */
54 static int      OpenDecoder     ( vlc_object_t * );
55 static int      RunDecoder      ( decoder_fifo_t * );
56 static int      InitThread      ( videodec_thread_t * );
57 static void     EndThread       ( videodec_thread_t * );
58 static void     DecodeThread    ( videodec_thread_t * );
59
60
61 static int      b_ffmpeginit = 0;
62
63 /*****************************************************************************
64  * Module descriptor
65  *****************************************************************************/
66
67 #define ERROR_RESILIENCE_LONGTEXT \
68     "ffmpeg can make errors resiliences.          \n"\
69     "Nevertheless, with buggy encoder (like ISO MPEG-4 encoder from M$) " \
70     "this will produce a lot of errors.\n" \
71     "Valid range is -1 to 99 (-1 disable all errors resiliences)."
72
73 #define HURRY_UP_LONGTEXT \
74     "Allow the decoder to partially decode or skip frame(s) " \
75     "when there not enough time.\n It's usefull with low CPU power " \
76     "but it could produce broken pictures."
77
78 #define POSTPROCESSING_Q_LONGTEXT \
79     "Quality of post processing\n"\
80     "Valid range is 0 to 6\n" \
81     "( Overridden by others setting)"
82     
83 #define POSTPROCESSING_AQ_LONGTEXT \
84     "Post processing quality is selected upon time left" \
85     "but no more than requested quality\n" \
86     "Not yet implemented !"
87
88 vlc_module_begin();
89     add_category_hint( N_("Ffmpeg"), NULL );
90 #if LIBAVCODEC_BUILD >= 4611
91     add_integer ( "ffmpeg-error-resilience", -1, NULL, 
92                   "error resilience", ERROR_RESILIENCE_LONGTEXT );
93     add_integer ( "ffmpeg-workaround-bugs", 0, NULL, 
94                   "workaround bugs", "0-99, seems to be for msmpeg v3\n"  );
95 #endif
96     add_bool( "ffmpeg-hurry-up", 0, NULL, "hurry up", HURRY_UP_LONGTEXT );
97     
98     add_category_hint( N_("Post processing"), NULL );
99     add_module( "ffmpeg-pp", "postprocessing",NULL, NULL,
100                 N_( "ffmpeg postprocessing module" ), NULL ); 
101     add_integer( "ffmpeg-pp-q", 0, NULL,
102                  "post processing quality", POSTPROCESSING_Q_LONGTEXT );
103     add_bool( "ffmpeg-pp-auto", 0, NULL,
104               "auto-level Post processing quality", POSTPROCESSING_AQ_LONGTEXT );
105     add_bool( "ffmpeg-db-yv", 0, NULL, 
106               "force vertical luminance deblocking", 
107               "force vertical luminance deblocking (override other settings)" );
108     add_bool( "ffmpeg-db-yh", 0, NULL, 
109               "force horizontal luminance deblocking",
110               "force horizontal luminance deblocking (override other settings)" );
111     add_bool( "ffmpeg-db-cv", 0, NULL, 
112               "force vertical chrominance deblocking",
113               "force vertical chrominance deblocking (override other settings)" );
114     add_bool( "ffmpeg-db-ch", 0, NULL, 
115               "force horizontal chrominance deblocking",
116               "force horizontal chrominance deblocking (override other settings) " );
117     add_bool( "ffmpeg-dr-y", 0, NULL,
118               "force luminance deringing",
119               "force luminance deringing (override other settings)" );
120     add_bool( "ffmpeg-dr-c", 0, NULL,
121               "force chrominance deringing",
122               "force chrominance deringing (override other settings)" );
123       
124     set_description( _("ffmpeg video decoder((MS)MPEG4,SVQ1,H263)") );
125     set_capability( "decoder", 70 );
126     set_callbacks( OpenDecoder, NULL );
127 vlc_module_end();
128
129 /*****************************************************************************
130  * OpenDecoder: probe the decoder and return score
131  *****************************************************************************
132  * Tries to launch a decoder and return score so that the interface is able 
133  * to chose.
134  *****************************************************************************/
135 static int OpenDecoder( vlc_object_t *p_this )
136 {
137     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
138
139     if( ffmpeg_GetFfmpegCodec( p_fifo->i_fourcc, NULL, NULL ) )
140     {
141         p_fifo->pf_run = RunDecoder;
142         return VLC_SUCCESS;
143     }
144
145     return VLC_EGENERIC;
146 }
147
148 /*****************************************************************************
149  * RunDecoder: this function is called just after the thread is created
150  *****************************************************************************/
151 static int RunDecoder( decoder_fifo_t *p_fifo )
152 {
153     videodec_thread_t   *p_vdec;
154     int b_error;
155
156     if ( !(p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t))) )
157     {
158         msg_Err( p_fifo, "out of memory" );
159         DecoderError( p_fifo );
160         return( -1 );
161     }
162     memset( p_vdec, 0, sizeof( videodec_thread_t ) );
163
164     p_vdec->p_fifo = p_fifo;
165
166     if( InitThread( p_vdec ) != 0 )
167     {
168         DecoderError( p_fifo );
169         return( -1 );
170     }
171      
172     while( (!p_vdec->p_fifo->b_die) && (!p_vdec->p_fifo->b_error) )
173     {
174         DecodeThread( p_vdec );
175     }
176
177     if( ( b_error = p_vdec->p_fifo->b_error ) )
178     {
179         DecoderError( p_vdec->p_fifo );
180     }
181
182     EndThread( p_vdec );
183
184     if( b_error )
185     {
186         return( -1 );
187     }
188    
189     return( 0 );
190
191
192
193 /*****************************************************************************
194  * locales Functions
195  *****************************************************************************/
196
197 #define GetWLE( p ) \
198     ( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) )
199
200 #define GetDWLE( p ) \
201     (  *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) + \
202       ( *((u8*)(p)+2) << 16 ) + ( *((u8*)(p)+3) << 24 ) )
203
204 #define FREE( p ) if( p ) free( p ); p = NULL
205     
206 static void ffmpeg_ParseBitMapInfoHeader( bitmapinfoheader_t *p_bh, 
207                                           u8 *p_data )
208 {
209     p_bh->i_size          = GetDWLE( p_data );
210     p_bh->i_width         = GetDWLE( p_data + 4 );
211     p_bh->i_height        = GetDWLE( p_data + 8 );
212     p_bh->i_planes        = GetWLE( p_data + 12 );
213     p_bh->i_bitcount      = GetWLE( p_data + 14 );
214     p_bh->i_compression   = GetDWLE( p_data + 16 );
215     p_bh->i_sizeimage     = GetDWLE( p_data + 20 );
216     p_bh->i_xpelspermeter = GetDWLE( p_data + 24 );
217     p_bh->i_ypelspermeter = GetDWLE( p_data + 28 );
218     p_bh->i_clrused       = GetDWLE( p_data + 32 );
219     p_bh->i_clrimportant  = GetDWLE( p_data + 36 );
220
221     if( p_bh->i_size > 40 )
222     {
223         p_bh->i_data = p_bh->i_size - 40;
224         if( ( p_bh->p_data = malloc( p_bh->i_data ) ) )
225         {
226             memcpy( p_bh->p_data, p_data + 40, p_bh->i_data );
227         }
228         else
229         {
230             p_bh->i_data = 0;
231         }
232     }
233     else
234     {
235         p_bh->i_data = 0;
236         p_bh->p_data = NULL;
237     } 
238
239 }
240 /* get the first pes from fifo */
241 static pes_packet_t *__PES_GET( decoder_fifo_t *p_fifo )
242 {
243     pes_packet_t *p_pes;
244
245     vlc_mutex_lock( &p_fifo->data_lock );
246
247     /* if fifo is emty wait */
248     while( !p_fifo->p_first )
249     {
250         if( p_fifo->b_die )
251         {
252             vlc_mutex_unlock( &p_fifo->data_lock );
253             return( NULL );
254         }
255         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
256     }
257     p_pes = p_fifo->p_first;
258
259     vlc_mutex_unlock( &p_fifo->data_lock );
260
261     return( p_pes );
262 }
263
264 /* free the first pes and go to next */
265 static void __PES_NEXT( decoder_fifo_t *p_fifo )
266 {
267     pes_packet_t *p_next;
268
269     vlc_mutex_lock( &p_fifo->data_lock );
270     
271     p_next = p_fifo->p_first->p_next;
272     p_fifo->p_first->p_next = NULL;
273     input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
274     p_fifo->p_first = p_next;
275     p_fifo->i_depth--;
276
277     if( !p_fifo->p_first )
278     {
279         /* No PES in the fifo */
280         /* pp_last no longer valid */
281         p_fifo->pp_last = &p_fifo->p_first;
282         while( !p_fifo->p_first )
283         {
284             vlc_cond_signal( &p_fifo->data_wait );
285             vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
286         }
287     }
288     vlc_mutex_unlock( &p_fifo->data_lock );
289 }
290
291 static inline void __GetFrame( videodec_thread_t *p_vdec )
292 {
293     pes_packet_t  *p_pes;
294     data_packet_t *p_data;
295     byte_t        *p_buffer;
296
297     p_pes = __PES_GET( p_vdec->p_fifo );
298     p_vdec->i_pts = p_pes->i_pts;
299
300     while( ( !p_pes->i_nb_data )||( !p_pes->i_pes_size ) )
301     {
302         __PES_NEXT( p_vdec->p_fifo );
303         p_pes = __PES_GET( p_vdec->p_fifo );
304     }
305     p_vdec->i_framesize = p_pes->i_pes_size;
306     if( p_pes->i_nb_data == 1 )
307     {
308         p_vdec->p_framedata = p_pes->p_first->p_payload_start;
309         return;    
310     }
311     /* get a buffer and gather all data packet */
312     if( p_vdec->i_buffer_size < p_pes->i_pes_size )
313     {
314         if( p_vdec->p_buffer )
315         {
316             p_vdec->p_buffer = realloc( p_vdec->p_buffer,
317                                         p_pes->i_pes_size );
318         }
319         else
320         {
321             p_vdec->p_buffer = malloc( p_pes->i_pes_size );
322         }
323         p_vdec->i_buffer_size = p_pes->i_pes_size;
324     }
325     
326     p_buffer = p_vdec->p_framedata = p_vdec->p_buffer;
327     p_data = p_pes->p_first;
328     do
329     {
330         p_vdec->p_fifo->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, 
331                      p_data->p_payload_end - p_data->p_payload_start );
332         p_buffer += p_data->p_payload_end - p_data->p_payload_start;
333         p_data = p_data->p_next;
334     } while( p_data );
335 }
336
337 static inline void __NextFrame( videodec_thread_t *p_vdec )
338 {
339     __PES_NEXT( p_vdec->p_fifo );
340 }
341
342
343 /* Check if we have a Vout with good parameters */
344 static int ffmpeg_CheckVout( vout_thread_t *p_vout,
345                              int i_width,
346                              int i_height,
347                              int i_aspect,
348                              int i_chroma )
349 {
350     if( !p_vout )
351     {
352         return( 0 );
353     }
354     if( !i_chroma )
355     {
356         /* we will try to make conversion */
357         i_chroma = VLC_FOURCC('I','4','2','0');
358     } 
359     
360     if( ( p_vout->render.i_width != i_width )||
361         ( p_vout->render.i_height != i_height )||
362         ( p_vout->render.i_chroma != i_chroma )||
363         ( p_vout->render.i_aspect != 
364                 ffmpeg_FfAspect( i_width, i_height, i_aspect ) ) )
365     {
366         return( 0 );
367     }
368     else
369     {
370         return( 1 );
371     }
372 }
373
374 /* Return a Vout */
375
376 static vout_thread_t *ffmpeg_CreateVout( videodec_thread_t *p_vdec,
377                                          int i_width,
378                                          int i_height,
379                                          int i_aspect,
380                                          int i_chroma )
381 {
382     vout_thread_t *p_vout;
383
384     if( (!i_width)||(!i_height) )
385     {
386         return( NULL ); /* Can't create a new vout without display size */
387     }
388
389     if( !i_chroma )
390     {
391         /* we make conversion if possible*/
392         i_chroma = VLC_FOURCC('I','4','2','0');
393         msg_Warn( p_vdec->p_fifo, "Internal chroma conversion (FIXME)");
394         /* It's mainly for I410 -> I420 conversion that I've made,
395            it's buggy and very slow */
396     } 
397
398     i_aspect = ffmpeg_FfAspect( i_width, i_height, i_aspect );
399     
400     /* Spawn a video output if there is none. First we look for our children,
401      * then we look for any other vout that might be available. */
402     p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
403                                               FIND_CHILD );
404     if( !p_vout )
405     {
406         p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
407                                                   FIND_ANYWHERE );
408     }
409
410     if( p_vout )
411     {
412         if( !ffmpeg_CheckVout( p_vout, 
413                                i_width, i_height, i_aspect,i_chroma ) )
414         {
415             /* We are not interested in this format, close this vout */
416             vlc_object_detach( p_vout );
417             vlc_object_release( p_vout );
418             vout_DestroyThread( p_vout );
419             p_vout = NULL;
420         }
421         else
422         {
423             /* This video output is cool! Hijack it. */
424             vlc_object_detach( p_vout );
425             vlc_object_attach( p_vout, p_vdec->p_fifo );
426             vlc_object_release( p_vout );
427         }
428     }
429
430     if( p_vout == NULL )
431     {
432         msg_Dbg( p_vdec->p_fifo, "no vout present, spawning one" );
433     
434         p_vout = vout_CreateThread( p_vdec->p_fifo,
435                                     i_width, i_height,
436                                     i_chroma, i_aspect );
437     }
438     
439     return( p_vout );
440 }
441
442 /* FIXME FIXME FIXME this is a big shit
443    does someone want to rewrite this function ? 
444    or said to me how write a better thing
445    FIXME FIXME FIXME
446 */
447 static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
448                                              AVPicture *p_avpicture,
449                                              videodec_thread_t   *p_vdec )
450 {
451     u8 *p_src, *p_dst;
452     u8 *p_plane[3];
453     int i_plane;
454     
455     int i_stride, i_lines;
456     int i_height, i_width;
457     int i_y, i_x;
458     
459     i_height = p_vdec->p_context->height;
460     i_width  = p_vdec->p_context->width;
461     
462     p_dst = p_pic->p[0].p_pixels;
463     p_src  = p_avpicture->data[0];
464
465     /* copy first plane */
466     for( i_y = 0; i_y < i_height; i_y++ )
467     {
468         p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width);
469         p_dst += p_pic->p[0].i_pitch;
470         p_src += p_avpicture->linesize[0];
471     }
472     
473     /* process each plane in a temporary buffer */
474     for( i_plane = 1; i_plane < 3; i_plane++ )
475     {
476         i_stride = p_avpicture->linesize[i_plane];
477         i_lines = i_height / 4;
478
479         p_dst = p_plane[i_plane] = malloc( i_lines * i_stride * 2 * 2 );
480         p_src  = p_avpicture->data[i_plane];
481
482         /* for each source line */
483         for( i_y = 0; i_y < i_lines; i_y++ )
484         {
485             for( i_x = 0; i_x < i_stride - 1; i_x++ )
486             {
487                 p_dst[2 * i_x    ] = p_src[i_x];
488                 p_dst[2 * i_x + 1] = ( p_src[i_x] + p_src[i_x + 1]) / 2;
489
490             }
491             p_dst[2 * i_stride - 2] = p_src[i_x];
492             p_dst[2 * i_stride - 1] = p_src[i_x];
493                            
494             p_dst += 4 * i_stride; /* process the next even lines */
495             p_src += i_stride;
496         }
497
498
499     }
500
501     for( i_plane = 1; i_plane < 3; i_plane++ )
502     {
503         i_stride = p_avpicture->linesize[i_plane];
504         i_lines = i_height / 4;
505
506         p_dst = p_plane[i_plane] + 2*i_stride;
507         p_src  = p_plane[i_plane];
508
509         for( i_y = 0; i_y < i_lines - 1; i_y++ )
510         {
511             for( i_x = 0; i_x <  2 * i_stride ; i_x++ )
512             {
513                 p_dst[i_x] = ( p_src[i_x] + p_src[i_x + 4*i_stride])/2;
514             }
515                            
516             p_dst += 4 * i_stride; /* process the next odd lines */
517             p_src += 4 * i_stride;
518         }
519         /* last line */
520         p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, 2*i_stride );
521     }
522     /* copy to p_pic, by block
523        if I do pixel per pixel it segfault. It's why I use 
524        temporaries buffers */
525     for( i_plane = 1; i_plane < 3; i_plane++ )
526     {
527
528         int i_size; 
529         p_src  = p_plane[i_plane];
530         p_dst = p_pic->p[i_plane].p_pixels;
531
532         i_size = __MIN( 2*i_stride, p_pic->p[i_plane].i_pitch);
533         for( i_y = 0; i_y < __MIN(p_pic->p[i_plane].i_lines, 2 * i_lines); i_y++ )
534         {
535             p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
536             p_src += 2 * i_stride;
537             p_dst += p_pic->p[i_plane].i_pitch;
538         }
539         free( p_plane[i_plane] );
540     }
541
542 }
543
544 static void ffmpeg_GetPicture( picture_t *p_pic,
545                                AVPicture *p_avpicture,
546                                videodec_thread_t   *p_vdec )
547 {
548     int i_plane; 
549     int i_size;
550     int i_line;
551
552     u8  *p_dst;
553     u8  *p_src;
554     int i_src_stride;
555     int i_dst_stride;
556
557     if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
558     {
559         for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
560         {
561             p_src  = p_avpicture->data[i_plane];
562             p_dst = p_pic->p[i_plane].p_pixels;
563             i_src_stride = p_avpicture->linesize[i_plane];
564             i_dst_stride = p_pic->p[i_plane].i_pitch;
565             
566             i_size = __MIN( i_src_stride, i_dst_stride );
567             for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
568             {
569                 p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
570                 p_src += i_src_stride;
571                 p_dst += i_dst_stride;
572             }
573         }
574         if( ( p_vdec->i_pp_mode )&&
575             ( ( p_vdec->p_vout->render.i_chroma == 
576                     VLC_FOURCC( 'I','4','2','0' ) )||
577               ( p_vdec->p_vout->render.i_chroma == 
578                     VLC_FOURCC( 'Y','V','1','2' ) ) ) )
579         {
580             /* Make postproc */
581 #if LIBAVCODEC_BUILD > 4313
582             p_vdec->p_pp->pf_postprocess( p_pic,
583                                           p_vdec->p_context->quant_store, 
584                                           p_vdec->p_context->qstride,
585                                           p_vdec->i_pp_mode );
586 #endif
587         }
588     }
589     else
590     {
591         /* we need to convert to I420 */
592         switch( p_vdec->p_context->pix_fmt )
593         {
594 #if LIBAVCODEC_BUILD >= 4615
595             case( PIX_FMT_YUV410P ):
596                 ffmpeg_ConvertPictureI410toI420( p_pic, p_avpicture, p_vdec );
597                 break;
598 #endif            
599             default:
600                 p_vdec->p_fifo->b_error = 1;
601                 break;
602         }
603
604     }
605   
606 }
607
608
609
610 /*****************************************************************************
611  *
612  * Functions that initialize, decode and end the decoding process
613  *
614  *****************************************************************************/
615
616 /*****************************************************************************
617  * InitThread: initialize vdec output thread
618  *****************************************************************************
619  * This function is called from decoder_Run and performs the second step 
620  * of the initialization. It returns 0 on success. Note that the thread's 
621  * flag are not modified inside this function.
622  *
623  * ffmpeg codec will be open, some memory allocated. But Vout is not yet
624  *   open (done after the first decoded frame)
625  *****************************************************************************/
626 static int InitThread( videodec_thread_t *p_vdec )
627 {
628     int i_ffmpeg_codec; 
629     int i_tmp;
630     
631     if( p_vdec->p_fifo->p_demux_data )
632     {
633         ffmpeg_ParseBitMapInfoHeader( &p_vdec->format, 
634                                       (u8*)p_vdec->p_fifo->p_demux_data );
635     }
636     else
637     {
638         msg_Warn( p_vdec->p_fifo, "display informations missing" );
639     }
640
641     /* **** init ffmpeg library (libavcodec) ***** */
642     if( !b_ffmpeginit )
643     {
644         avcodec_init();
645         avcodec_register_all();
646         b_ffmpeginit = 1;
647         msg_Dbg( p_vdec->p_fifo, "library ffmpeg initialized" );
648     }
649     else
650     {
651         msg_Dbg( p_vdec->p_fifo, "library ffmpeg already initialized" );
652     }
653
654     /* ***** Search for codec ***** */
655     ffmpeg_GetFfmpegCodec( p_vdec->p_fifo->i_fourcc,
656                            &i_ffmpeg_codec,
657                            &p_vdec->psz_namecodec );
658     p_vdec->p_codec = 
659         avcodec_find_decoder( i_ffmpeg_codec );
660     
661     if( !p_vdec->p_codec )
662     {
663         msg_Err( p_vdec->p_fifo, "codec not found (%s)",
664                                  p_vdec->psz_namecodec );
665         return( -1 );
666     }
667
668     /* ***** Fill p_context with init values ***** */
669     p_vdec->p_context = &p_vdec->context;
670     memset( p_vdec->p_context, 0, sizeof( AVCodecContext ) );
671
672     p_vdec->p_context->width  = p_vdec->format.i_width;
673     p_vdec->p_context->height = p_vdec->format.i_height;
674     
675     /*  ***** Get configuration of ffmpeg plugin ***** */
676 #if LIBAVCODEC_BUILD >= 4611
677     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-workaround-bugs" );
678     p_vdec->p_context->workaround_bugs  = __MAX( __MIN( i_tmp, 99 ), 0 );
679
680     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-error-resilience" );
681     p_vdec->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
682 #endif
683 #if LIBAVCODEC_BUILD >= 4614
684     if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
685     {
686         p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
687     }
688 #endif
689     p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
690     
691
692     /* ***** Open the codec ***** */ 
693     if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0)
694     {
695         msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
696                                  p_vdec->psz_namecodec );
697         return( -1 );
698     }
699     else
700     {
701         msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
702                                  p_vdec->psz_namecodec );
703     }
704
705     /* ***** init this codec with special data(up to now MPEG4 only) ***** */
706     if( p_vdec->format.i_data )
707     {
708         AVPicture avpicture;
709         int b_gotpicture;
710         
711         switch( i_ffmpeg_codec )
712         {
713             case( CODEC_ID_MPEG4 ):
714                 avcodec_decode_video( p_vdec->p_context, &avpicture, 
715                                       &b_gotpicture,
716                                       p_vdec->format.p_data,
717                                       p_vdec->format.i_data );
718                 break;
719             default:
720                 break;
721         }
722     }
723     
724     /* ***** Load post processing ***** */
725
726     /* get overridding settings */
727     p_vdec->i_pp_mode = 0;
728     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
729         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
730     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
731         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
732     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
733         p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
734     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
735         p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
736     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
737         p_vdec->i_pp_mode |= PP_DERING_Y;
738     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
739         p_vdec->i_pp_mode |= PP_DERING_C;
740     
741     if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
742         ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )  )||
743         ( p_vdec->i_pp_mode != 0 ) )
744     {
745         /* check if the codec support postproc. */
746         switch( i_ffmpeg_codec )
747         {
748 #if LIBAVCODEC_BUILD > 4608
749             case( CODEC_ID_MSMPEG4V1 ):
750             case( CODEC_ID_MSMPEG4V2 ):
751             case( CODEC_ID_MSMPEG4V3 ):
752 #else
753             case( CODEC_ID_MSMPEG4 ):
754 #endif
755             case( CODEC_ID_MPEG4 ):
756             case( CODEC_ID_H263 ):
757 //            case( CODEC_ID_H263P ): I don't use it up to now
758             case( CODEC_ID_H263I ):
759                 /* Ok we can make postprocessing :)) */
760                /* first try to get a postprocess module */
761 #if LIBAVCODEC_BUILD > 4613
762                 p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
763                                                   sizeof( postprocessing_t ) );
764                 p_vdec->p_pp->psz_object_name = "postprocessing";
765                 p_vdec->p_pp->p_module = 
766                    module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
767
768                 if( !p_vdec->p_pp->p_module )
769                 {
770                     msg_Warn( p_vdec->p_fifo, 
771                               "no suitable postprocessing module" );
772                     vlc_object_destroy( p_vdec->p_pp );
773                     p_vdec->p_pp = NULL;
774                     p_vdec->i_pp_mode = 0;
775                 }
776                 else
777                 {
778                     /* get mode upon quality */
779                     p_vdec->i_pp_mode |= 
780                         p_vdec->p_pp->pf_getmode( 
781                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
782                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
783                                                 );
784
785                     /* allocate table for postprocess */
786                     p_vdec->p_context->quant_store = 
787                         malloc( sizeof( int ) * ( MBR + 1 ) * ( MBC + 1 ) );
788                     p_vdec->p_context->qstride = MBC + 1;
789                 }
790 #else
791                 p_vdec->i_pp_mode = 0;
792                 msg_Warn( p_vdec->p_fifo, 
793                           "post-processing not supported, upgrade ffmpeg" );
794 #endif
795                 break;
796             default:
797                 p_vdec->i_pp_mode = 0;
798                 msg_Warn( p_vdec->p_fifo, 
799                           "Post processing unsupported for this codec" );
800                 break;
801         }
802
803     }
804 //    memset( &p_vdec->statistic, 0, sizeof( statistic_t ) );
805
806     return( 0 );
807 }
808
809 /*****************************************************************************
810  * DecodeThread: Called for decode one frame
811  *****************************************************************************/
812 static void  DecodeThread( videodec_thread_t *p_vdec )
813 {
814     int     i_status;
815     int     b_drawpicture;
816     int     b_gotpicture;
817     AVPicture avpicture;  /* ffmpeg picture */
818     picture_t *p_pic; /* videolan picture */
819     /* we have to get a frame stored in a pes 
820        give it to ffmpeg decoder 
821        and send the image to the output */ 
822
823     /* TODO implement it in a better way */
824     /* A good idea could be to decode all I pictures and see for the other */
825     if( ( p_vdec->b_hurry_up )&&
826         ( p_vdec->i_frame_late > 4 ) )
827     {
828 #if LIBAVCODEC_BUILD > 4603
829         b_drawpicture = 0;
830         if( p_vdec->i_frame_late < 8 )
831         {
832             p_vdec->p_context->hurry_up = 2;
833         }
834         else
835         {
836             /* too much late picture, won't decode 
837                but break picture until a new I, and for mpeg4 ...*/
838             p_vdec->i_frame_late--; /* needed else it will never be decrease */
839             __PES_NEXT( p_vdec->p_fifo );
840             return;
841         }
842 #else
843         if( p_vdec->i_frame_late < 8 )
844         {
845             b_drawpicture = 0; /* not really good but .. UPGRADE FFMPEG !! */
846         }
847         else
848         {
849             /* too much late picture, won't decode 
850                but break picture until a new I, and for mpeg4 ...*/
851             p_vdec->i_frame_late--; /* needed else it will never be decrease */
852             __PES_NEXT( p_vdec->p_fifo );
853             return;
854         }
855 #endif
856     }
857     else
858     {
859         b_drawpicture = 1;
860 #if LIBAVCODEC_BUILD > 4603
861         p_vdec->p_context->hurry_up = 0;
862 #endif
863     }
864
865     __GetFrame( p_vdec );
866
867     i_status = avcodec_decode_video( p_vdec->p_context,
868                                      &avpicture,
869                                      &b_gotpicture,
870                                      p_vdec->p_framedata,
871                                      p_vdec->i_framesize);
872
873     __NextFrame( p_vdec );
874
875     if( i_status < 0 )
876     {
877         msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
878                                   p_vdec->i_framesize );
879         p_vdec->i_frame_error++;
880         return;
881     }
882     /* Update frame late count*/
883     /* I don't make statistic on decoding time */
884     if( p_vdec->i_pts <= mdate()) 
885     {
886         p_vdec->i_frame_late++;
887     }
888     else
889     {
890         p_vdec->i_frame_late = 0;
891     }
892
893     if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture)
894     {
895         return;
896     }
897     
898     /* Check our vout */
899     if( !ffmpeg_CheckVout( p_vdec->p_vout,
900                            p_vdec->p_context->width,
901                            p_vdec->p_context->height,
902                            p_vdec->p_context->aspect_ratio_info,
903                            ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) )
904     {
905         p_vdec->p_vout = 
906           ffmpeg_CreateVout( p_vdec,
907                              p_vdec->p_context->width,
908                              p_vdec->p_context->height,
909                              p_vdec->p_context->aspect_ratio_info,
910                              ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt));
911         if( !p_vdec->p_vout )
912         {
913             msg_Err( p_vdec->p_fifo, "cannot create vout" );
914             p_vdec->p_fifo->b_error = 1; /* abort */
915             return;
916         }
917     }
918
919     /* Get a new picture */
920     while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
921     {
922         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
923         {
924             return;
925         }
926         msleep( VOUT_OUTMEM_SLEEP );
927     }
928     /* fill p_picture_t from avpicture, do I410->I420 if needed
929        and do post-processing if requested */    
930     ffmpeg_GetPicture( p_pic, &avpicture, p_vdec );
931
932     /* FIXME correct avi and use i_dts */
933
934     /* Send decoded frame to vout */
935     vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->i_pts);
936     vout_DisplayPicture( p_vdec->p_vout, p_pic );
937     
938     return;
939 }
940
941
942 /*****************************************************************************
943  * EndThread: thread destruction
944  *****************************************************************************
945  * This function is called when the thread ends after a sucessful
946  * initialization.
947  *****************************************************************************/
948 static void EndThread( videodec_thread_t *p_vdec )
949 {
950     
951     if( !p_vdec )
952     {
953         return;
954     }
955     if( p_vdec->p_pp )
956     {
957         /* release postprocessing module */
958         module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
959         vlc_object_destroy( p_vdec->p_pp );
960         p_vdec->p_pp = NULL;
961     }
962
963     if( p_vdec->p_context != NULL)
964     {
965         FREE( p_vdec->p_context->quant_store );
966         avcodec_close( p_vdec->p_context );
967         msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) stopped",
968                                  p_vdec->psz_namecodec );
969     }
970
971     if( p_vdec->p_vout != NULL )
972     {
973         /* We are about to die. Reattach video output to p_vlc. */
974         vlc_object_detach( p_vdec->p_vout );
975         vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc );
976     }
977
978     FREE( p_vdec->format.p_data );
979     FREE( p_vdec->p_buffer );
980
981     free( p_vdec );
982 }
983