82cd54ddd7a60f662abfa9fa1bdb1c466a80ca2c
[vlc.git] / modules / codec / ffmpeg / video.c
1 /*****************************************************************************
2  * video.c: video decoder using ffmpeg library
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: video.c,v 1.6 2002/11/27 12:41:45 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@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>                                      /* malloc(), free() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/vout.h>
32 #include <vlc/aout.h>
33 #include <vlc/decoder.h>
34 #include <vlc/input.h>
35
36 #include <string.h>
37
38 #ifdef HAVE_SYS_TIMES_H
39 #   include <sys/times.h>
40 #endif
41
42 #include "avcodec.h"                                               /* ffmpeg */
43
44 #include "postprocessing/postprocessing.h"
45
46 #include "ffmpeg.h"
47 #include "video.h"
48
49 /*****************************************************************************
50  * Local prototypes
51  *****************************************************************************/
52 static void ffmpeg_CopyPicture( picture_t *, AVPicture *, vdec_thread_t * );
53 static void ffmpeg_PostProcPicture( vdec_thread_t *, picture_t * );
54 static int  ffmpeg_GetFrameBuf( struct AVCodecContext *, int, int, int );
55
56 /* FIXME FIXME some of them are wrong */
57 static int i_ffmpeg_PixFmtToChroma[] =
58 {
59     /* PIX_FMT_ANY = -1, PIX_FMT_YUV420P, 
60        PIX_FMT_YUV422,   PIX_FMT_RGB24,   
61        PIX_FMT_BGR24,    PIX_FMT_YUV422P, 
62        PIX_FMT_YUV444P,  PIX_FMT_YUV410P 
63      */
64     0,                           VLC_FOURCC('I','4','2','0'),
65     VLC_FOURCC('I','4','2','0'), VLC_FOURCC('R','V','2','4'),
66     0,                           VLC_FOURCC('I','4','2','2'),
67     VLC_FOURCC('I','4','4','4'), 0
68 };
69
70 /*****************************************************************************
71  * Local Functions
72  *****************************************************************************/
73
74 static inline u32 ffmpeg_PixFmtToChroma( int i_ffmpegchroma )
75 {
76     if( ++i_ffmpegchroma > 7 )
77     {
78         return( 0 );
79     }
80     else
81     {
82         return( i_ffmpeg_PixFmtToChroma[i_ffmpegchroma] );
83     }
84 }
85
86 static inline int ffmpeg_FfAspect( int i_width, int i_height, int i_ffaspect )
87 {
88     switch( i_ffaspect )
89     {
90         case( FF_ASPECT_4_3_625 ):
91         case( FF_ASPECT_4_3_525 ):
92             return( VOUT_ASPECT_FACTOR * 4 / 3);
93         case( FF_ASPECT_16_9_625 ):
94         case( FF_ASPECT_16_9_525 ):
95             return( VOUT_ASPECT_FACTOR * 16 / 9 );
96         case( FF_ASPECT_SQUARE ):
97         default:
98             return( VOUT_ASPECT_FACTOR * i_width / i_height );
99     }
100 }
101
102 /* Check if we have a Vout with good parameters */
103 static int ffmpeg_CheckVout( vout_thread_t *p_vout,
104                              int i_width,
105                              int i_height,
106                              int i_chroma )
107 {
108     if( !p_vout )
109     {
110         return( 0 );
111     }
112     if( !i_chroma )
113     {
114         /* we will try to make conversion */
115         i_chroma = VLC_FOURCC('I','4','2','0');
116     } 
117
118     if( ( p_vout->render.i_width != i_width )||
119         ( p_vout->render.i_height != i_height )||
120         ( p_vout->render.i_chroma != i_chroma ) )
121     {
122         return( 0 );
123     }
124     else
125     {
126         return( 1 );
127     }
128 }
129
130 /* Return a Vout */
131 static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
132                                          AVCodecContext *p_context )
133 {
134     vout_thread_t *p_vout;
135     int         i_width = p_vdec->p_context->width;
136     int         i_height = p_vdec->p_context->height;
137     uint32_t    i_chroma = ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt );
138     int         i_aspect;
139
140     if( !i_width || !i_height )
141     {
142         return( NULL ); /* Can't create a new vout without display size */
143     }
144
145     if( !i_chroma )
146     {
147         /* we make conversion if possible*/
148         i_chroma = VLC_FOURCC('I','4','2','0');
149         msg_Warn( p_vdec->p_fifo, "Internal chroma conversion (FIXME)");
150         /* It's mainly for I410 -> I420 conversion that I've made,
151            it's buggy and very slow */
152     } 
153
154 #if LIBAVCODEC_BUILD >= 4640
155     i_aspect = (int) ( VOUT_ASPECT_FACTOR * p_vdec->p_context->aspect_ratio );
156
157     if( i_aspect == 0 )
158     {
159         i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
160     }
161
162 #else
163     switch( i_aspect )
164     {
165         case( FF_ASPECT_4_3_625 ):
166         case( FF_ASPECT_4_3_525 ):
167             i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
168         case( FF_ASPECT_16_9_625 ):
169         case( FF_ASPECT_16_9_525 ):
170             i_aspect = VOUT_ASPECT_FACTOR * 16 / 9 ;
171         case( FF_ASPECT_SQUARE ):
172         default:
173             i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
174     }
175 #endif
176     /* Spawn a video output if there is none. First we look for our children,
177      * then we look for any other vout that might be available. */
178     p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
179                                               FIND_CHILD );
180     if( !p_vout )
181     {
182         p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
183                                                   FIND_ANYWHERE );
184     }
185
186     if( p_vout )
187     {
188         if( !ffmpeg_CheckVout( p_vout, i_width, i_height, i_chroma ) )
189         {
190             /* We are not interested in this format, close this vout */
191             vlc_object_detach( p_vout );
192             vlc_object_release( p_vout );
193             vout_DestroyThread( p_vout );
194             p_vout = NULL;
195         }
196         else
197         {
198             /* This video output is cool! Hijack it. */
199             vlc_object_detach( p_vout );
200             vlc_object_attach( p_vout, p_vdec->p_fifo );
201             vlc_object_release( p_vout );
202         }
203     }
204
205     if( p_vout == NULL )
206     {
207         msg_Dbg( p_vdec->p_fifo, "no vout present, spawning one" );
208
209         p_vout = vout_CreateThread( p_vdec->p_fifo,
210                                     i_width, i_height,
211                                     i_chroma, i_aspect );
212     }
213
214     return( p_vout );
215 }
216
217 /* FIXME FIXME FIXME this is a big shit
218    does someone want to rewrite this function ? 
219    or said to me how write a better thing
220    FIXME FIXME FIXME
221 */
222 static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
223                                              AVPicture *p_avpicture,
224                                              vdec_thread_t   *p_vdec )
225 {
226     u8 *p_src, *p_dst;
227     u8 *p_plane[3];
228     int i_plane;
229
230     int i_stride, i_lines;
231     int i_height, i_width;
232     int i_y, i_x;
233
234     i_height = p_vdec->p_context->height;
235     i_width  = p_vdec->p_context->width;
236
237     p_dst = p_pic->p[0].p_pixels;
238     p_src  = p_avpicture->data[0];
239
240     /* copy first plane */
241     for( i_y = 0; i_y < i_height; i_y++ )
242     {
243         p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width);
244         p_dst += p_pic->p[0].i_pitch;
245         p_src += p_avpicture->linesize[0];
246     }
247
248     /* process each plane in a temporary buffer */
249     for( i_plane = 1; i_plane < 3; i_plane++ )
250     {
251         i_stride = p_avpicture->linesize[i_plane];
252         i_lines = i_height / 4;
253
254         p_dst = p_plane[i_plane] = malloc( i_lines * i_stride * 2 * 2 );
255         p_src  = p_avpicture->data[i_plane];
256
257         /* for each source line */
258         for( i_y = 0; i_y < i_lines; i_y++ )
259         {
260             for( i_x = 0; i_x < i_stride - 1; i_x++ )
261             {
262                 p_dst[2 * i_x    ] = p_src[i_x];
263                 p_dst[2 * i_x + 1] = ( p_src[i_x] + p_src[i_x + 1]) / 2;
264
265             }
266             p_dst[2 * i_stride - 2] = p_src[i_x];
267             p_dst[2 * i_stride - 1] = p_src[i_x];
268
269             p_dst += 4 * i_stride; /* process the next even lines */
270             p_src += i_stride;
271         }
272     }
273
274     for( i_plane = 1; i_plane < 3; i_plane++ )
275     {
276         i_stride = p_avpicture->linesize[i_plane];
277         i_lines = i_height / 4;
278
279         p_dst = p_plane[i_plane] + 2*i_stride;
280         p_src  = p_plane[i_plane];
281
282         for( i_y = 0; i_y < i_lines - 1; i_y++ )
283         {
284             for( i_x = 0; i_x <  2 * i_stride ; i_x++ )
285             {
286                 p_dst[i_x] = ( p_src[i_x] + p_src[i_x + 4*i_stride])/2;
287             }
288
289             p_dst += 4 * i_stride; /* process the next odd lines */
290             p_src += 4 * i_stride;
291         }
292         /* last line */
293         p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, 2*i_stride );
294     }
295     /* copy to p_pic, by block
296        if I do pixel per pixel it segfault. It's why I use 
297        temporaries buffers */
298     for( i_plane = 1; i_plane < 3; i_plane++ )
299     {
300         int i_size; 
301         p_src  = p_plane[i_plane];
302         p_dst = p_pic->p[i_plane].p_pixels;
303
304         i_size = __MIN( 2*i_stride, p_pic->p[i_plane].i_pitch);
305         for( i_y = 0; i_y < __MIN(p_pic->p[i_plane].i_lines, 2 * i_lines); i_y++ )
306         {
307             p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
308             p_src += 2 * i_stride;
309             p_dst += p_pic->p[i_plane].i_pitch;
310         }
311         free( p_plane[i_plane] );
312     }
313 }
314
315 /*****************************************************************************
316  *
317  * Functions that initialize, decode and end the decoding process
318  *
319  * Functions exported for ffmpeg.c
320  *   * E_( InitThread_Video )
321  *   * E_( DecodeThread )
322  *   * E_( EndThread_Video )
323  *****************************************************************************/
324
325 /*****************************************************************************
326  * InitThread: initialize vdec output thread
327  *****************************************************************************
328  * This function is called from decoder_Run and performs the second step 
329  * of the initialization. It returns 0 on success. Note that the thread's 
330  * flag are not modified inside this function.
331  *
332  * ffmpeg codec will be open, some memory allocated. But Vout is not yet
333  * open (done after the first decoded frame)
334  *****************************************************************************/
335 int E_( InitThread_Video )( vdec_thread_t *p_vdec )
336 {
337     int i_tmp;
338
339     if( p_vdec->p_fifo->p_demux_data )
340     {
341         p_vdec->p_format = (BITMAPINFOHEADER *)p_vdec->p_fifo->p_demux_data;
342
343         /* ***** Fill p_context with init values ***** */
344         p_vdec->p_context->width  = p_vdec->p_format->biWidth;
345         p_vdec->p_context->height = p_vdec->p_format->biHeight;
346
347     }
348     else
349     {
350         msg_Warn( p_vdec->p_fifo, "display informations missing" );
351         p_vdec->p_format = NULL;
352     }
353
354     
355     /*  ***** Get configuration of ffmpeg plugin ***** */
356 #if LIBAVCODEC_BUILD >= 4611
357     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-workaround-bugs" );
358     p_vdec->p_context->workaround_bugs  = __MAX( __MIN( i_tmp, 99 ), 0 );
359
360     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-error-resilience" );
361     p_vdec->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
362 #endif
363 #if LIBAVCODEC_BUILD >= 4614
364     if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
365     {
366         p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
367     }
368 #endif
369
370     p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
371
372     p_vdec->p_lastpic = NULL;
373     p_vdec->p_secondlastpic = NULL;
374     p_vdec->b_direct_rendering = 0;
375 #if LIBAVCODEC_BUILD > 4615
376     if( (p_vdec->p_codec->capabilities & CODEC_CAP_DR1)
377         && (p_vdec->p_context->pix_fmt != PIX_FMT_YUV410P) && 
378         config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) )
379     {
380         msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
381         p_vdec->b_direct_rendering = 1;
382         p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE | CODEC_FLAG_DR1; 
383         p_vdec->p_context->get_buffer_callback = ffmpeg_GetFrameBuf;
384         p_vdec->p_context->opaque = p_vdec;
385     }
386 #endif
387
388 #if 0
389     /* check if codec support truncated frames */
390 //    if( p_vdec->p_codec->capabilities & CODEC_FLAG_TRUNCATED )
391     if( p_vdec->i_codec_id == CODEC_ID_MPEG1VIDEO)
392     {
393         msg_Dbg( p_vdec->p_fifo, "CODEC_FLAG_TRUNCATED supported" );
394         p_vdec->p_context->flags |= CODEC_FLAG_TRUNCATED;
395     }
396 #endif
397     
398     /* ***** Open the codec ***** */
399     if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
400     {
401         msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
402                                  p_vdec->psz_namecodec );
403         return( -1 );
404     }
405     else
406     {
407         msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
408                                  p_vdec->psz_namecodec );
409     }
410
411     /* ***** init this codec with special data ***** */
412     if( p_vdec->p_format && 
413             p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
414     {
415         AVPicture avpicture;
416         int b_gotpicture;
417         
418         switch( p_vdec->i_codec_id )
419         {
420             case( CODEC_ID_MPEG4 ):
421                 avcodec_decode_video( p_vdec->p_context, &avpicture, 
422                                       &b_gotpicture,
423                                       (void *)&p_vdec->p_format[1],
424                                       p_vdec->p_format->biSize
425                                         - sizeof(BITMAPINFOHEADER) );
426                 break;
427             default:
428                 if( p_vdec->p_fifo->i_fourcc == FOURCC_MP4S ||
429                     p_vdec->p_fifo->i_fourcc == FOURCC_mp4s ||
430                     p_vdec->p_fifo->i_fourcc == FOURCC_M4S2 ||
431                     p_vdec->p_fifo->i_fourcc == FOURCC_m4s2 ||
432                     p_vdec->p_fifo->i_fourcc == FOURCC_WMV2 ||
433                     p_vdec->p_fifo->i_fourcc == FOURCC_MJPG ||
434                     p_vdec->p_fifo->i_fourcc == FOURCC_mjpg ||
435                     p_vdec->p_fifo->i_fourcc == FOURCC_mjpa ||
436                     p_vdec->p_fifo->i_fourcc == FOURCC_mjpb )
437                 {
438                     p_vdec->p_context->extradata_size =
439                         p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
440                     p_vdec->p_context->extradata =
441                         malloc( p_vdec->p_context->extradata_size );
442                     memcpy( p_vdec->p_context->extradata,
443                             &p_vdec->p_format[1],
444                             p_vdec->p_context->extradata_size );
445                 }
446
447                 break;
448         }
449     }
450     
451     /* ***** Load post processing ***** */
452
453     /* get overridding settings */
454     p_vdec->i_pp_mode = 0;
455     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
456         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
457     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
458         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
459     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
460         p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
461     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
462         p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
463     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
464         p_vdec->i_pp_mode |= PP_DERING_Y;
465     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
466         p_vdec->i_pp_mode |= PP_DERING_C;
467
468     if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
469         ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )  )||
470         ( p_vdec->i_pp_mode != 0 ) )
471     {
472         /* check if the codec support postproc. */
473         switch( p_vdec->i_codec_id )
474         {
475 #if LIBAVCODEC_BUILD > 4608
476             case( CODEC_ID_MSMPEG4V1 ):
477             case( CODEC_ID_MSMPEG4V2 ):
478             case( CODEC_ID_MSMPEG4V3 ):
479 #else
480             case( CODEC_ID_MSMPEG4 ):
481 #endif
482             case( CODEC_ID_MPEG4 ):
483             case( CODEC_ID_H263 ):
484 //            case( CODEC_ID_H263P ): I don't use it up to now
485             case( CODEC_ID_H263I ):
486                 /* Ok we can make postprocessing :)) */
487                 /* first try to get a postprocess module */
488 #if LIBAVCODEC_BUILD >= 4633
489                 p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
490                                                   sizeof( postprocessing_t ) );
491                 p_vdec->p_pp->psz_object_name = "postprocessing";
492                 p_vdec->p_pp->p_module = 
493                    module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
494
495                 if( !p_vdec->p_pp->p_module )
496                 {
497                     msg_Warn( p_vdec->p_fifo, 
498                               "no suitable postprocessing module" );
499                     vlc_object_destroy( p_vdec->p_pp );
500                     p_vdec->p_pp = NULL;
501                     p_vdec->i_pp_mode = 0;
502                 }
503                 else
504                 {
505                     /* get mode upon quality */
506                     p_vdec->i_pp_mode |= 
507                         p_vdec->p_pp->pf_getmode( 
508                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
509                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
510                                                 );
511
512                     /* allocate table for postprocess */
513 //                    p_vdec->p_context->quant_store = 
514 //                        malloc( sizeof( int ) * ( MBR + 1 ) * ( MBC + 1 ) );
515 //                    p_vdec->p_context->qstride = MBC + 1;
516                 }
517 #else
518                 p_vdec->i_pp_mode = 0;
519                 msg_Warn( p_vdec->p_fifo, 
520                           "post-processing not supported, upgrade ffmpeg" );
521 #endif
522                 break;
523             default:
524                 p_vdec->i_pp_mode = 0;
525                 msg_Warn( p_vdec->p_fifo, 
526                           "Post processing unsupported for this codec" );
527                 break;
528         }
529
530     }
531 //    memset( &p_vdec->statistic, 0, sizeof( statistic_t ) );
532
533     return( 0 );
534 }
535
536 /*****************************************************************************
537  * DecodeThread: Called to decode one frame
538  *****************************************************************************
539  * We have to get a frame stored in a pes, give it to ffmpeg decoder and send
540  * the image to the output.
541  *****************************************************************************/
542 void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
543 {
544     pes_packet_t    *p_pes;
545     int     i_frame_size;
546     int     i_used;
547     int     b_drawpicture;
548     int     b_gotpicture;
549     AVPicture avpicture;                                   /* ffmpeg picture */
550     picture_t *p_pic;                                    /* videolan picture */
551     mtime_t   i_pts;
552
553     /* TODO implement it in a better way */
554     /* A good idea could be to decode all I pictures and see for the other */
555     if( ( p_vdec->b_hurry_up )&& ( p_vdec->i_frame_late > 4 ) )
556     {
557 #if LIBAVCODEC_BUILD > 4603
558         b_drawpicture = 0;
559         if( p_vdec->i_frame_late < 8 )
560         {
561             p_vdec->p_context->hurry_up = 2;
562         }
563         else
564         {
565             /* too much late picture, won't decode 
566                but break picture until a new I, and for mpeg4 ...*/
567             p_vdec->i_frame_late--; /* needed else it will never be decrease */
568             input_ExtractPES( p_vdec->p_fifo, NULL );
569             return;
570         }
571 #else
572         if( p_vdec->i_frame_late < 8 )
573         {
574             b_drawpicture = 0; /* not really good but .. UPGRADE FFMPEG !! */
575         }
576         else
577         {
578             /* too much late picture, won't decode 
579                but break picture until a new I, and for mpeg4 ...*/
580             p_vdec->i_frame_late--; /* needed else it will never be decrease */
581             input_ExtractPES( p_vdec->p_fifo, NULL );
582             return;
583         }
584 #endif
585     }
586     else
587     {
588         b_drawpicture = 1;
589 #if LIBAVCODEC_BUILD > 4603
590         p_vdec->p_context->hurry_up = 0;
591 #endif
592     }
593
594     do
595     {
596         input_ExtractPES( p_vdec->p_fifo, &p_pes );
597         if( !p_pes )
598         {
599             p_vdec->p_fifo->b_error = 1;
600             return;
601         }
602 #if 0
603         if( p_vdec->i_codec_id == CODEC_ID_MPEG1VIDEO )
604         {
605             if( p_pes->i_dts )
606             {
607                 p_vdec->pts = p_pes->i_dts;
608                 p_vdec->i_frame_count = 0;
609             }
610         }
611         else
612         {
613             if( p_pes->i_pts )
614             {
615                 p_vdec->pts = p_pes->i_pts;
616                 p_vdec->i_frame_count = 0;
617             }
618         }
619 #endif   
620         if( p_pes->i_pts )
621         {
622             p_vdec->pts = p_pes->i_pts;
623             p_vdec->i_frame_count = 0;
624         }
625
626         i_frame_size = p_pes->i_pes_size;
627
628         if( i_frame_size > 0 )
629         {
630             uint8_t *p_last;
631             int i_need;
632             /* XXX Don't forget that ffmpeg required a little more bytes 
633              * that the real frame size */
634             i_need = i_frame_size + 16 + p_vdec->i_buffer; 
635             if( p_vdec->i_buffer_size < i_need)
636             {
637                 p_last = p_vdec->p_buffer;
638                 p_vdec->p_buffer = malloc( i_need );
639                 p_vdec->i_buffer_size = i_need;
640                 if( p_vdec->i_buffer > 0 )
641                 {
642                     memcpy( p_vdec->p_buffer, p_last, p_vdec->i_buffer );
643                 }
644                 FREE( p_last );
645             }
646             i_frame_size = 
647                 E_( GetPESData )( p_vdec->p_buffer + p_vdec->i_buffer, 
648                                   i_frame_size ,
649                                   p_pes );
650             memset( p_vdec->p_buffer + p_vdec->i_buffer + i_frame_size,
651                     0,
652                     16 );
653         }   
654         input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
655     } while( i_frame_size <= 0 );
656
657     i_frame_size += p_vdec->i_buffer;
658
659 usenextdata:
660     i_used = avcodec_decode_video( p_vdec->p_context,
661                                    &avpicture,
662                                    &b_gotpicture,
663                                    p_vdec->p_buffer,
664                                    i_frame_size );
665
666 #if 0
667     msg_Dbg( p_vdec->p_fifo, 
668              "used:%d framesize:%d (%s picture)", 
669              i_used, i_frame_size, b_gotpicture ? "got":"no got" );
670 #endif
671     if( i_used < 0 )
672     {
673         msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
674                                   i_frame_size );
675         p_vdec->i_frame_error++;
676         p_vdec->i_buffer = 0;
677         return;
678     }
679     else if( i_used < i_frame_size )
680     {
681 #if 0
682         msg_Dbg( p_vdec->p_fifo, 
683                  "didn't use all memory(%d  < %d)", i_used, i_frame_size );
684 #endif
685         memmove( p_vdec->p_buffer,
686                  p_vdec->p_buffer + i_used,
687                  p_vdec->i_buffer_size - i_used );
688         
689         p_vdec->i_buffer = i_frame_size - i_used;
690     }
691     else
692     {
693         p_vdec->i_buffer = 0;
694     }
695     
696     if( b_gotpicture )
697     {
698         p_vdec->i_frame_count++;
699     }
700     
701     /* consumed bytes */
702     i_frame_size -= i_used;
703
704    /* Update frame late count*/
705     /* I don't make statistic on decoding time */
706     if( p_vdec->pts <= mdate()) 
707     {
708         p_vdec->i_frame_late++;
709     }
710     else
711     {
712         p_vdec->i_frame_late = 0;
713     }
714
715     if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture )
716     {
717         return;
718     }
719
720     if( !p_vdec->b_direct_rendering )
721     {
722         /* Check our vout */
723         if( !ffmpeg_CheckVout( p_vdec->p_vout, 
724                            p_vdec->p_context->width,
725                            p_vdec->p_context->height,
726                            ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) )
727         {
728             p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
729             if( !p_vdec->p_vout )
730             {
731                 msg_Err( p_vdec->p_fifo, "cannot create vout" );
732                 p_vdec->p_fifo->b_error = 1; /* abort */
733                 return;
734             }
735         }
736
737         /* Get a new picture */
738         while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
739         {
740             if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
741             {
742                 return;
743             }
744             msleep( VOUT_OUTMEM_SLEEP );
745         }
746
747         /* fill p_picture_t from avpicture, do I410->I420 if needed */
748         ffmpeg_CopyPicture( p_pic, &avpicture, p_vdec );
749     }
750     else
751     {
752 #if LIBAVCODEC_BUILD > 4615
753         p_pic = (picture_t *)p_vdec->p_context->dr_opaque_frame;
754 #endif
755     }
756
757     /* Do post-processing if requested */
758     ffmpeg_PostProcPicture( p_vdec, p_pic );
759
760     /* Send decoded frame to vout */
761     if( p_vdec->pts > 0 )
762     {
763         i_pts = p_vdec->pts;
764        
765         if( p_vdec->p_context->frame_rate > 0 )
766         {
767            i_pts += (uint64_t)1000000 * 
768                     ( p_vdec->i_frame_count - 1) /
769                     FRAME_RATE_BASE /
770                     p_vdec->p_context->frame_rate;
771         }
772     }
773     else
774     {
775         i_pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
776     }
777
778     vout_DatePicture( p_vdec->p_vout, 
779                       p_pic, 
780                       i_pts );
781
782     vout_DisplayPicture( p_vdec->p_vout, p_pic );
783     
784     if( i_frame_size > 0 )
785     {
786         goto usenextdata;
787     }
788 }
789
790 /*****************************************************************************
791  * EndThread: thread destruction
792  *****************************************************************************
793  * This function is called when the thread ends after a sucessful
794  * initialization.
795  *****************************************************************************/
796 void E_( EndThread_Video )( vdec_thread_t *p_vdec )
797 {
798     if( p_vdec->p_secondlastpic )
799         vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
800     if( p_vdec->p_lastpic )
801         vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_lastpic );
802
803     if( p_vdec->p_pp )
804     {
805         /* release postprocessing module */
806         module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
807         vlc_object_destroy( p_vdec->p_pp );
808         p_vdec->p_pp = NULL;
809     }
810
811     if( p_vdec->p_vout != NULL )
812     {
813         /* We are about to die. Reattach video output to p_vlc. */
814         vlc_object_detach( p_vdec->p_vout );
815         vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc );
816     }
817 }
818
819 /*****************************************************************************
820  * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
821  *                     picture_t structure (when not in direct rendering mode).
822  *****************************************************************************/
823 static void ffmpeg_CopyPicture( picture_t *p_pic, AVPicture *p_avpicture,
824                                 vdec_thread_t *p_vdec )
825 {
826     int i_plane; 
827     int i_size;
828     int i_line;
829
830     u8  *p_dst;
831     u8  *p_src;
832     int i_src_stride;
833     int i_dst_stride;
834
835     if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
836     {
837         for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
838         {
839             p_src  = p_avpicture->data[i_plane];
840             p_dst = p_pic->p[i_plane].p_pixels;
841             i_src_stride = p_avpicture->linesize[i_plane];
842             i_dst_stride = p_pic->p[i_plane].i_pitch;
843
844             i_size = __MIN( i_src_stride, i_dst_stride );
845             for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
846             {
847                 p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
848                 p_src += i_src_stride;
849                 p_dst += i_dst_stride;
850             }
851         }
852     }
853     else
854     {
855         /* we need to convert to I420 */
856         switch( p_vdec->p_context->pix_fmt )
857         {
858 #if LIBAVCODEC_BUILD >= 4615
859             case( PIX_FMT_YUV410P ):
860                 ffmpeg_ConvertPictureI410toI420( p_pic, p_avpicture, p_vdec );
861                 break;
862 #endif            
863             default:
864                 p_vdec->p_fifo->b_error = 1;
865                 break;
866         }
867     }
868 }
869
870 /*****************************************************************************
871  * ffmpeg_PostProcPicture: Postprocessing is done here.
872  *****************************************************************************/
873 static void ffmpeg_PostProcPicture( vdec_thread_t *p_vdec, picture_t *p_pic )
874 {
875 #if LIBAVCODEC_BUILD > 4313
876     if( ( p_vdec->i_pp_mode )&&
877         ( ( p_vdec->p_vout->render.i_chroma == 
878             VLC_FOURCC( 'I','4','2','0' ) )||
879           ( p_vdec->p_vout->render.i_chroma == 
880             VLC_FOURCC( 'Y','V','1','2' ) ) ) )
881     {
882         /* Make postproc */
883         p_vdec->p_pp->pf_postprocess( p_pic,
884                                       p_vdec->p_context->display_qscale_table,
885 //                                      p_vdec->p_context->current_qscale_table,
886                                       p_vdec->p_context->qstride,
887                                       p_vdec->i_pp_mode );
888     }
889 #endif
890 }
891
892 /*****************************************************************************
893  * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
894  *                     (used for direct rendering)
895  *****************************************************************************/
896 static int ffmpeg_GetFrameBuf( struct AVCodecContext *avctx, int width,
897                                int height, int pict_type )
898 {
899 #if LIBAVCODEC_BUILD > 4615
900     vdec_thread_t *p_vdec = (vdec_thread_t *)avctx->opaque;
901     picture_t *p_pic;
902
903     /* Check our vout */
904     if( !ffmpeg_CheckVout( p_vdec->p_vout,
905                            p_vdec->p_context->width,
906                            p_vdec->p_context->height,
907                            ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) )
908     {
909         p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
910         if( !p_vdec->p_vout )
911         {
912             msg_Err( p_vdec->p_fifo, "cannot create vout" );
913             p_vdec->p_fifo->b_error = 1; /* abort */
914             return -1;
915         }
916     }
917
918     /* Get a new picture */
919     while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
920     {
921         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
922         {
923             return -1;
924         }
925         msleep( VOUT_OUTMEM_SLEEP );
926     }
927
928     /* FIXME: We keep the last picture linked until the current one is decoded,
929      * this trick won't work with streams with B frames though. */
930     vout_LinkPicture( p_vdec->p_vout, p_pic );
931     if( p_vdec->p_secondlastpic )
932         vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
933     p_vdec->p_secondlastpic = p_vdec->p_lastpic;
934     p_vdec->p_lastpic = p_pic;
935
936     avctx->draw_horiz_band= NULL;
937     avctx->dr_buffer[0]= p_pic->p[0].p_pixels;
938     avctx->dr_buffer[1]= p_pic->p[1].p_pixels;
939     avctx->dr_buffer[2]= p_pic->p[2].p_pixels;
940
941     avctx->dr_stride   = p_pic->p[0].i_pitch;
942     avctx->dr_uvstride = p_pic->p[1].i_pitch;
943
944     avctx->dr_opaque_frame = p_pic;
945
946     /* This variable is used to determine if a macro-block to be written
947      * can be skipped. The idea behind this is that if a macro-block hasn't
948      * changed and all the frame-buffers already have the value of this
949      * macro-block, then we don't need to write it again. */
950     avctx->dr_ip_buffer_count = p_vdec->p_vout->render.i_pictures;
951     p_vdec->p_vout->render.b_allow_modify_pics = 0;
952
953     return 0;
954 #endif
955 }