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