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