bb6c4c9ed26176bb16b4b25f357533eea258ea23
[vlc.git] / modules / codec / ffmpeg / video.c
1 /*****************************************************************************
2  * video.c: video decoder using ffmpeg library
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: video.c,v 1.26 2003/05/07 15:44:59 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin@netcourrier.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/vout.h>
32 #include <vlc/aout.h>
33 #include <vlc/decoder.h>
34 #include <vlc/input.h>
35
36 #include <string.h>
37
38 #ifdef HAVE_SYS_TIMES_H
39 #   include <sys/times.h>
40 #endif
41
42 /* ffmpeg header */
43 #ifdef HAVE_FFMPEG_AVCODEC_H
44 #   include <ffmpeg/avcodec.h>
45 #else
46 #   include <avcodec.h>
47 #endif
48
49 #include "ffmpeg.h"
50
51 #ifdef LIBAVCODEC_PP
52 #   ifdef HAVE_POSTPROC_POSTPROCESS_H
53 #       include <postproc/postprocess.h>
54 #   else
55 #       include <libpostproc/postprocess.h>
56 #   endif
57 #else
58 #   include "postprocessing/postprocessing.h"
59 #endif
60
61 #include "video.h"
62
63
64 /*****************************************************************************
65  * Local prototypes
66  *****************************************************************************/
67 static void ffmpeg_CopyPicture( picture_t *, AVFrame *, vdec_thread_t * );
68
69 #ifndef LIBAVCODEC_PP
70 static void ffmpeg_PostProcPicture( vdec_thread_t *, picture_t * );
71 #endif
72
73 /* direct rendering */
74 static int  ffmpeg_GetFrameBuf      ( struct AVCodecContext *, AVFrame *);
75 static void ffmpeg_ReleaseFrameBuf  ( struct AVCodecContext *, AVFrame *);
76
77 /*****************************************************************************
78  * Local Functions
79  *****************************************************************************/
80
81 static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
82 {
83     /* FIXME FIXME some of them are wrong */
84     switch( i_ff_chroma )
85     {
86         case PIX_FMT_YUV420P:
87         case PIX_FMT_YUV422:
88             return( VLC_FOURCC('I','4','2','0') );
89         case PIX_FMT_RGB24:
90             return( VLC_FOURCC('R','V','2','4') );
91
92         case PIX_FMT_YUV422P:
93             return( VLC_FOURCC('I','4','2','2') );
94         case PIX_FMT_YUV444P:
95             return( VLC_FOURCC('I','4','4','4') );
96         case PIX_FMT_YUV410P:
97         case PIX_FMT_YUV411P:
98         case PIX_FMT_BGR24:
99         default:
100             return( 0 );
101     }
102 }
103
104 /* Return a Vout */
105 static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
106                                          AVCodecContext *p_context )
107 {
108     vout_thread_t *p_vout;
109     unsigned int   i_width = p_context->width;
110     unsigned int   i_height = p_context->height;
111     uint32_t       i_chroma = ffmpeg_PixFmtToChroma( p_context->pix_fmt );
112     unsigned int   i_aspect;
113
114     if( !i_width || !i_height )
115     {
116         return( NULL ); /* Can't create a new vout without display size */
117     }
118
119     if( !i_chroma )
120     {
121         /* we make conversion if possible*/
122         i_chroma = VLC_FOURCC('I','4','2','0');
123     }
124
125     i_aspect = VOUT_ASPECT_FACTOR * p_context->aspect_ratio;
126     if( i_aspect == 0 )
127     {
128         i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
129     }
130
131     /* Spawn a video output if there is none. First we look for our children,
132      * then we look for any other vout that might be available. */
133     p_vout = vout_Request( p_vdec->p_fifo, NULL,
134                            i_width, i_height, i_chroma, i_aspect );
135 #ifdef LIBAVCODEC_PP
136     if( p_vdec->pp_mode && !p_vdec->pp_context )
137     {
138         int32_t i_cpu = p_vdec->p_fifo->p_libvlc->i_cpu;
139         int i_flags = 0;
140
141         if( i_cpu & CPU_CAPABILITY_MMX )
142         {
143             i_flags |= PP_CPU_CAPS_MMX;
144         }
145         if( i_cpu & CPU_CAPABILITY_MMXEXT )
146         {
147             i_flags |= PP_CPU_CAPS_MMX2;
148         }
149         if( i_cpu & CPU_CAPABILITY_3DNOW )
150         {
151             i_flags |= PP_CPU_CAPS_3DNOW;
152         }
153
154         switch( p_context->pix_fmt )
155         {
156             case PIX_FMT_YUV444P:
157                 i_flags |= PP_FORMAT_444;
158                 break;
159             case PIX_FMT_YUV422P:
160                 i_flags |= PP_FORMAT_422;
161                 break;
162             case PIX_FMT_YUV411P:
163                 i_flags |= PP_FORMAT_411;
164                 break;
165             default:
166                 i_flags |= PP_FORMAT_420;
167                 break;
168         }
169
170         p_vdec->pp_context = pp_get_context( i_width, i_height, i_flags );
171     }
172 #endif
173
174     return p_vout;
175 }
176
177 /*****************************************************************************
178  *
179  * Functions that initialize, decode and end the decoding process
180  *
181  * Functions exported for ffmpeg.c
182  *   * E_( InitThread_Video )
183  *   * E_( DecodeThread )
184  *   * E_( EndThread_Video )
185  *****************************************************************************/
186
187 /*****************************************************************************
188  * InitThread: initialize vdec output thread
189  *****************************************************************************
190  * This function is called from decoder_Run and performs the second step
191  * of the initialization. It returns 0 on success. Note that the thread's
192  * flag are not modified inside this function.
193  *
194  * ffmpeg codec will be open, some memory allocated. But Vout is not yet
195  * open (done after the first decoded frame)
196  *****************************************************************************/
197 int E_( InitThread_Video )( vdec_thread_t *p_vdec )
198 {
199     int i_tmp;
200     int i_truncated;
201
202     p_vdec->p_ff_pic = avcodec_alloc_frame();
203
204     if( ( p_vdec->p_format = (BITMAPINFOHEADER *)p_vdec->p_fifo->p_bitmapinfoheader) != NULL )
205     {
206         /* ***** Fill p_context with init values ***** */
207         p_vdec->p_context->width  = p_vdec->p_format->biWidth;
208         p_vdec->p_context->height = p_vdec->p_format->biHeight;
209     }
210     else
211     {
212         msg_Warn( p_vdec->p_fifo, "display informations missing" );
213         p_vdec->p_format = NULL;
214     }
215
216
217     /*  ***** Get configuration of ffmpeg plugin ***** */
218     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-workaround-bugs" );
219     p_vdec->p_context->workaround_bugs  = __MAX( __MIN( i_tmp, 99 ), 0 );
220
221     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-error-resilience" );
222     p_vdec->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
223
224     if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
225     {
226         p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
227     }
228
229     p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
230
231     p_vdec->b_direct_rendering = 0;
232
233     /* CODEC_FLAG_TRUNCATED */
234
235     /* FIXME search real LIBAVCODEC_BUILD */
236 #if LIBAVCODEC_BUILD >= 4662
237     i_truncated = config_GetInt( p_vdec->p_fifo, "ffmpeg-truncated" );
238     if( i_truncated == 1 ||
239         ( i_truncated == -1 && ( p_vdec->p_context->width == 0 || p_vdec->p_context->height == 0 ) ) )
240     {
241         p_vdec->p_context->flags |= CODEC_FLAG_TRUNCATED;
242     }
243 #endif
244     /* ***** Open the codec ***** */
245     if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
246     {
247         msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
248                                  p_vdec->psz_namecodec );
249         return( VLC_EGENERIC );
250     }
251     else
252     {
253         msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
254                                  p_vdec->psz_namecodec );
255     }
256
257     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) &&
258         p_vdec->p_codec->capabilities & CODEC_CAP_DR1 &&
259         ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
260     {
261         /* FIXME: some codecs set pix_fmt only after a frame
262          * has been decoded. */
263
264         msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
265         p_vdec->b_direct_rendering = 1;
266         p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE;
267         p_vdec->p_context->get_buffer     = ffmpeg_GetFrameBuf;
268         p_vdec->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
269         p_vdec->p_context->opaque = p_vdec;
270
271     }
272
273     /* ***** init this codec with special data ***** */
274     if( p_vdec->p_format &&
275             p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
276     {
277         int b_gotpicture;
278         int i_size = p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
279
280         if( p_vdec->i_codec_id == CODEC_ID_MPEG4 )
281         {
282             avcodec_decode_video( p_vdec->p_context, p_vdec->p_ff_pic,
283                                   &b_gotpicture,
284                                   (void *)&p_vdec->p_format[1],
285                                   i_size );
286         }
287         else
288         {
289             p_vdec->p_context->extradata_size = i_size;
290             p_vdec->p_context->extradata      = malloc( i_size );
291             memcpy( p_vdec->p_context->extradata,
292                     &p_vdec->p_format[1],
293                     i_size );
294         }
295     }
296
297     /* ***** Load post processing ***** */
298 #ifdef LIBAVCODEC_PP
299     p_vdec->pp_context = NULL;
300     p_vdec->pp_mode    = NULL;
301
302     /* for now we cannot do postproc and dr */
303     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 && !p_vdec->b_direct_rendering )
304     {
305         int  i_quality = config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" );
306         char *psz_name = config_GetPsz( p_vdec->p_fifo, "ffmpeg-pp-name" );
307
308
309         if( !psz_name )
310         {
311             psz_name = strdup( "default" );
312         }
313         else if( *psz_name == '\0' )
314         {
315             free( psz_name );
316             psz_name = strdup( "default" );
317         }
318
319
320         p_vdec->pp_mode = pp_get_mode_by_name_and_quality( psz_name, i_quality );
321
322         if( !p_vdec->pp_mode )
323         {
324             msg_Err( p_vdec->p_fifo, "failed geting mode for postproc" );
325         }
326         else
327         {
328             msg_Info( p_vdec->p_fifo, "postproc activated" );
329         }
330         free( psz_name );
331     }
332     else
333     {
334         msg_Dbg( p_vdec->p_fifo, "no postproc" );
335     }
336
337 #else
338     /* get overridding settings */
339     p_vdec->i_pp_mode = 0;
340     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
341         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
342     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
343         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
344     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
345         p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
346     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
347         p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
348     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
349         p_vdec->i_pp_mode |= PP_DERING_Y;
350     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
351         p_vdec->i_pp_mode |= PP_DERING_C;
352
353     if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
354         ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )  )||
355         ( p_vdec->i_pp_mode != 0 ) )
356     {
357         /* check if the codec support postproc. */
358         switch( p_vdec->i_codec_id )
359         {
360             case( CODEC_ID_MSMPEG4V1 ):
361             case( CODEC_ID_MSMPEG4V2 ):
362             case( CODEC_ID_MSMPEG4V3 ):
363             case( CODEC_ID_MPEG4 ):
364             case( CODEC_ID_H263 ):
365 //            case( CODEC_ID_H263P ): I don't use it up to now
366             case( CODEC_ID_H263I ):
367                 /* Ok we can make postprocessing :)) */
368                 /* first try to get a postprocess module */
369                 p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
370                                                   sizeof( postprocessing_t ) );
371                 p_vdec->p_pp->psz_object_name = "postprocessing";
372                 p_vdec->p_pp->p_module =
373                    module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
374
375                 if( !p_vdec->p_pp->p_module )
376                 {
377                     msg_Warn( p_vdec->p_fifo,
378                               "no suitable postprocessing module" );
379                     vlc_object_destroy( p_vdec->p_pp );
380                     p_vdec->p_pp = NULL;
381                     p_vdec->i_pp_mode = 0;
382                 }
383                 else
384                 {
385                     /* get mode upon quality */
386                     p_vdec->i_pp_mode |=
387                         p_vdec->p_pp->pf_getmode(
388                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
389                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
390                                                 );
391                 }
392                 break;
393             default:
394                 p_vdec->i_pp_mode = 0;
395                 msg_Warn( p_vdec->p_fifo,
396                           "Post processing unsupported for this codec" );
397                 break;
398         }
399     }
400 #endif
401
402     return( VLC_SUCCESS );
403 }
404
405 /*****************************************************************************
406  * DecodeThread: Called to decode one frame
407  *****************************************************************************
408  * We have to get a frame stored in a pes, give it to ffmpeg decoder and send
409  * the image to the output.
410  *****************************************************************************/
411 void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
412 {
413     pes_packet_t    *p_pes;
414     int     i_frame_size;
415     int     i_used;
416     int     b_drawpicture;
417     int     b_gotpicture;
418     picture_t *p_pic;                                    /* videolan picture */
419     mtime_t   i_pts;
420
421
422     /* TODO implement it in a better way */
423     /* A good idea could be to decode all I pictures and see for the other */
424     if( ( p_vdec->b_hurry_up )&& ( p_vdec->i_frame_late > 4 ) )
425     {
426         b_drawpicture = 0;
427         if( p_vdec->i_frame_late < 8 )
428         {
429             p_vdec->p_context->hurry_up = 2;
430         }
431         else
432         {
433             /* too much late picture, won't decode
434                but break picture until a new I, and for mpeg4 ...*/
435             p_vdec->i_frame_late--; /* needed else it will never be decrease */
436             input_ExtractPES( p_vdec->p_fifo, NULL );
437             return;
438         }
439     }
440     else
441     {
442         b_drawpicture = 1;
443         p_vdec->p_context->hurry_up = 0;
444     }
445
446     if( p_vdec->i_frame_late > 0 && mdate() - p_vdec->i_frame_late_start > (mtime_t)5000000 )
447     {
448         msg_Err( p_vdec->p_fifo, "more than 5 seconds of late video -> dropping (to slow computer ?)" );
449         do
450         {
451             input_ExtractPES( p_vdec->p_fifo, &p_pes );
452             if( !p_pes )
453             {
454                 p_vdec->p_fifo->b_error = 1;
455                 return;
456             }
457             i_pts = p_pes->i_pts;
458             input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
459
460         } while( i_pts <= 0 || i_pts < mdate() );
461     }
462
463     if( !p_vdec->p_context->width || !p_vdec->p_context->height )
464     {
465         p_vdec->p_context->hurry_up = 5;
466     }
467
468     do
469     {
470         input_ExtractPES( p_vdec->p_fifo, &p_pes );
471         if( !p_pes )
472         {
473             p_vdec->p_fifo->b_error = 1;
474             return;
475         }
476 #if 0
477         if( p_vdec->i_codec_id == CODEC_ID_MPEG1VIDEO )
478         {
479             if( p_pes->i_dts )
480             {
481                 p_vdec->pts = p_pes->i_dts;
482                 p_vdec->i_frame_count = 0;
483             }
484         }
485         else
486         {
487             if( p_pes->i_pts )
488             {
489                 p_vdec->pts = p_pes->i_pts;
490                 p_vdec->i_frame_count = 0;
491             }
492         }
493 #endif
494         if( p_pes->i_pts )
495         {
496             p_vdec->pts = p_pes->i_pts;
497             p_vdec->i_frame_count = 0;
498         }
499
500         i_frame_size = p_pes->i_pes_size;
501
502         if( i_frame_size > 0 )
503         {
504             uint8_t *p_last;
505             int i_need;
506             /* XXX Don't forget that ffmpeg required a little more bytes
507              * that the real frame size */
508             i_need = i_frame_size + 16 + p_vdec->i_buffer;
509             if( p_vdec->i_buffer_size < i_need)
510             {
511                 p_last = p_vdec->p_buffer;
512                 p_vdec->p_buffer = malloc( i_need );
513                 p_vdec->i_buffer_size = i_need;
514                 if( p_vdec->i_buffer > 0 )
515                 {
516                     memcpy( p_vdec->p_buffer, p_last, p_vdec->i_buffer );
517                 }
518                 FREE( p_last );
519             }
520             i_frame_size =
521                 E_( GetPESData )( p_vdec->p_buffer + p_vdec->i_buffer,
522                                   i_frame_size ,
523                                   p_pes );
524             memset( p_vdec->p_buffer + p_vdec->i_buffer + i_frame_size,
525                     0,
526                     16 );
527         }
528         input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
529     } while( i_frame_size <= 0 );
530
531     i_frame_size += p_vdec->i_buffer;
532
533 usenextdata:
534     i_used = avcodec_decode_video( p_vdec->p_context,
535                                    p_vdec->p_ff_pic,
536                                    &b_gotpicture,
537                                    p_vdec->p_buffer,
538                                    i_frame_size );
539
540 #if 0
541     msg_Dbg( p_vdec->p_fifo,
542              "used:%d framesize:%d (%s picture)",
543              i_used, i_frame_size, b_gotpicture ? "got":"no got" );
544 #endif
545     if( i_used < 0 )
546     {
547         msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
548                                   i_frame_size );
549         p_vdec->i_frame_error++;
550         p_vdec->i_buffer = 0;
551         return;
552     }
553     else if( i_used < i_frame_size )
554     {
555         memmove( p_vdec->p_buffer,
556                  p_vdec->p_buffer + i_used,
557                  p_vdec->i_buffer_size - i_used );
558
559         p_vdec->i_buffer = i_frame_size - i_used;
560     }
561     else
562     {
563         p_vdec->i_buffer = 0;
564     }
565
566     if( b_gotpicture )
567     {
568         p_vdec->i_frame_count++;
569     }
570
571     /* consumed bytes */
572     i_frame_size -= i_used;
573
574    /* Update frame late count*/
575     if( p_vdec->pts <= mdate() )
576     {
577         p_vdec->i_frame_late++;
578         if( p_vdec->i_frame_late == 1 )
579         {
580             p_vdec->i_frame_late_start = mdate();
581         }
582     }
583     else
584     {
585         p_vdec->i_frame_late = 0;
586     }
587
588     if( !b_gotpicture || p_vdec->p_ff_pic->linesize[0] == 0 || !b_drawpicture )
589     {
590         return;
591     }
592
593     if( !p_vdec->b_direct_rendering )
594     {
595         p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
596         if( !p_vdec->p_vout )
597         {
598             msg_Err( p_vdec->p_fifo, "cannot create vout" );
599             p_vdec->p_fifo->b_error = 1; /* abort */
600             return;
601         }
602
603         /* Get a new picture */
604         while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
605         {
606             if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
607             {
608                 return;
609             }
610             msleep( VOUT_OUTMEM_SLEEP );
611         }
612
613         /* fill p_picture_t from AVVideoFrame and do chroma conversion
614          * if needed */
615         ffmpeg_CopyPicture( p_pic, p_vdec->p_ff_pic, p_vdec );
616
617 #ifndef LIBAVCODEC_PP
618         /* Do post-processing if requested (with old code)*/
619         /* XXX: no dr */
620         if( ( p_vdec->i_pp_mode )&&
621             ( ( p_vdec->p_vout->render.i_chroma ==
622                 VLC_FOURCC( 'I','4','2','0' ) )||
623               ( p_vdec->p_vout->render.i_chroma ==
624                 VLC_FOURCC( 'Y','V','1','2' ) ) ) )
625         {
626             p_vdec->p_pp->pf_postprocess( p_pic,
627                                           p_vdec->p_ff_pic->qscale_table,
628                                           p_vdec->p_ff_pic->qstride,
629                                           p_vdec->i_pp_mode );
630         }
631 #endif
632
633     }
634     else
635     {
636         p_pic = (picture_t *)p_vdec->p_ff_pic->opaque;
637     }
638
639     /* fix date calculation */
640     if( p_vdec->pts > 0 )
641     {
642         i_pts = p_vdec->pts;
643
644         if( p_vdec->p_context->frame_rate > 0 )
645         {
646 #if LIBAVCODEC_BUILD >= 4662
647            i_pts += (uint64_t)1000000 *
648                     ( p_vdec->i_frame_count - 1) /
649                     DEFAULT_FRAME_RATE_BASE /
650                     p_vdec->p_context->frame_rate;
651 #else
652            i_pts += (uint64_t)1000000 *
653                     ( p_vdec->i_frame_count - 1) /
654                     FRAME_RATE_BASE /
655                     p_vdec->p_context->frame_rate;
656 #endif
657         }
658     }
659     else
660     {
661         i_pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
662     }
663
664     vout_DatePicture( p_vdec->p_vout,
665                       p_pic,
666                       i_pts );
667
668     /* Send decoded frame to vout */
669     vout_DisplayPicture( p_vdec->p_vout, p_pic );
670
671     if( i_frame_size > 0 )
672     {
673         goto usenextdata; /* try to use all data */
674     }
675 }
676
677 /*****************************************************************************
678  * EndThread: thread destruction
679  *****************************************************************************
680  * This function is called when the thread ends after a sucessful
681  * initialization.
682  *****************************************************************************/
683 void E_( EndThread_Video )( vdec_thread_t *p_vdec )
684 {
685
686 #ifdef LIBAVCODEC_PP
687     if( p_vdec->pp_mode )
688     {
689         pp_free_mode( p_vdec->pp_mode );
690         if( p_vdec->pp_context )
691         {
692             pp_free_context( p_vdec->pp_context );
693         }
694     }
695 #else
696     if( p_vdec->p_pp )
697     {
698         /* release postprocessing module */
699         module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
700         vlc_object_destroy( p_vdec->p_pp );
701         p_vdec->p_pp = NULL;
702     }
703 #endif
704
705     if( p_vdec->p_ff_pic )
706     {
707         free( p_vdec->p_ff_pic );
708     }
709
710     /* We are about to die. Reattach video output to p_vlc. */
711     vout_Request( p_vdec->p_fifo, p_vdec->p_vout, 0, 0, 0, 0 );
712 }
713
714 /*****************************************************************************
715  * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
716  *                     picture_t structure (when not in direct rendering mode).
717  *****************************************************************************/
718 static void ffmpeg_CopyPicture( picture_t    *p_pic,
719                                 AVFrame *p_ff_pic,
720                                 vdec_thread_t *p_vdec )
721 {
722     int i_plane;
723     int i_size;
724     int i_line;
725
726     uint8_t *p_dst;
727     uint8_t *p_src;
728     int i_src_stride;
729     int i_dst_stride;
730
731     if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
732     {
733 #ifdef LIBAVCODEC_PP
734         if( p_vdec->pp_mode && p_vdec->pp_context )
735         {
736             uint8_t *src[3], *dst[3];
737             int     i_src_stride[3], i_dst_stride[3];
738
739             for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
740             {
741                 src[i_plane] = p_ff_pic->data[i_plane];
742                 dst[i_plane] = p_pic->p[i_plane].p_pixels;
743
744                 i_src_stride[i_plane] = p_ff_pic->linesize[i_plane];
745                 i_dst_stride[i_plane] = p_pic->p[i_plane].i_pitch;
746             }
747             pp_postprocess( src, i_src_stride,
748                             dst, i_dst_stride,
749                             p_vdec->p_context->width, p_vdec->p_context->height,
750                             p_ff_pic->qscale_table, p_ff_pic->qstride,
751                             p_vdec->pp_mode, p_vdec->pp_context,
752                             p_ff_pic->pict_type );
753         }
754         else
755         {
756 #endif
757             for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
758             {
759                 p_src  = p_ff_pic->data[i_plane];
760                 p_dst = p_pic->p[i_plane].p_pixels;
761                 i_src_stride = p_ff_pic->linesize[i_plane];
762                 i_dst_stride = p_pic->p[i_plane].i_pitch;
763
764                 i_size = __MIN( i_src_stride, i_dst_stride );
765                 for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
766                 {
767                     p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
768                     p_src += i_src_stride;
769                     p_dst += i_dst_stride;
770                 }
771             }
772 #ifdef LIBAVCODEC_PP
773         }
774 #endif
775     }
776     else
777     {
778         /* we need to convert to I420 */
779         switch( p_vdec->p_context->pix_fmt )
780         {
781             AVPicture dest_pic;
782             int i;
783
784             case( PIX_FMT_YUV410P ):
785             case( PIX_FMT_YUV411P ):
786                 for( i = 0; i < p_pic->i_planes; i++ )
787                 {
788                     dest_pic.data[i] = p_pic->p[i].p_pixels;
789                     dest_pic.linesize[i] = p_pic->p[i].i_pitch;
790                 }
791                 img_convert( &dest_pic, PIX_FMT_YUV420P,
792                              (AVPicture *)p_ff_pic,
793                              p_vdec->p_context->pix_fmt,
794                              p_vdec->p_context->width,
795                              p_vdec->p_context->height );
796                 break;
797             default:
798                 msg_Err( p_vdec->p_fifo, "don't know how to convert chroma %i",
799                          p_vdec->p_context->pix_fmt );
800                 p_vdec->p_fifo->b_error = 1;
801                 break;
802         }
803     }
804 }
805
806 /*****************************************************************************
807  * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
808  *                     (used for direct rendering)
809  *****************************************************************************/
810 static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
811                                AVFrame *p_ff_pic )
812 {
813     vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
814     picture_t *p_pic;
815
816     /* Check and (re)create if needed our vout */
817     p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
818     if( !p_vdec->p_vout )
819     {
820         msg_Err( p_vdec->p_fifo, "cannot create vout" );
821         p_vdec->p_fifo->b_error = 1; /* abort */
822         return -1;
823     }
824     p_vdec->p_vout->render.b_allow_modify_pics = 0;
825
826     /* Get a new picture */
827     while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
828     {
829         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
830         {
831             return -1;
832         }
833         msleep( VOUT_OUTMEM_SLEEP );
834     }
835     p_vdec->p_context->draw_horiz_band= NULL;
836
837     p_ff_pic->opaque = (void*)p_pic;
838     p_ff_pic->type = FF_BUFFER_TYPE_USER;
839     p_ff_pic->data[0] = p_pic->p[0].p_pixels;
840     p_ff_pic->data[1] = p_pic->p[1].p_pixels;
841     p_ff_pic->data[2] = p_pic->p[2].p_pixels;
842     p_ff_pic->data[3] = NULL; /* alpha channel but I'm not sure */
843
844     p_ff_pic->linesize[0] = p_pic->p[0].i_pitch;
845     p_ff_pic->linesize[1] = p_pic->p[1].i_pitch;
846     p_ff_pic->linesize[2] = p_pic->p[2].i_pitch;
847     p_ff_pic->linesize[3] = 0;
848
849     if( p_ff_pic->reference != 0 )
850     {
851         vout_LinkPicture( p_vdec->p_vout, p_pic );
852     }
853     /* FIXME what is that, should give good value */
854     p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
855
856     return( 0 );
857 }
858
859 static void  ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
860                                      AVFrame *p_ff_pic )
861 {
862     vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
863     picture_t *p_pic;
864
865     //msg_Dbg( p_vdec->p_fifo, "ffmpeg_ReleaseFrameBuf" );
866     p_pic = (picture_t*)p_ff_pic->opaque;
867
868     p_ff_pic->data[0] = NULL;
869     p_ff_pic->data[1] = NULL;
870     p_ff_pic->data[2] = NULL;
871     p_ff_pic->data[3] = NULL;
872
873     vout_UnlinkPicture( p_vdec->p_vout, p_pic );
874 }
875