]> git.sesse.net Git - vlc/blob - modules/codec/ffmpeg/video.c
* modules/codec/spudec/*: modified the spu decoder to handle text subtitles.
[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.3 2002/11/06 21:48:24 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     {
359         msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
360         p_vdec->b_direct_rendering = 1;
361         p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE | CODEC_FLAG_DR1; 
362         p_vdec->p_context->get_buffer_callback = ffmpeg_GetFrameBuf;
363         p_vdec->p_context->opaque = p_vdec;
364     }
365 #endif
366
367     /* ***** Open the codec ***** */
368     if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
369     {
370         msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
371                                  p_vdec->psz_namecodec );
372         return( -1 );
373     }
374     else
375     {
376         msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
377                                  p_vdec->psz_namecodec );
378     }
379
380     /* ***** init this codec with special data ***** */
381     if( p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
382     {
383         AVPicture avpicture;
384         int b_gotpicture;
385         
386         switch( p_vdec->i_codec_id )
387         {
388             case( CODEC_ID_MPEG4 ):
389                 avcodec_decode_video( p_vdec->p_context, &avpicture, 
390                                       &b_gotpicture,
391                                       (void *)&p_vdec->p_format[1],
392                                       p_vdec->p_format->biSize
393                                         - sizeof(BITMAPINFOHEADER) );
394                 break;
395             default:
396                 if( p_vdec->p_fifo->i_fourcc == FOURCC_MP4S ||
397                     p_vdec->p_fifo->i_fourcc == FOURCC_mp4s ||
398                     p_vdec->p_fifo->i_fourcc == FOURCC_M4S2 ||
399                     p_vdec->p_fifo->i_fourcc == FOURCC_m4s2 )
400                 {
401                     p_vdec->p_context->extradata_size =
402                         p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
403                     p_vdec->p_context->extradata =
404                         malloc( p_vdec->p_context->extradata_size );
405                     memcpy( p_vdec->p_context->extradata,
406                             &p_vdec->p_format[1],
407                             p_vdec->p_context->extradata_size );
408                 }
409
410                 break;
411         }
412     }
413     
414     /* ***** Load post processing ***** */
415
416     /* get overridding settings */
417     p_vdec->i_pp_mode = 0;
418     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
419         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
420     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
421         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
422     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
423         p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
424     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
425         p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
426     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
427         p_vdec->i_pp_mode |= PP_DERING_Y;
428     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
429         p_vdec->i_pp_mode |= PP_DERING_C;
430
431     if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
432         ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )  )||
433         ( p_vdec->i_pp_mode != 0 ) )
434     {
435         /* check if the codec support postproc. */
436         switch( p_vdec->i_codec_id )
437         {
438 #if LIBAVCODEC_BUILD > 4608
439             case( CODEC_ID_MSMPEG4V1 ):
440             case( CODEC_ID_MSMPEG4V2 ):
441             case( CODEC_ID_MSMPEG4V3 ):
442 #else
443             case( CODEC_ID_MSMPEG4 ):
444 #endif
445             case( CODEC_ID_MPEG4 ):
446             case( CODEC_ID_H263 ):
447 //            case( CODEC_ID_H263P ): I don't use it up to now
448             case( CODEC_ID_H263I ):
449                 /* Ok we can make postprocessing :)) */
450                 /* first try to get a postprocess module */
451 #if LIBAVCODEC_BUILD > 4613
452                 p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
453                                                   sizeof( postprocessing_t ) );
454                 p_vdec->p_pp->psz_object_name = "postprocessing";
455                 p_vdec->p_pp->p_module = 
456                    module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
457
458                 if( !p_vdec->p_pp->p_module )
459                 {
460                     msg_Warn( p_vdec->p_fifo, 
461                               "no suitable postprocessing module" );
462                     vlc_object_destroy( p_vdec->p_pp );
463                     p_vdec->p_pp = NULL;
464                     p_vdec->i_pp_mode = 0;
465                 }
466                 else
467                 {
468                     /* get mode upon quality */
469                     p_vdec->i_pp_mode |= 
470                         p_vdec->p_pp->pf_getmode( 
471                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
472                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
473                                                 );
474
475                     /* allocate table for postprocess */
476                     p_vdec->p_context->quant_store = 
477                         malloc( sizeof( int ) * ( MBR + 1 ) * ( MBC + 1 ) );
478                     p_vdec->p_context->qstride = MBC + 1;
479                 }
480 #else
481                 p_vdec->i_pp_mode = 0;
482                 msg_Warn( p_vdec->p_fifo, 
483                           "post-processing not supported, upgrade ffmpeg" );
484 #endif
485                 break;
486             default:
487                 p_vdec->i_pp_mode = 0;
488                 msg_Warn( p_vdec->p_fifo, 
489                           "Post processing unsupported for this codec" );
490                 break;
491         }
492
493     }
494 //    memset( &p_vdec->statistic, 0, sizeof( statistic_t ) );
495
496     return( 0 );
497 }
498
499 /*****************************************************************************
500  * DecodeThread: Called for decode one frame
501  *****************************************************************************
502  * We have to get a frame stored in a pes, give it to ffmpeg decoder and send
503  * the image to the output.
504  *****************************************************************************/
505 void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
506 {
507     pes_packet_t    *p_pes;
508     int     i_frame_size;
509     int     i_status;
510     int     b_drawpicture;
511     int     b_gotpicture;
512     AVPicture avpicture;                                   /* ffmpeg picture */
513     picture_t *p_pic;                                    /* videolan picture */
514
515     /* TODO implement it in a better way */
516     /* A good idea could be to decode all I pictures and see for the other */
517     if( ( p_vdec->b_hurry_up )&& ( p_vdec->i_frame_late > 4 ) )
518     {
519 #if LIBAVCODEC_BUILD > 4603
520         b_drawpicture = 0;
521         if( p_vdec->i_frame_late < 8 )
522         {
523             p_vdec->p_context->hurry_up = 2;
524         }
525         else
526         {
527             /* too much late picture, won't decode 
528                but break picture until a new I, and for mpeg4 ...*/
529             p_vdec->i_frame_late--; /* needed else it will never be decrease */
530             input_ExtractPES( p_vdec->p_fifo, NULL );
531             return;
532         }
533 #else
534         if( p_vdec->i_frame_late < 8 )
535         {
536             b_drawpicture = 0; /* not really good but .. UPGRADE FFMPEG !! */
537         }
538         else
539         {
540             /* too much late picture, won't decode 
541                but break picture until a new I, and for mpeg4 ...*/
542             p_vdec->i_frame_late--; /* needed else it will never be decrease */
543             input_ExtractPES( p_vdec->p_fifo, NULL );
544             return;
545         }
546 #endif
547     }
548     else
549     {
550         b_drawpicture = 1;
551 #if LIBAVCODEC_BUILD > 4603
552         p_vdec->p_context->hurry_up = 0;
553 #endif
554     }
555
556     do
557     {
558         input_ExtractPES( p_vdec->p_fifo, &p_pes );
559         if( !p_pes )
560         {
561             p_vdec->p_fifo->b_error = 1;
562             return;
563         }
564         p_vdec->pts = p_pes->i_pts;
565         i_frame_size = p_pes->i_pes_size;
566
567         if( i_frame_size > 0 )
568         {
569             if( p_vdec->i_buffer < i_frame_size + 16 )
570             {
571                 FREE( p_vdec->p_buffer );
572                 p_vdec->p_buffer = malloc( i_frame_size + 16 );
573                 p_vdec->i_buffer = i_frame_size + 16;
574             }
575             
576             E_( GetPESData )( p_vdec->p_buffer, p_vdec->i_buffer, p_pes );
577         }
578         input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
579     } while( i_frame_size <= 0 );
580
581
582     i_status = avcodec_decode_video( p_vdec->p_context,
583                                      &avpicture,
584                                      &b_gotpicture,
585                                      p_vdec->p_buffer,
586                                      i_frame_size );
587
588     if( i_status < 0 )
589     {
590         msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
591                                   i_frame_size );
592         p_vdec->i_frame_error++;
593         return;
594     }
595     /* Update frame late count*/
596     /* I don't make statistic on decoding time */
597     if( p_vdec->pts <= mdate()) 
598     {
599         p_vdec->i_frame_late++;
600     }
601     else
602     {
603         p_vdec->i_frame_late = 0;
604     }
605
606     if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture )
607     {
608         return;
609     }
610
611     if( !p_vdec->b_direct_rendering )
612     {
613         /* Check our vout */
614         if( !ffmpeg_CheckVout( p_vdec->p_vout,
615                            p_vdec->p_context->width,
616                            p_vdec->p_context->height,
617                            p_vdec->p_context->aspect_ratio_info,
618                            ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) )
619         {
620             p_vdec->p_vout = ffmpeg_CreateVout( p_vdec,
621                            p_vdec->p_context->width,
622                            p_vdec->p_context->height,
623                            p_vdec->p_context->aspect_ratio_info,
624                            ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt) );
625             if( !p_vdec->p_vout )
626             {
627                 msg_Err( p_vdec->p_fifo, "cannot create vout" );
628                 p_vdec->p_fifo->b_error = 1; /* abort */
629                 return;
630             }
631         }
632
633         /* Get a new picture */
634         while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
635         {
636             if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
637             {
638                 return;
639             }
640             msleep( VOUT_OUTMEM_SLEEP );
641         }
642
643         /* fill p_picture_t from avpicture, do I410->I420 if needed */
644         ffmpeg_CopyPicture( p_pic, &avpicture, p_vdec );
645     }
646     else
647     {
648 #if LIBAVCODEC_BUILD > 4615
649         p_pic = (picture_t *)p_vdec->p_context->dr_opaque_frame;
650 #endif
651     }
652
653     /* Do post-processing if requested */
654     ffmpeg_PostProcPicture( p_vdec, p_pic );
655
656     /* FIXME correct avi and use i_dts */
657
658     /* Send decoded frame to vout */
659     vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->pts);
660     vout_DisplayPicture( p_vdec->p_vout, p_pic );
661     
662     return;
663 }
664
665 /*****************************************************************************
666  * EndThread: thread destruction
667  *****************************************************************************
668  * This function is called when the thread ends after a sucessful
669  * initialization.
670  *****************************************************************************/
671 void E_( EndThread_Video )( vdec_thread_t *p_vdec )
672 {
673     if( p_vdec->p_secondlastpic )
674         vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
675     if( p_vdec->p_lastpic )
676         vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_lastpic );
677
678     if( p_vdec->p_pp )
679     {
680         /* release postprocessing module */
681         module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
682         vlc_object_destroy( p_vdec->p_pp );
683         p_vdec->p_pp = NULL;
684     }
685
686     if( p_vdec->p_vout != NULL )
687     {
688         /* We are about to die. Reattach video output to p_vlc. */
689         vlc_object_detach( p_vdec->p_vout );
690         vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc );
691     }
692 }
693
694 /*****************************************************************************
695  * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
696  *                     picture_t structure (when not in direct rendering mode).
697  *****************************************************************************/
698 static void ffmpeg_CopyPicture( picture_t *p_pic, AVPicture *p_avpicture,
699                                 vdec_thread_t *p_vdec )
700 {
701     int i_plane; 
702     int i_size;
703     int i_line;
704
705     u8  *p_dst;
706     u8  *p_src;
707     int i_src_stride;
708     int i_dst_stride;
709
710     if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
711     {
712         for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
713         {
714             p_src  = p_avpicture->data[i_plane];
715             p_dst = p_pic->p[i_plane].p_pixels;
716             i_src_stride = p_avpicture->linesize[i_plane];
717             i_dst_stride = p_pic->p[i_plane].i_pitch;
718
719             i_size = __MIN( i_src_stride, i_dst_stride );
720             for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
721             {
722                 p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
723                 p_src += i_src_stride;
724                 p_dst += i_dst_stride;
725             }
726         }
727     }
728     else
729     {
730         /* we need to convert to I420 */
731         switch( p_vdec->p_context->pix_fmt )
732         {
733 #if LIBAVCODEC_BUILD >= 4615
734             case( PIX_FMT_YUV410P ):
735                 ffmpeg_ConvertPictureI410toI420( p_pic, p_avpicture, p_vdec );
736                 break;
737 #endif            
738             default:
739                 p_vdec->p_fifo->b_error = 1;
740                 break;
741         }
742     }
743 }
744
745 /*****************************************************************************
746  * ffmpeg_PostProcPicture: Postprocessing is done here.
747  *****************************************************************************/
748 static void ffmpeg_PostProcPicture( vdec_thread_t *p_vdec, picture_t *p_pic )
749 {
750 #if LIBAVCODEC_BUILD > 4313
751     if( ( p_vdec->i_pp_mode )&&
752         ( ( p_vdec->p_vout->render.i_chroma == 
753             VLC_FOURCC( 'I','4','2','0' ) )||
754           ( p_vdec->p_vout->render.i_chroma == 
755             VLC_FOURCC( 'Y','V','1','2' ) ) ) )
756     {
757         /* Make postproc */
758         p_vdec->p_pp->pf_postprocess( p_pic,
759                                       p_vdec->p_context->quant_store, 
760                                       p_vdec->p_context->qstride,
761                                       p_vdec->i_pp_mode );
762     }
763 #endif
764 }
765
766 /*****************************************************************************
767  * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
768  *                     (used for direct rendering)
769  *****************************************************************************/
770 static int ffmpeg_GetFrameBuf( struct AVCodecContext *avctx, int width,
771                                int height, int pict_type )
772 {
773 #if LIBAVCODEC_BUILD > 4615
774     vdec_thread_t *p_vdec = (vdec_thread_t *)avctx->opaque;
775     picture_t *p_pic;
776
777     /* Check our vout */
778     if( !ffmpeg_CheckVout( p_vdec->p_vout,
779                            p_vdec->p_context->width,
780                            p_vdec->p_context->height,
781                            p_vdec->p_context->aspect_ratio_info,
782                            ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) )
783     {
784         p_vdec->p_vout = ffmpeg_CreateVout( p_vdec,
785                            p_vdec->p_context->width,
786                            p_vdec->p_context->height,
787                            p_vdec->p_context->aspect_ratio_info,
788                            ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt) );
789         if( !p_vdec->p_vout )
790         {
791             msg_Err( p_vdec->p_fifo, "cannot create vout" );
792             p_vdec->p_fifo->b_error = 1; /* abort */
793             return -1;
794         }
795     }
796
797     /* Get a new picture */
798     while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
799     {
800         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
801         {
802             return -1;
803         }
804         msleep( VOUT_OUTMEM_SLEEP );
805     }
806
807     /* FIXME: We keep the last picture linked until the current one is decoded,
808      * this trick won't work with streams with B frames though. */
809     vout_LinkPicture( p_vdec->p_vout, p_pic );
810     if( p_vdec->p_secondlastpic )
811         vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
812     p_vdec->p_secondlastpic = p_vdec->p_lastpic;
813     p_vdec->p_lastpic = p_pic;
814
815     avctx->draw_horiz_band= NULL;
816     avctx->dr_buffer[0]= p_pic->p[0].p_pixels;
817     avctx->dr_buffer[1]= p_pic->p[1].p_pixels;
818     avctx->dr_buffer[2]= p_pic->p[2].p_pixels;
819
820     avctx->dr_stride   = p_pic->p[0].i_pitch;
821     avctx->dr_uvstride = p_pic->p[1].i_pitch;
822
823     avctx->dr_opaque_frame = p_pic;
824
825     /* FIXME: this variable is used to determine if a macro-block to be written
826      * can be skipped. The idea behind this is that if a macro-block hasn't
827      * changed and all the frame-buffers already have the value of this
828      * macro-block, then we can skip the writting.
829      * But currently we cannot ensure this is the case, so we decide to write
830      * everything. */
831     avctx->dr_ip_buffer_count = 999;
832
833     return 0;
834 #endif
835 }