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