video.c 27.2 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * video.c: video decoder using ffmpeg library
 *****************************************************************************
 * Copyright (C) 1999-2001 VideoLAN
5
 * $Id: video.c,v 1.24 2003/04/27 13:03:28 fenrir Exp $
6
7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
gbazin's avatar
   
gbazin committed
8
 *          Gildas Bazin <gbazin@netcourrier.com>
9
10
11
12
13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
14
 *
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */

#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <vlc/input.h>

#include <string.h>

#ifdef HAVE_SYS_TIMES_H
#   include <sys/times.h>
#endif

gbazin's avatar
   
gbazin committed
42
43
44
45
46
47
48
/* ffmpeg header */
#ifdef HAVE_FFMPEG_AVCODEC_H
#   include <ffmpeg/avcodec.h>
#else
#   include <avcodec.h>
#endif

49
#include "ffmpeg.h"
50

51
#ifdef LIBAVCODEC_PP
gbazin's avatar
   
gbazin committed
52
53
54
55
56
#   ifdef HAVE_POSTPROC_POSTPROCESS_H
#       include <postproc/postprocess.h>
#   else
#       include <libpostproc/postprocess.h>
#   endif
57
58
59
#else
#   include "postprocessing/postprocessing.h"
#endif
60
61
62

#include "video.h"

63

gbazin's avatar
   
gbazin committed
64
/*****************************************************************************
65
 * Local prototypes
gbazin's avatar
   
gbazin committed
66
 *****************************************************************************/
67
static void ffmpeg_CopyPicture( picture_t *, AVFrame *, vdec_thread_t * );
68

69
#ifndef LIBAVCODEC_PP
gbazin's avatar
   
gbazin committed
70
static void ffmpeg_PostProcPicture( vdec_thread_t *, picture_t * );
71
#endif
72

73
74
75
76
/* direct rendering */
static int  ffmpeg_GetFrameBuf      ( struct AVCodecContext *, AVFrame *);
static void ffmpeg_ReleaseFrameBuf  ( struct AVCodecContext *, AVFrame *);

gbazin's avatar
   
gbazin committed
77
78
79
80
/*****************************************************************************
 * Local Functions
 *****************************************************************************/

81
static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
82
{
83
84
85
86
87
88
89
90
    /* FIXME FIXME some of them are wrong */
    switch( i_ff_chroma )
    {
        case PIX_FMT_YUV420P:
        case PIX_FMT_YUV422:
            return( VLC_FOURCC('I','4','2','0') );
        case PIX_FMT_RGB24:
            return( VLC_FOURCC('R','V','2','4') );
91

92
93
94
95
96
        case PIX_FMT_YUV422P:
            return( VLC_FOURCC('I','4','2','2') );
        case PIX_FMT_YUV444P:
            return( VLC_FOURCC('I','4','4','4') );
        case PIX_FMT_YUV410P:
gbazin's avatar
   
gbazin committed
97
        case PIX_FMT_YUV411P:
98
        case PIX_FMT_BGR24:
99
        default:
100
            return( 0 );
101
102
103
104
    }
}

/* Return a Vout */
105
106
static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
                                         AVCodecContext *p_context )
107
108
{
    vout_thread_t *p_vout;
109
    unsigned int   i_width = p_context->width;
gbazin's avatar
   
gbazin committed
110
    unsigned int   i_height = p_context->height;
111
112
    uint32_t       i_chroma = ffmpeg_PixFmtToChroma( p_context->pix_fmt );
    unsigned int   i_aspect;
113

114
    if( !i_width || !i_height )
115
116
117
118
119
120
121
122
    {
        return( NULL ); /* Can't create a new vout without display size */
    }

    if( !i_chroma )
    {
        /* we make conversion if possible*/
        i_chroma = VLC_FOURCC('I','4','2','0');
123
    }
124

125
126
    i_aspect = VOUT_ASPECT_FACTOR * p_context->aspect_ratio;
    if( i_aspect == 0 )
127
128
129
    {
        i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
    }
130

131
132
    /* Spawn a video output if there is none. First we look for our children,
     * then we look for any other vout that might be available. */
133
134
    p_vout = vout_Request( p_vdec->p_fifo, NULL,
                           i_width, i_height, i_chroma, i_aspect );
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#ifdef LIBAVCODEC_PP
    if( p_vdec->pp_mode && !p_vdec->pp_context )
    {
        int32_t i_cpu = p_vdec->p_fifo->p_libvlc->i_cpu;
        int i_flags = 0;

        if( i_cpu & CPU_CAPABILITY_MMX )
        {
            i_flags |= PP_CPU_CAPS_MMX;
        }
        if( i_cpu & CPU_CAPABILITY_MMXEXT )
        {
            i_flags |= PP_CPU_CAPS_MMX2;
        }
        if( i_cpu & CPU_CAPABILITY_3DNOW )
        {
            i_flags |= PP_CPU_CAPS_3DNOW;
        }

        switch( p_context->pix_fmt )
        {
            case PIX_FMT_YUV444P:
                i_flags |= PP_FORMAT_444;
                break;
            case PIX_FMT_YUV422P:
                i_flags |= PP_FORMAT_422;
                break;
            case PIX_FMT_YUV411P:
                i_flags |= PP_FORMAT_411;
                break;
            default:
                i_flags |= PP_FORMAT_420;
                break;
        }

        p_vdec->pp_context = pp_get_context( i_width, i_height, i_flags );
    }
#endif
gbazin's avatar
   
gbazin committed
173

174
    return p_vout;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
}

/*****************************************************************************
 *
 * Functions that initialize, decode and end the decoding process
 *
 * Functions exported for ffmpeg.c
 *   * E_( InitThread_Video )
 *   * E_( DecodeThread )
 *   * E_( EndThread_Video )
 *****************************************************************************/

/*****************************************************************************
 * InitThread: initialize vdec output thread
 *****************************************************************************
190
191
 * This function is called from decoder_Run and performs the second step
 * of the initialization. It returns 0 on success. Note that the thread's
192
193
194
 * flag are not modified inside this function.
 *
 * ffmpeg codec will be open, some memory allocated. But Vout is not yet
gbazin's avatar
   
gbazin committed
195
 * open (done after the first decoded frame)
196
197
198
199
 *****************************************************************************/
int E_( InitThread_Video )( vdec_thread_t *p_vdec )
{
    int i_tmp;
200
    p_vdec->p_ff_pic = avcodec_alloc_frame();
gbazin's avatar
   
gbazin committed
201

202
    if( ( p_vdec->p_format = (BITMAPINFOHEADER *)p_vdec->p_fifo->p_bitmapinfoheader) != NULL )
203
    {
204
205
206
        /* ***** Fill p_context with init values ***** */
        p_vdec->p_context->width  = p_vdec->p_format->biWidth;
        p_vdec->p_context->height = p_vdec->p_format->biHeight;
207
208
209
210
    }
    else
    {
        msg_Warn( p_vdec->p_fifo, "display informations missing" );
211
        p_vdec->p_format = NULL;
212
213
    }

214

215
216
217
218
219
220
    /*  ***** Get configuration of ffmpeg plugin ***** */
    i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-workaround-bugs" );
    p_vdec->p_context->workaround_bugs  = __MAX( __MIN( i_tmp, 99 ), 0 );

    i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-error-resilience" );
    p_vdec->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
221

222
223
224
225
    if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
    {
        p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
    }
gbazin's avatar
   
gbazin committed
226

227
228
    p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");

gbazin's avatar
   
gbazin committed
229
    p_vdec->b_direct_rendering = 0;
230

231
232
233
234
235
236
237
238
239
    /* CODEC_FLAG_TRUNCATED */

    /* FIXME search real LIBAVCODEC_BUILD */
#if LIBAVCODEC_BUILD >= 4662
    if( p_vdec->p_codec->capabilities & CODEC_CAP_TRUNCATED )
    {
        p_vdec->p_context->flags |= CODEC_FLAG_TRUNCATED;
    }
#endif
gbazin's avatar
   
gbazin committed
240
241
    /* ***** Open the codec ***** */
    if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
242
243
244
    {
        msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
                                 p_vdec->psz_namecodec );
245
        return( VLC_EGENERIC );
246
247
248
249
250
251
252
    }
    else
    {
        msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
                                 p_vdec->psz_namecodec );
    }

gbazin's avatar
   
gbazin committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) &&
        p_vdec->p_codec->capabilities & CODEC_CAP_DR1 &&
        ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
    {
        /* FIXME: some codecs set pix_fmt only after a frame
         * has been decoded. */

        msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
        p_vdec->b_direct_rendering = 1;
        p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE;
        p_vdec->p_context->get_buffer     = ffmpeg_GetFrameBuf;
        p_vdec->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
        p_vdec->p_context->opaque = p_vdec;

    }

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
279
280
281
282
283
284
285
286
287
288
289
            avcodec_decode_video( p_vdec->p_context, p_vdec->p_ff_pic,
                                  &b_gotpicture,
                                  (void *)&p_vdec->p_format[1],
                                  i_size );
        }
        else
        {
            p_vdec->p_context->extradata_size = i_size;
            p_vdec->p_context->extradata      = malloc( i_size );
            memcpy( p_vdec->p_context->extradata,
                    &p_vdec->p_format[1],
                    i_size );
290
291
        }
    }
292

293
    /* ***** Load post processing ***** */
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#ifdef LIBAVCODEC_PP
    p_vdec->pp_context = NULL;
    p_vdec->pp_mode    = NULL;

    /* for now we cannot do postproc and dr */
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 && !p_vdec->b_direct_rendering )
    {
        int  i_quality = config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" );
        char *psz_name = config_GetPsz( p_vdec->p_fifo, "ffmpeg-pp-name" );


        if( !psz_name )
        {
            psz_name = strdup( "default" );
        }
        else if( *psz_name == '\0' )
        {
            free( psz_name );
            psz_name = strdup( "default" );
        }
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

        p_vdec->pp_mode = pp_get_mode_by_name_and_quality( psz_name, i_quality );

        if( !p_vdec->pp_mode )
        {
            msg_Err( p_vdec->p_fifo, "failed geting mode for postproc" );
        }
        else
        {
            msg_Info( p_vdec->p_fifo, "postproc activated" );
        }
        free( psz_name );
    }
    else
    {
        msg_Dbg( p_vdec->p_fifo, "no postproc" );
    }

#else
334
335
336
337
338
339
340
341
342
343
344
345
346
347
    /* get overridding settings */
    p_vdec->i_pp_mode = 0;
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
        p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
        p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
        p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
        p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
        p_vdec->i_pp_mode |= PP_DERING_Y;
    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
        p_vdec->i_pp_mode |= PP_DERING_C;
gbazin's avatar
   
gbazin committed
348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
    if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
        ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )  )||
        ( p_vdec->i_pp_mode != 0 ) )
    {
        /* check if the codec support postproc. */
        switch( p_vdec->i_codec_id )
        {
            case( CODEC_ID_MSMPEG4V1 ):
            case( CODEC_ID_MSMPEG4V2 ):
            case( CODEC_ID_MSMPEG4V3 ):
            case( CODEC_ID_MPEG4 ):
            case( CODEC_ID_H263 ):
//            case( CODEC_ID_H263P ): I don't use it up to now
            case( CODEC_ID_H263I ):
                /* Ok we can make postprocessing :)) */
gbazin's avatar
   
gbazin committed
364
                /* first try to get a postprocess module */
365
366
367
                p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
                                                  sizeof( postprocessing_t ) );
                p_vdec->p_pp->psz_object_name = "postprocessing";
368
                p_vdec->p_pp->p_module =
369
370
371
372
                   module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );

                if( !p_vdec->p_pp->p_module )
                {
373
                    msg_Warn( p_vdec->p_fifo,
374
375
376
377
378
379
380
381
                              "no suitable postprocessing module" );
                    vlc_object_destroy( p_vdec->p_pp );
                    p_vdec->p_pp = NULL;
                    p_vdec->i_pp_mode = 0;
                }
                else
                {
                    /* get mode upon quality */
382
383
                    p_vdec->i_pp_mode |=
                        p_vdec->p_pp->pf_getmode(
384
385
386
387
388
389
390
                              config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
                              config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
                                                );
                }
                break;
            default:
                p_vdec->i_pp_mode = 0;
391
                msg_Warn( p_vdec->p_fifo,
392
393
394
395
                          "Post processing unsupported for this codec" );
                break;
        }
    }
396
#endif
397

398
    return( VLC_SUCCESS );
399
400
401
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
402
 * DecodeThread: Called to decode one frame
gbazin's avatar
   
gbazin committed
403
404
405
 *****************************************************************************
 * We have to get a frame stored in a pes, give it to ffmpeg decoder and send
 * the image to the output.
406
407
408
409
410
 *****************************************************************************/
void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
{
    pes_packet_t    *p_pes;
    int     i_frame_size;
411
    int     i_used;
412
413
    int     b_drawpicture;
    int     b_gotpicture;
gbazin's avatar
   
gbazin committed
414
    picture_t *p_pic;                                    /* videolan picture */
415
    mtime_t   i_pts;
416

417

418
419
    /* TODO implement it in a better way */
    /* A good idea could be to decode all I pictures and see for the other */
gbazin's avatar
   
gbazin committed
420
    if( ( p_vdec->b_hurry_up )&& ( p_vdec->i_frame_late > 4 ) )
421
422
423
424
425
426
427
428
    {
        b_drawpicture = 0;
        if( p_vdec->i_frame_late < 8 )
        {
            p_vdec->p_context->hurry_up = 2;
        }
        else
        {
429
            /* too much late picture, won't decode
430
431
432
433
434
435
436
437
438
439
440
441
               but break picture until a new I, and for mpeg4 ...*/
            p_vdec->i_frame_late--; /* needed else it will never be decrease */
            input_ExtractPES( p_vdec->p_fifo, NULL );
            return;
        }
    }
    else
    {
        b_drawpicture = 1;
        p_vdec->p_context->hurry_up = 0;
    }

442
443
    if( p_vdec->i_frame_late > 0 && mdate() - p_vdec->i_frame_late_start > (mtime_t)5000000 )
    {
Laurent Aimar's avatar
Laurent Aimar committed
444
        msg_Err( p_vdec->p_fifo, "more than 5 seconds of late video -> dropping (to slow computer ?)" );
445
446
447
448
449
450
451
452
453
454
455
        do
        {
            input_ExtractPES( p_vdec->p_fifo, &p_pes );
            if( !p_pes )
            {
                p_vdec->p_fifo->b_error = 1;
                return;
            }
            i_pts = p_pes->i_pts;
            input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );

456
        } while( i_pts <= 0 || i_pts < mdate() );
457
458
    }

459
460
    if( !p_vdec->p_context->width || !p_vdec->p_context->height )
    {
461
        p_vdec->p_context->hurry_up = 5;
462
463
    }

464
465
466
467
468
469
470
471
    do
    {
        input_ExtractPES( p_vdec->p_fifo, &p_pes );
        if( !p_pes )
        {
            p_vdec->p_fifo->b_error = 1;
            return;
        }
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
#if 0
        if( p_vdec->i_codec_id == CODEC_ID_MPEG1VIDEO )
        {
            if( p_pes->i_dts )
            {
                p_vdec->pts = p_pes->i_dts;
                p_vdec->i_frame_count = 0;
            }
        }
        else
        {
            if( p_pes->i_pts )
            {
                p_vdec->pts = p_pes->i_pts;
                p_vdec->i_frame_count = 0;
            }
        }
489
#endif
490
491
492
493
494
495
        if( p_pes->i_pts )
        {
            p_vdec->pts = p_pes->i_pts;
            p_vdec->i_frame_count = 0;
        }

496
497
498
499
        i_frame_size = p_pes->i_pes_size;

        if( i_frame_size > 0 )
        {
500
501
            uint8_t *p_last;
            int i_need;
502
            /* XXX Don't forget that ffmpeg required a little more bytes
503
             * that the real frame size */
504
            i_need = i_frame_size + 16 + p_vdec->i_buffer;
505
            if( p_vdec->i_buffer_size < i_need)
506
            {
507
508
509
510
511
512
513
514
                p_last = p_vdec->p_buffer;
                p_vdec->p_buffer = malloc( i_need );
                p_vdec->i_buffer_size = i_need;
                if( p_vdec->i_buffer > 0 )
                {
                    memcpy( p_vdec->p_buffer, p_last, p_vdec->i_buffer );
                }
                FREE( p_last );
515
            }
516
517
            i_frame_size =
                E_( GetPESData )( p_vdec->p_buffer + p_vdec->i_buffer,
518
519
520
521
522
                                  i_frame_size ,
                                  p_pes );
            memset( p_vdec->p_buffer + p_vdec->i_buffer + i_frame_size,
                    0,
                    16 );
523
        }
524
525
526
        input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
    } while( i_frame_size <= 0 );

527
    i_frame_size += p_vdec->i_buffer;
528

529
530
usenextdata:
    i_used = avcodec_decode_video( p_vdec->p_context,
531
                                   p_vdec->p_ff_pic,
532
533
534
                                   &b_gotpicture,
                                   p_vdec->p_buffer,
                                   i_frame_size );
535

536
#if 0
537
538
    msg_Dbg( p_vdec->p_fifo,
             "used:%d framesize:%d (%s picture)",
539
540
541
             i_used, i_frame_size, b_gotpicture ? "got":"no got" );
#endif
    if( i_used < 0 )
542
543
544
545
    {
        msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
                                  i_frame_size );
        p_vdec->i_frame_error++;
546
        p_vdec->i_buffer = 0;
547
548
        return;
    }
549
550
551
552
553
    else if( i_used < i_frame_size )
    {
        memmove( p_vdec->p_buffer,
                 p_vdec->p_buffer + i_used,
                 p_vdec->i_buffer_size - i_used );
554

555
556
557
558
559
560
        p_vdec->i_buffer = i_frame_size - i_used;
    }
    else
    {
        p_vdec->i_buffer = 0;
    }
561

562
563
564
565
    if( b_gotpicture )
    {
        p_vdec->i_frame_count++;
    }
566

567
568
569
570
    /* consumed bytes */
    i_frame_size -= i_used;

   /* Update frame late count*/
571
    if( p_vdec->pts <= mdate() )
572
573
    {
        p_vdec->i_frame_late++;
574
575
576
577
        if( p_vdec->i_frame_late == 1 )
        {
            p_vdec->i_frame_late_start = mdate();
        }
578
579
580
581
582
583
    }
    else
    {
        p_vdec->i_frame_late = 0;
    }

584
    if( !b_gotpicture || p_vdec->p_ff_pic->linesize[0] == 0 || !b_drawpicture )
585
586
587
    {
        return;
    }
gbazin's avatar
   
gbazin committed
588
589
590

    if( !p_vdec->b_direct_rendering )
    {
591
592
        p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
        if( !p_vdec->p_vout )
593
        {
594
595
596
            msg_Err( p_vdec->p_fifo, "cannot create vout" );
            p_vdec->p_fifo->b_error = 1; /* abort */
            return;
597
598
        }

gbazin's avatar
   
gbazin committed
599
600
        /* Get a new picture */
        while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
601
        {
gbazin's avatar
   
gbazin committed
602
603
604
605
606
            if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
            {
                return;
            }
            msleep( VOUT_OUTMEM_SLEEP );
607
        }
gbazin's avatar
   
gbazin committed
608

gbazin's avatar
   
gbazin committed
609
610
        /* fill p_picture_t from AVVideoFrame and do chroma conversion
         * if needed */
611
        ffmpeg_CopyPicture( p_pic, p_vdec->p_ff_pic, p_vdec );
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628

#ifndef LIBAVCODEC_PP
        /* Do post-processing if requested (with old code)*/
        /* XXX: no dr */
        if( ( p_vdec->i_pp_mode )&&
            ( ( p_vdec->p_vout->render.i_chroma ==
                VLC_FOURCC( 'I','4','2','0' ) )||
              ( p_vdec->p_vout->render.i_chroma ==
                VLC_FOURCC( 'Y','V','1','2' ) ) ) )
        {
            p_vdec->p_pp->pf_postprocess( p_pic,
                                          p_vdec->p_ff_pic->qscale_table,
                                          p_vdec->p_ff_pic->qstride,
                                          p_vdec->i_pp_mode );
        }
#endif

629
    }
gbazin's avatar
   
gbazin committed
630
631
    else
    {
632
        p_pic = (picture_t *)p_vdec->p_ff_pic->opaque;
gbazin's avatar
   
gbazin committed
633
634
    }

635
    /* fix date calculation */
636
637
638
    if( p_vdec->pts > 0 )
    {
        i_pts = p_vdec->pts;
639

640
641
        if( p_vdec->p_context->frame_rate > 0 )
        {
642
643
644
645
646
647
#if LIBAVCODEC_BUILD >= 4662
           i_pts += (uint64_t)1000000 *
                    ( p_vdec->i_frame_count - 1) /
                    DEFAULT_FRAME_RATE_BASE /
                    p_vdec->p_context->frame_rate;
#else
648
           i_pts += (uint64_t)1000000 *
649
650
651
                    ( p_vdec->i_frame_count - 1) /
                    FRAME_RATE_BASE /
                    p_vdec->p_context->frame_rate;
652
#endif
653
654
655
656
657
658
659
        }
    }
    else
    {
        i_pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
    }

660
661
    vout_DatePicture( p_vdec->p_vout,
                      p_pic,
662
663
                      i_pts );

664
    /* Send decoded frame to vout */
665
    vout_DisplayPicture( p_vdec->p_vout, p_pic );
666

667
668
    if( i_frame_size > 0 )
    {
669
        goto usenextdata; /* try to use all data */
670
    }
671
672
673
674
675
676
677
678
679
680
}

/*****************************************************************************
 * EndThread: thread destruction
 *****************************************************************************
 * This function is called when the thread ends after a sucessful
 * initialization.
 *****************************************************************************/
void E_( EndThread_Video )( vdec_thread_t *p_vdec )
{
gbazin's avatar
   
gbazin committed
681

682
683
684
685
686
687
688
689
690
691
#ifdef LIBAVCODEC_PP
    if( p_vdec->pp_mode )
    {
        pp_free_mode( p_vdec->pp_mode );
        if( p_vdec->pp_context )
        {
            pp_free_context( p_vdec->pp_context );
        }
    }
#else
692
693
694
695
696
697
698
    if( p_vdec->p_pp )
    {
        /* release postprocessing module */
        module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
        vlc_object_destroy( p_vdec->p_pp );
        p_vdec->p_pp = NULL;
    }
699
#endif
700

701
702
703
704
705
    if( p_vdec->p_ff_pic )
    {
        free( p_vdec->p_ff_pic );
    }

706
707
    /* We are about to die. Reattach video output to p_vlc. */
    vout_Request( p_vdec->p_fifo, p_vdec->p_vout, 0, 0, 0, 0 );
gbazin's avatar
   
gbazin committed
708
709
710
711
712
713
}

/*****************************************************************************
 * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
 *                     picture_t structure (when not in direct rendering mode).
 *****************************************************************************/
714
static void ffmpeg_CopyPicture( picture_t    *p_pic,
715
                                AVFrame *p_ff_pic,
716
                                vdec_thread_t *p_vdec )
gbazin's avatar
   
gbazin committed
717
{
718
    int i_plane;
gbazin's avatar
   
gbazin committed
719
720
721
    int i_size;
    int i_line;

722
723
    uint8_t *p_dst;
    uint8_t *p_src;
gbazin's avatar
   
gbazin committed
724
725
726
727
728
    int i_src_stride;
    int i_dst_stride;

    if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
    {
729
730
#ifdef LIBAVCODEC_PP
        if( p_vdec->pp_mode && p_vdec->pp_context )
gbazin's avatar
   
gbazin committed
731
        {
732
733
            uint8_t *src[3], *dst[3];
            int     i_src_stride[3], i_dst_stride[3];
gbazin's avatar
   
gbazin committed
734

735
            for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
gbazin's avatar
   
gbazin committed
736
            {
737
738
739
740
741
                src[i_plane] = p_ff_pic->data[i_plane];
                dst[i_plane] = p_pic->p[i_plane].p_pixels;

                i_src_stride[i_plane] = p_ff_pic->linesize[i_plane];
                i_dst_stride[i_plane] = p_pic->p[i_plane].i_pitch;
gbazin's avatar
   
gbazin committed
742
            }
743
744
745
746
747
748
            pp_postprocess( src, i_src_stride,
                            dst, i_dst_stride,
                            p_vdec->p_context->width, p_vdec->p_context->height,
                            p_ff_pic->qscale_table, p_ff_pic->qstride,
                            p_vdec->pp_mode, p_vdec->pp_context,
                            p_ff_pic->pict_type );
gbazin's avatar
   
gbazin committed
749
        }
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
        else
        {
#endif
            for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
            {
                p_src  = p_ff_pic->data[i_plane];
                p_dst = p_pic->p[i_plane].p_pixels;
                i_src_stride = p_ff_pic->linesize[i_plane];
                i_dst_stride = p_pic->p[i_plane].i_pitch;

                i_size = __MIN( i_src_stride, i_dst_stride );
                for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
                {
                    p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
                    p_src += i_src_stride;
                    p_dst += i_dst_stride;
                }
            }
#ifdef LIBAVCODEC_PP
        }
#endif
gbazin's avatar
   
gbazin committed
771
772
773
774
775
776
    }
    else
    {
        /* we need to convert to I420 */
        switch( p_vdec->p_context->pix_fmt )
        {
gbazin's avatar
   
gbazin committed
777
778
779
            AVPicture dest_pic;
            int i;

gbazin's avatar
   
gbazin committed
780
            case( PIX_FMT_YUV410P ):
gbazin's avatar
   
gbazin committed
781
782
783
784
785
786
787
788
789
790
791
            case( PIX_FMT_YUV411P ):
                for( i = 0; i < p_pic->i_planes; i++ )
                {
                    dest_pic.data[i] = p_pic->p[i].p_pixels;
                    dest_pic.linesize[i] = p_pic->p[i].i_pitch;
                }
                img_convert( &dest_pic, PIX_FMT_YUV420P,
                             (AVPicture *)p_ff_pic,
                             p_vdec->p_context->pix_fmt,
                             p_vdec->p_context->width,
                             p_vdec->p_context->height );
gbazin's avatar
   
gbazin committed
792
793
                break;
            default:
gbazin's avatar
   
gbazin committed
794
795
                msg_Err( p_vdec->p_fifo, "don't know how to convert chroma %i",
                         p_vdec->p_context->pix_fmt );
gbazin's avatar
   
gbazin committed
796
797
798
799
800
                p_vdec->p_fifo->b_error = 1;
                break;
        }
    }
}
801

gbazin's avatar
   
gbazin committed
802
803
804
805
/*****************************************************************************
 * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
 *                     (used for direct rendering)
 *****************************************************************************/
806
static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
807
                               AVFrame *p_ff_pic )
gbazin's avatar
   
gbazin committed
808
{
809
    vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
gbazin's avatar
   
gbazin committed
810
811
    picture_t *p_pic;

812
    /* Check and (re)create if needed our vout */
813
814
    p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
    if( !p_vdec->p_vout )
gbazin's avatar
   
gbazin committed
815
    {
816
817
818
        msg_Err( p_vdec->p_fifo, "cannot create vout" );
        p_vdec->p_fifo->b_error = 1; /* abort */
        return -1;
gbazin's avatar
   
gbazin committed
819
    }
820
    p_vdec->p_vout->render.b_allow_modify_pics = 0;
gbazin's avatar
   
gbazin committed
821
822
823
824
825
826
827
828
829
830

    /* Get a new picture */
    while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
    {
        if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
        {
            return -1;
        }
        msleep( VOUT_OUTMEM_SLEEP );
    }
831
832
833
    p_vdec->p_context->draw_horiz_band= NULL;

    p_ff_pic->opaque = (void*)p_pic;
834
    p_ff_pic->type = FF_BUFFER_TYPE_USER;
835
836
837
838
    p_ff_pic->data[0] = p_pic->p[0].p_pixels;
    p_ff_pic->data[1] = p_pic->p[1].p_pixels;
    p_ff_pic->data[2] = p_pic->p[2].p_pixels;
    p_ff_pic->data[3] = NULL; /* alpha channel but I'm not sure */
839

840
841
842
843
844
845
846
847
848
849
850
    p_ff_pic->linesize[0] = p_pic->p[0].i_pitch;
    p_ff_pic->linesize[1] = p_pic->p[1].i_pitch;
    p_ff_pic->linesize[2] = p_pic->p[2].i_pitch;
    p_ff_pic->linesize[3] = 0;

    if( p_ff_pic->reference != 0 )
    {
        vout_LinkPicture( p_vdec->p_vout, p_pic );
    }
    /* FIXME what is that, should give good value */
    p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
gbazin's avatar
   
gbazin committed
851

852
853
854
    return( 0 );
}

855
static void  ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
856
                                     AVFrame *p_ff_pic )
857
858
859
{
    vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
    picture_t *p_pic;
gbazin's avatar
   
gbazin committed
860

861
862
    //msg_Dbg( p_vdec->p_fifo, "ffmpeg_ReleaseFrameBuf" );
    p_pic = (picture_t*)p_ff_pic->opaque;
gbazin's avatar
   
gbazin committed
863

864
865
866
867
    p_ff_pic->data[0] = NULL;
    p_ff_pic->data[1] = NULL;
    p_ff_pic->data[2] = NULL;
    p_ff_pic->data[3] = NULL;
gbazin's avatar
   
gbazin committed
868

869
870
    vout_UnlinkPicture( p_vdec->p_vout, p_pic );
}
gbazin's avatar
   
gbazin committed
871