]> git.sesse.net Git - vlc/blob - modules/codec/ffmpeg/video.c
* configure.ac.in, modules/codec/ffmpeg/*, modules/encoder/ffmpeg/*, modules/stream_o...
[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.21 2003/04/20 11:57:13 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 /* 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     p_vdec->p_ff_pic = avcodec_alloc_frame();
201
202     if( ( p_vdec->p_format = (BITMAPINFOHEADER *)p_vdec->p_fifo->p_bitmapinfoheader) != NULL )
203     {
204         /* ***** Fill p_context with init values ***** */
205         p_vdec->p_context->width  = p_vdec->p_format->biWidth;
206         p_vdec->p_context->height = p_vdec->p_format->biHeight;
207     }
208     else
209     {
210         msg_Warn( p_vdec->p_fifo, "display informations missing" );
211         p_vdec->p_format = NULL;
212     }
213
214
215     /*  ***** Get configuration of ffmpeg plugin ***** */
216     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-workaround-bugs" );
217     p_vdec->p_context->workaround_bugs  = __MAX( __MIN( i_tmp, 99 ), 0 );
218
219     i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-error-resilience" );
220     p_vdec->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
221
222     if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
223     {
224         p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
225     }
226
227     p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
228
229     p_vdec->b_direct_rendering = 0;
230
231     /* CODEC_FLAG_TRUNCATED */
232
233     /* FIXME search real LIBAVCODEC_BUILD */
234 #if LIBAVCODEC_BUILD >= 4662
235     if( p_vdec->p_codec->capabilities & CODEC_CAP_TRUNCATED )
236     {
237         p_vdec->p_context->flags |= CODEC_FLAG_TRUNCATED;
238     }
239 #endif
240     /* ***** Open the codec ***** */
241     if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
242     {
243         msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
244                                  p_vdec->psz_namecodec );
245         return( VLC_EGENERIC );
246     }
247     else
248     {
249         msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
250                                  p_vdec->psz_namecodec );
251     }
252
253     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) &&
254         p_vdec->p_codec->capabilities & CODEC_CAP_DR1 &&
255         ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
256     {
257         /* FIXME: some codecs set pix_fmt only after a frame
258          * has been decoded. */
259
260         msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
261         p_vdec->b_direct_rendering = 1;
262         p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE;
263         p_vdec->p_context->get_buffer     = ffmpeg_GetFrameBuf;
264         p_vdec->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
265         p_vdec->p_context->opaque = p_vdec;
266
267     }
268
269     /* ***** init this codec with special data ***** */
270     if( p_vdec->p_format &&
271             p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
272     {
273         int b_gotpicture;
274         int i_size = p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
275
276         if( p_vdec->i_codec_id == CODEC_ID_MPEG4 )
277         {
278             avcodec_decode_video( p_vdec->p_context, p_vdec->p_ff_pic,
279                                   &b_gotpicture,
280                                   (void *)&p_vdec->p_format[1],
281                                   i_size );
282         }
283         else
284         {
285             p_vdec->p_context->extradata_size = i_size;
286             p_vdec->p_context->extradata      = malloc( i_size );
287             memcpy( p_vdec->p_context->extradata,
288                     &p_vdec->p_format[1],
289                     i_size );
290         }
291     }
292
293     /* ***** Load post processing ***** */
294 #ifdef LIBAVCODEC_PP
295     p_vdec->pp_context = NULL;
296     p_vdec->pp_mode    = NULL;
297
298     /* for now we cannot do postproc and dr */
299     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 && !p_vdec->b_direct_rendering )
300     {
301         int  i_quality = config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" );
302         char *psz_name = config_GetPsz( p_vdec->p_fifo, "ffmpeg-pp-name" );
303
304
305         if( !psz_name )
306         {
307             psz_name = strdup( "default" );
308         }
309         else if( *psz_name == '\0' )
310         {
311             free( psz_name );
312             psz_name = strdup( "default" );
313         }
314
315
316         p_vdec->pp_mode = pp_get_mode_by_name_and_quality( psz_name, i_quality );
317
318         if( !p_vdec->pp_mode )
319         {
320             msg_Err( p_vdec->p_fifo, "failed geting mode for postproc" );
321         }
322         else
323         {
324             msg_Info( p_vdec->p_fifo, "postproc activated" );
325         }
326         free( psz_name );
327     }
328     else
329     {
330         msg_Dbg( p_vdec->p_fifo, "no postproc" );
331     }
332
333 #else
334     /* get overridding settings */
335     p_vdec->i_pp_mode = 0;
336     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
337         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
338     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
339         p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
340     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
341         p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
342     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
343         p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
344     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
345         p_vdec->i_pp_mode |= PP_DERING_Y;
346     if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
347         p_vdec->i_pp_mode |= PP_DERING_C;
348
349     if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
350         ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )  )||
351         ( p_vdec->i_pp_mode != 0 ) )
352     {
353         /* check if the codec support postproc. */
354         switch( p_vdec->i_codec_id )
355         {
356             case( CODEC_ID_MSMPEG4V1 ):
357             case( CODEC_ID_MSMPEG4V2 ):
358             case( CODEC_ID_MSMPEG4V3 ):
359             case( CODEC_ID_MPEG4 ):
360             case( CODEC_ID_H263 ):
361 //            case( CODEC_ID_H263P ): I don't use it up to now
362             case( CODEC_ID_H263I ):
363                 /* Ok we can make postprocessing :)) */
364                 /* first try to get a postprocess module */
365                 p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
366                                                   sizeof( postprocessing_t ) );
367                 p_vdec->p_pp->psz_object_name = "postprocessing";
368                 p_vdec->p_pp->p_module =
369                    module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
370
371                 if( !p_vdec->p_pp->p_module )
372                 {
373                     msg_Warn( p_vdec->p_fifo,
374                               "no suitable postprocessing module" );
375                     vlc_object_destroy( p_vdec->p_pp );
376                     p_vdec->p_pp = NULL;
377                     p_vdec->i_pp_mode = 0;
378                 }
379                 else
380                 {
381                     /* get mode upon quality */
382                     p_vdec->i_pp_mode |=
383                         p_vdec->p_pp->pf_getmode(
384                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
385                               config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
386                                                 );
387                 }
388                 break;
389             default:
390                 p_vdec->i_pp_mode = 0;
391                 msg_Warn( p_vdec->p_fifo,
392                           "Post processing unsupported for this codec" );
393                 break;
394         }
395     }
396 #endif
397
398     return( VLC_SUCCESS );
399 }
400
401 /*****************************************************************************
402  * DecodeThread: Called to decode one frame
403  *****************************************************************************
404  * We have to get a frame stored in a pes, give it to ffmpeg decoder and send
405  * the image to the output.
406  *****************************************************************************/
407 void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
408 {
409     pes_packet_t    *p_pes;
410     int     i_frame_size;
411     int     i_used;
412     int     b_drawpicture;
413     int     b_gotpicture;
414     picture_t *p_pic;                                    /* videolan picture */
415     mtime_t   i_pts;
416
417
418     /* TODO implement it in a better way */
419     /* A good idea could be to decode all I pictures and see for the other */
420     if( ( p_vdec->b_hurry_up )&& ( p_vdec->i_frame_late > 4 ) )
421     {
422         b_drawpicture = 0;
423         if( p_vdec->i_frame_late < 8 )
424         {
425             p_vdec->p_context->hurry_up = 2;
426         }
427         else
428         {
429             /* too much late picture, won't decode
430                but break picture until a new I, and for mpeg4 ...*/
431             p_vdec->i_frame_late--; /* needed else it will never be decrease */
432             input_ExtractPES( p_vdec->p_fifo, NULL );
433             return;
434         }
435     }
436     else
437     {
438         b_drawpicture = 1;
439         p_vdec->p_context->hurry_up = 0;
440     }
441
442     if( !p_vdec->p_context->width || !p_vdec->p_context->height )
443     {
444         p_vdec->p_context->hurry_up = 5; 
445     }
446
447     do
448     {
449         input_ExtractPES( p_vdec->p_fifo, &p_pes );
450         if( !p_pes )
451         {
452             p_vdec->p_fifo->b_error = 1;
453             return;
454         }
455 #if 0
456         if( p_vdec->i_codec_id == CODEC_ID_MPEG1VIDEO )
457         {
458             if( p_pes->i_dts )
459             {
460                 p_vdec->pts = p_pes->i_dts;
461                 p_vdec->i_frame_count = 0;
462             }
463         }
464         else
465         {
466             if( p_pes->i_pts )
467             {
468                 p_vdec->pts = p_pes->i_pts;
469                 p_vdec->i_frame_count = 0;
470             }
471         }
472 #endif
473         if( p_pes->i_pts )
474         {
475             p_vdec->pts = p_pes->i_pts;
476             p_vdec->i_frame_count = 0;
477         }
478
479         i_frame_size = p_pes->i_pes_size;
480
481         if( i_frame_size > 0 )
482         {
483             uint8_t *p_last;
484             int i_need;
485             /* XXX Don't forget that ffmpeg required a little more bytes
486              * that the real frame size */
487             i_need = i_frame_size + 16 + p_vdec->i_buffer;
488             if( p_vdec->i_buffer_size < i_need)
489             {
490                 p_last = p_vdec->p_buffer;
491                 p_vdec->p_buffer = malloc( i_need );
492                 p_vdec->i_buffer_size = i_need;
493                 if( p_vdec->i_buffer > 0 )
494                 {
495                     memcpy( p_vdec->p_buffer, p_last, p_vdec->i_buffer );
496                 }
497                 FREE( p_last );
498             }
499             i_frame_size =
500                 E_( GetPESData )( p_vdec->p_buffer + p_vdec->i_buffer,
501                                   i_frame_size ,
502                                   p_pes );
503             memset( p_vdec->p_buffer + p_vdec->i_buffer + i_frame_size,
504                     0,
505                     16 );
506         }
507         input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
508     } while( i_frame_size <= 0 );
509
510     i_frame_size += p_vdec->i_buffer;
511
512 usenextdata:
513     i_used = avcodec_decode_video( p_vdec->p_context,
514                                    p_vdec->p_ff_pic,
515                                    &b_gotpicture,
516                                    p_vdec->p_buffer,
517                                    i_frame_size );
518
519 #if 0
520     msg_Dbg( p_vdec->p_fifo,
521              "used:%d framesize:%d (%s picture)",
522              i_used, i_frame_size, b_gotpicture ? "got":"no got" );
523 #endif
524     if( i_used < 0 )
525     {
526         msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
527                                   i_frame_size );
528         p_vdec->i_frame_error++;
529         p_vdec->i_buffer = 0;
530         return;
531     }
532     else if( i_used < i_frame_size )
533     {
534         memmove( p_vdec->p_buffer,
535                  p_vdec->p_buffer + i_used,
536                  p_vdec->i_buffer_size - i_used );
537
538         p_vdec->i_buffer = i_frame_size - i_used;
539     }
540     else
541     {
542         p_vdec->i_buffer = 0;
543     }
544
545     if( b_gotpicture )
546     {
547         p_vdec->i_frame_count++;
548     }
549
550     /* consumed bytes */
551     i_frame_size -= i_used;
552
553    /* Update frame late count*/
554     if( p_vdec->pts <= mdate() )
555     {
556         p_vdec->i_frame_late++;
557     }
558     else
559     {
560         p_vdec->i_frame_late = 0;
561     }
562
563     if( !b_gotpicture || p_vdec->p_ff_pic->linesize[0] == 0 || !b_drawpicture )
564     {
565         return;
566     }
567
568     if( !p_vdec->b_direct_rendering )
569     {
570         p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
571         if( !p_vdec->p_vout )
572         {
573             msg_Err( p_vdec->p_fifo, "cannot create vout" );
574             p_vdec->p_fifo->b_error = 1; /* abort */
575             return;
576         }
577
578         /* Get a new picture */
579         while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
580         {
581             if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
582             {
583                 return;
584             }
585             msleep( VOUT_OUTMEM_SLEEP );
586         }
587
588         /* fill p_picture_t from AVVideoFrame and do chroma conversion
589          * if needed */
590         ffmpeg_CopyPicture( p_pic, p_vdec->p_ff_pic, p_vdec );
591
592 #ifndef LIBAVCODEC_PP
593         /* Do post-processing if requested (with old code)*/
594         /* XXX: no dr */
595         if( ( p_vdec->i_pp_mode )&&
596             ( ( p_vdec->p_vout->render.i_chroma ==
597                 VLC_FOURCC( 'I','4','2','0' ) )||
598               ( p_vdec->p_vout->render.i_chroma ==
599                 VLC_FOURCC( 'Y','V','1','2' ) ) ) )
600         {
601             p_vdec->p_pp->pf_postprocess( p_pic,
602                                           p_vdec->p_ff_pic->qscale_table,
603                                           p_vdec->p_ff_pic->qstride,
604                                           p_vdec->i_pp_mode );
605         }
606 #endif
607
608     }
609     else
610     {
611         p_pic = (picture_t *)p_vdec->p_ff_pic->opaque;
612     }
613
614     /* fix date calculation */
615     if( p_vdec->pts > 0 )
616     {
617         i_pts = p_vdec->pts;
618
619         if( p_vdec->p_context->frame_rate > 0 )
620         {
621 #if LIBAVCODEC_BUILD >= 4662
622            i_pts += (uint64_t)1000000 *
623                     ( p_vdec->i_frame_count - 1) /
624                     DEFAULT_FRAME_RATE_BASE /
625                     p_vdec->p_context->frame_rate;
626 #else
627            i_pts += (uint64_t)1000000 *
628                     ( p_vdec->i_frame_count - 1) /
629                     FRAME_RATE_BASE /
630                     p_vdec->p_context->frame_rate;
631 #endif
632         }
633     }
634     else
635     {
636         i_pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
637     }
638
639     vout_DatePicture( p_vdec->p_vout,
640                       p_pic,
641                       i_pts );
642
643     /* Send decoded frame to vout */
644     vout_DisplayPicture( p_vdec->p_vout, p_pic );
645
646     if( i_frame_size > 0 )
647     {
648         goto usenextdata; /* try to use all data */
649     }
650 }
651
652 /*****************************************************************************
653  * EndThread: thread destruction
654  *****************************************************************************
655  * This function is called when the thread ends after a sucessful
656  * initialization.
657  *****************************************************************************/
658 void E_( EndThread_Video )( vdec_thread_t *p_vdec )
659 {
660
661 #ifdef LIBAVCODEC_PP
662     if( p_vdec->pp_mode )
663     {
664         pp_free_mode( p_vdec->pp_mode );
665         if( p_vdec->pp_context )
666         {
667             pp_free_context( p_vdec->pp_context );
668         }
669     }
670 #else
671     if( p_vdec->p_pp )
672     {
673         /* release postprocessing module */
674         module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
675         vlc_object_destroy( p_vdec->p_pp );
676         p_vdec->p_pp = NULL;
677     }
678 #endif
679
680     if( p_vdec->p_ff_pic )
681     {
682         free( p_vdec->p_ff_pic );
683     }
684
685     /* We are about to die. Reattach video output to p_vlc. */
686     vout_Request( p_vdec->p_fifo, p_vdec->p_vout, 0, 0, 0, 0 );
687 }
688
689 /*****************************************************************************
690  * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
691  *                     picture_t structure (when not in direct rendering mode).
692  *****************************************************************************/
693 static void ffmpeg_CopyPicture( picture_t    *p_pic,
694                                 AVFrame *p_ff_pic,
695                                 vdec_thread_t *p_vdec )
696 {
697     int i_plane;
698     int i_size;
699     int i_line;
700
701     uint8_t *p_dst;
702     uint8_t *p_src;
703     int i_src_stride;
704     int i_dst_stride;
705
706     if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
707     {
708 #ifdef LIBAVCODEC_PP
709         if( p_vdec->pp_mode && p_vdec->pp_context )
710         {
711             uint8_t *src[3], *dst[3];
712             int     i_src_stride[3], i_dst_stride[3];
713
714             for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
715             {
716                 src[i_plane] = p_ff_pic->data[i_plane];
717                 dst[i_plane] = p_pic->p[i_plane].p_pixels;
718
719                 i_src_stride[i_plane] = p_ff_pic->linesize[i_plane];
720                 i_dst_stride[i_plane] = p_pic->p[i_plane].i_pitch;
721             }
722             pp_postprocess( src, i_src_stride,
723                             dst, i_dst_stride,
724                             p_vdec->p_context->width, p_vdec->p_context->height,
725                             p_ff_pic->qscale_table, p_ff_pic->qstride,
726                             p_vdec->pp_mode, p_vdec->pp_context,
727                             p_ff_pic->pict_type );
728         }
729         else
730         {
731 #endif
732             for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
733             {
734                 p_src  = p_ff_pic->data[i_plane];
735                 p_dst = p_pic->p[i_plane].p_pixels;
736                 i_src_stride = p_ff_pic->linesize[i_plane];
737                 i_dst_stride = p_pic->p[i_plane].i_pitch;
738
739                 i_size = __MIN( i_src_stride, i_dst_stride );
740                 for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
741                 {
742                     p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
743                     p_src += i_src_stride;
744                     p_dst += i_dst_stride;
745                 }
746             }
747 #ifdef LIBAVCODEC_PP
748         }
749 #endif
750     }
751     else
752     {
753         /* we need to convert to I420 */
754         switch( p_vdec->p_context->pix_fmt )
755         {
756             AVPicture dest_pic;
757             int i;
758
759             case( PIX_FMT_YUV410P ):
760             case( PIX_FMT_YUV411P ):
761                 for( i = 0; i < p_pic->i_planes; i++ )
762                 {
763                     dest_pic.data[i] = p_pic->p[i].p_pixels;
764                     dest_pic.linesize[i] = p_pic->p[i].i_pitch;
765                 }
766                 img_convert( &dest_pic, PIX_FMT_YUV420P,
767                              (AVPicture *)p_ff_pic,
768                              p_vdec->p_context->pix_fmt,
769                              p_vdec->p_context->width,
770                              p_vdec->p_context->height );
771                 break;
772             default:
773                 msg_Err( p_vdec->p_fifo, "don't know how to convert chroma %i",
774                          p_vdec->p_context->pix_fmt );
775                 p_vdec->p_fifo->b_error = 1;
776                 break;
777         }
778     }
779 }
780
781 /*****************************************************************************
782  * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
783  *                     (used for direct rendering)
784  *****************************************************************************/
785 static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
786                                AVFrame *p_ff_pic )
787 {
788     vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
789     picture_t *p_pic;
790
791     /* Check and (re)create if needed our vout */
792     p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
793     if( !p_vdec->p_vout )
794     {
795         msg_Err( p_vdec->p_fifo, "cannot create vout" );
796         p_vdec->p_fifo->b_error = 1; /* abort */
797         return -1;
798     }
799     p_vdec->p_vout->render.b_allow_modify_pics = 0;
800
801     /* Get a new picture */
802     while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
803     {
804         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
805         {
806             return -1;
807         }
808         msleep( VOUT_OUTMEM_SLEEP );
809     }
810     p_vdec->p_context->draw_horiz_band= NULL;
811
812     p_ff_pic->opaque = (void*)p_pic;
813     p_ff_pic->type = FF_BUFFER_TYPE_USER;
814     p_ff_pic->data[0] = p_pic->p[0].p_pixels;
815     p_ff_pic->data[1] = p_pic->p[1].p_pixels;
816     p_ff_pic->data[2] = p_pic->p[2].p_pixels;
817     p_ff_pic->data[3] = NULL; /* alpha channel but I'm not sure */
818
819     p_ff_pic->linesize[0] = p_pic->p[0].i_pitch;
820     p_ff_pic->linesize[1] = p_pic->p[1].i_pitch;
821     p_ff_pic->linesize[2] = p_pic->p[2].i_pitch;
822     p_ff_pic->linesize[3] = 0;
823
824     if( p_ff_pic->reference != 0 )
825     {
826         vout_LinkPicture( p_vdec->p_vout, p_pic );
827     }
828     /* FIXME what is that, should give good value */
829     p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
830
831     return( 0 );
832 }
833
834 static void  ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
835                                      AVFrame *p_ff_pic )
836 {
837     vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
838     picture_t *p_pic;
839
840     //msg_Dbg( p_vdec->p_fifo, "ffmpeg_ReleaseFrameBuf" );
841     p_pic = (picture_t*)p_ff_pic->opaque;
842
843     p_ff_pic->data[0] = NULL;
844     p_ff_pic->data[1] = NULL;
845     p_ff_pic->data[2] = NULL;
846     p_ff_pic->data[3] = NULL;
847
848     vout_UnlinkPicture( p_vdec->p_vout, p_pic );
849 }
850