encoder.c

来自「VLC媒体播放程序」· C语言 代码 · 共 773 行 · 第 1/2 页

C
773
字号
/***************************************************************************** * encoder.c: video and audio encoder using the ffmpeg library ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN * $Id: encoder.c,v 1.23 2004/02/21 22:41:49 gbazin Exp $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> *          Gildas Bazin <gbazin@netcourrier.com> * * 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. * * 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 <vlc/vlc.h>#include <vlc/vout.h>#include <vlc/aout.h>#include <vlc/decoder.h>/* ffmpeg header */#define HAVE_MMX#ifdef HAVE_FFMPEG_AVCODEC_H#   include <ffmpeg/avcodec.h>#else#   include <avcodec.h>#endif#include "ffmpeg.h"#define AVCODEC_MAX_VIDEO_FRAME_SIZE (3*1024*1024)#define HURRY_UP_GUARD1 (1000000)#define HURRY_UP_GUARD2 (1000000)#define HURRY_UP_GUARD3 (200000)/***************************************************************************** * Local prototypes *****************************************************************************/int  E_(OpenEncoder) ( vlc_object_t * );void E_(CloseEncoder)( vlc_object_t * );static block_t *EncodeVideo( encoder_t *, picture_t * );static block_t *EncodeAudio( encoder_t *, aout_buffer_t * );struct thread_context_t;static int FfmpegThread( struct thread_context_t *p_context );static int FfmpegExecute( AVCodecContext *s,                          int (*pf_func)(AVCodecContext *c2, void *arg2),                          void **arg, int *ret, int count );/***************************************************************************** * thread_context_t : for multithreaded encoding *****************************************************************************/#if LIBAVCODEC_BUILD >= 4702struct thread_context_t{    VLC_COMMON_MEMBERS    AVCodecContext  *p_context;    int             (* pf_func)(AVCodecContext *c, void *arg);    void            *arg;    int             i_ret;    vlc_mutex_t     lock;    vlc_cond_t      cond;    vlc_bool_t      b_work, b_done;};#endif/***************************************************************************** * encoder_sys_t : ffmpeg encoder descriptor *****************************************************************************/struct encoder_sys_t{    /*     * Ffmpeg properties     */    AVCodec         *p_codec;    AVCodecContext  *p_context;    /*     * Common properties     */    char *p_buffer;    char *p_buffer_out;    /*     * Video properties     */    mtime_t i_last_ref_pts;    mtime_t i_buggy_pts_detect;    vlc_bool_t b_inited;    /*     * Audio properties     */    int i_frame_size;    int i_samples_delay;    mtime_t i_pts;};/***************************************************************************** * OpenEncoder: probe the encoder *****************************************************************************/extern int16_t ff_mpeg4_default_intra_matrix[];extern int16_t ff_mpeg4_default_non_intra_matrix[];int E_(OpenEncoder)( vlc_object_t *p_this ){    encoder_t *p_enc = (encoder_t *)p_this;    encoder_sys_t *p_sys = p_enc->p_sys;    AVCodecContext *p_context;    AVCodec *p_codec;    int i_codec_id, i_cat;    char *psz_namecodec;    if( !E_(GetFfmpegCodec)( p_enc->fmt_out.i_codec, &i_cat, &i_codec_id,                             &psz_namecodec ) )    {        if( E_(GetFfmpegChroma)( p_enc->fmt_out.i_codec ) < 0 )        {            /* handed chroma output */            return VLC_EGENERIC;        }        i_cat      = VIDEO_ES;        i_codec_id = CODEC_ID_RAWVIDEO;        psz_namecodec = "Raw video";    }    if( p_enc->fmt_out.i_cat == VIDEO_ES && i_cat != VIDEO_ES )    {        msg_Err( p_enc, "\"%s\" is not a video encoder", psz_namecodec );        return VLC_EGENERIC;    }    if( p_enc->fmt_out.i_cat == AUDIO_ES && i_cat != AUDIO_ES )    {        msg_Err( p_enc, "\"%s\" is not an audio encoder", psz_namecodec );        return VLC_EGENERIC;    }    /* Initialization must be done before avcodec_find_decoder() */    E_(InitLibavcodec)(p_this);    p_codec = avcodec_find_encoder( i_codec_id );    if( !p_codec )    {        msg_Err( p_enc, "cannot find encoder %s", psz_namecodec );        return VLC_EGENERIC;    }    /* Allocate the memory needed to store the decoder's structure */    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )    {        msg_Err( p_enc, "out of memory" );        return VLC_EGENERIC;    }    p_enc->p_sys = p_sys;    p_sys->p_codec = p_codec;    p_enc->pf_encode_video = EncodeVideo;    p_enc->pf_encode_audio = EncodeAudio;    p_sys->p_buffer_out = NULL;    p_sys->p_buffer = NULL;    p_sys->b_inited = 0;    p_sys->p_context = p_context = avcodec_alloc_context();    /* Set CPU capabilities */    p_context->dsp_mask = 0;    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMX) )    {        p_context->dsp_mask |= FF_MM_MMX;    }    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT) )    {        p_context->dsp_mask |= FF_MM_MMXEXT;    }    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW) )    {        p_context->dsp_mask |= FF_MM_3DNOW;    }    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_SSE) )    {        p_context->dsp_mask |= FF_MM_SSE;        p_context->dsp_mask |= FF_MM_SSE2;    }    /* Make sure we get extradata filled by the encoder */    p_context->extradata_size = 0;    p_context->extradata = NULL;    p_context->flags |= CODEC_FLAG_GLOBAL_HEADER;    if( p_enc->fmt_in.i_cat == VIDEO_ES )    {        if( !p_enc->fmt_in.video.i_width || !p_enc->fmt_in.video.i_height )        {            msg_Warn( p_enc, "invalid size %ix%i", p_enc->fmt_in.video.i_width,                      p_enc->fmt_in.video.i_height );            free( p_sys );            return VLC_EGENERIC;        }        p_context->width = p_enc->fmt_in.video.i_width;        p_context->height = p_enc->fmt_in.video.i_height;        p_context->frame_rate = p_enc->fmt_in.video.i_frame_rate;        p_context->frame_rate_base= p_enc->fmt_in.video.i_frame_rate_base;        /* Defaults from ffmpeg.c */        p_context->qblur = 0.5;        p_context->qcompress = 0.5;        p_context->b_quant_offset = 1.25;        p_context->b_quant_factor = 1.25;        p_context->i_quant_offset = 0.0;        p_context->i_quant_factor = -0.8;        p_context->gop_size = p_enc->i_key_int > 0 ? p_enc->i_key_int : 50;        p_context->max_b_frames =            __MIN( p_enc->i_b_frames, FF_MAX_B_FRAMES );        p_context->b_frame_strategy = 0;#if LIBAVCODEC_BUILD >= 4687        p_context->sample_aspect_ratio =            (AVRational){ p_enc->fmt_in.video.i_aspect *                          (int64_t)p_context->height / p_context->width,                          VOUT_ASPECT_FACTOR };#else        p_context->aspect_ratio = ((float)p_enc->fmt_in.video.i_aspect) /            VOUT_ASPECT_FACTOR;#endif        p_sys->p_buffer_out = malloc( AVCODEC_MAX_VIDEO_FRAME_SIZE );        p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');        if ( p_enc->b_strict_rc )        {            p_context->rc_max_rate = p_enc->fmt_out.i_bitrate;            p_context->rc_buffer_size = p_enc->i_rc_buffer_size;            p_context->rc_buffer_aggressivity = p_enc->f_rc_buffer_aggressivity;        }        if ( p_enc->f_i_quant_factor != 0.0 )        {            p_context->i_quant_factor = p_enc->f_i_quant_factor;        }#if LIBAVCODEC_BUILD >= 4690        p_context->noise_reduction = p_enc->i_noise_reduction;#endif        if ( p_enc->b_mpeg4_matrix )        {            p_context->intra_matrix = ff_mpeg4_default_intra_matrix;            p_context->inter_matrix = ff_mpeg4_default_non_intra_matrix;        }        if ( p_enc->b_pre_me )        {            p_context->pre_me = 1;            p_context->me_pre_cmp = FF_CMP_CHROMA;        }        if ( p_enc->b_interlace )        {            p_context->flags |= CODEC_FLAG_INTERLACED_DCT;#if LIBAVCODEC_BUILD >= 4698            p_context->flags |= CODEC_FLAG_INTERLACED_ME;#endif        }        if ( p_enc->b_trellis )        {            p_context->flags |= CODEC_FLAG_TRELLIS_QUANT;        }#if LIBAVCODEC_BUILD >= 4702        if ( p_enc->i_threads >= 1 )        {            p_context->thread_count = p_enc->i_threads;        }#endif        if( p_enc->i_vtolerance > 0 )        {            p_context->bit_rate_tolerance = p_enc->i_vtolerance;        }        p_context->mb_qmin = p_context->qmin = p_enc->i_qmin;        p_context->mb_qmax = p_context->qmax = p_enc->i_qmax;        p_context->max_qdiff = 3;        p_context->mb_decision = p_enc->i_hq;    }    else if( p_enc->fmt_in.i_cat == AUDIO_ES )    {        p_enc->fmt_in.i_codec  = AOUT_FMT_S16_NE;        p_context->sample_rate = p_enc->fmt_in.audio.i_rate;        p_context->channels    = p_enc->fmt_in.audio.i_channels;        p_sys->i_frame_size = p_context->frame_size * 2 * p_context->channels;        p_sys->p_buffer = malloc( p_sys->i_frame_size );        p_sys->p_buffer_out = malloc( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE );    }    /* Misc parameters */    p_context->bit_rate = p_enc->fmt_out.i_bitrate;    if( i_codec_id == CODEC_ID_RAWVIDEO )    {        /* XXX: hack: Force same codec (will be handled by transcode) */        p_enc->fmt_in.i_codec = p_enc->fmt_out.i_codec;        p_context->pix_fmt = E_(GetFfmpegChroma)( p_enc->fmt_in.i_codec );    }    /* Make sure we get extradata filled by the encoder */    p_context->extradata_size = 0;    p_context->extradata = NULL;    p_context->flags |= CODEC_FLAG_GLOBAL_HEADER;    if( avcodec_open( p_context, p_codec ) )    {        if( p_enc->fmt_in.i_cat == AUDIO_ES && p_context->channels > 2 )        {            p_context->channels = 2;            p_enc->fmt_in.audio.i_channels = 2; // FIXME            if( avcodec_open( p_context, p_codec ) )            {                msg_Err( p_enc, "cannot open encoder" );                free( p_sys );                return VLC_EGENERIC;            }            msg_Warn( p_enc, "stereo mode selected (codec limitation)" );        }        else        {            msg_Err( p_enc, "cannot open encoder" );            free( p_sys );            return VLC_EGENERIC;        }    }    p_enc->fmt_out.i_extra = p_context->extradata_size;    p_enc->fmt_out.p_extra = p_context->extradata;    p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;    if( p_enc->fmt_in.i_cat == AUDIO_ES )    {        p_sys->i_frame_size = p_context->frame_size * 2 * p_context->channels;        p_sys->p_buffer = malloc( p_sys->i_frame_size );    }    p_sys->i_last_ref_pts = 0;    p_sys->i_buggy_pts_detect = 0;    p_sys->i_samples_delay = 0;    p_sys->i_pts = 0;    msg_Dbg( p_enc, "found encoder %s", psz_namecodec );    return VLC_SUCCESS;}/**************************************************************************** * Ffmpeg threading system ****************************************************************************/#if LIBAVCODEC_BUILD >= 4702static int FfmpegThread( struct thread_context_t *p_context ){    while ( !p_context->b_die && !p_context->b_error )    {        vlc_mutex_lock( &p_context->lock );        while ( !p_context->b_work && !p_context->b_die && !p_context->b_error )        {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?