Commit 630b0fc7 authored by Gildas Bazin's avatar Gildas Bazin

* modules/codec/ffmpeg/*: ported the ffmpeg audio and video decoders to the new api.
   Isolated the video postprocessing routines in postprocess.c

* modules/codec/ffmpeg/encoder.c, modules/codec/vorbis.c, modules/stream_out/transcode.c,
   include/vlc_block.h, include/vlc_codec.h: extracted the encoders out of transcode.c.
   transcode now uses encoder plugins (currently ffmpeg, vorbis and theora).

PS: transcoding is currently a bit broken but I'll fix that ASAP.
parent 074f7be5
dnl Autoconf settings for vlc
dnl $Id: configure.ac,v 1.98 2003/10/26 17:11:56 gbazin Exp $
dnl $Id: configure.ac,v 1.99 2003/10/27 01:04:38 gbazin Exp $
AC_INIT(vlc,0.6.3-cvs)
......@@ -1706,13 +1706,6 @@ then
AC_MSG_ERROR([cannot find ${real_ffmpeg_tree}/libavcodec/libavcodec.a, make sure you compiled libavcodec in ${with_ffmpeg_tree}])
fi
fi
ac_have_vorbis_headers=yes
AC_CHECK_HEADERS(vorbis/vorbisenc.h vorbis/codec.h,,
ac_have_vorbis_headers=no)
if test "$ac_have_vorbis_headers" = "yes"; then
AX_ADD_LDFLAGS([stream_out_transcode],[-lvorbisenc -lvorbis -logg])
fi
fi
dnl
......@@ -2020,6 +2013,9 @@ then
AC_CHECK_HEADERS(vorbis/codec.h, [
AX_ADD_PLUGINS([vorbis])
AX_ADD_LDFLAGS([vorbis],[-lvorbis -logg]) ],[])
AC_CHECK_HEADERS(vorbis/vorbisenc.h, [
AX_ADD_LDFLAGS([vorbis],[-lvorbisenc]) ],[])
fi
dnl
......
......@@ -2,7 +2,7 @@
* vlc_block.h: Data blocks management functions
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* $Id: vlc_block.h,v 1.3 2003/09/30 20:23:03 gbazin Exp $
* $Id: vlc_block.h,v 1.4 2003/10/27 01:04:38 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -37,6 +37,7 @@ struct block_t
vlc_bool_t b_frame_start;
mtime_t i_pts;
mtime_t i_dts;
mtime_t i_length;
vlc_bool_t b_discontinuity; /* only temporary */
......
......@@ -2,7 +2,7 @@
* vlc_codec.h: codec related structures
*****************************************************************************
* Copyright (C) 1999-2003 VideoLAN
* $Id: vlc_codec.h,v 1.1 2003/10/08 21:01:07 gbazin Exp $
* $Id: vlc_codec.h,v 1.2 2003/10/27 01:04:38 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
......@@ -87,6 +87,20 @@ struct encoder_t
/* Properties of the output of the encoder */
vlc_fourcc_t i_fourcc;
int i_bitrate;
int i_extra_data;
uint8_t *p_extra_data;
/* FIXME: move these to the ffmpeg encoder */
int i_frame_rate;
int i_frame_rate_base;
int i_key_int;
int i_b_frames;
int i_vtolerance;
int i_qmin;
int i_qmax;
int i_hq;
};
/**
......
......@@ -2,9 +2,9 @@ SOURCES_ffmpeg = \
ffmpeg.c \
ffmpeg.h \
video.c \
video.h \
audio.c \
audio.h \
chroma.c \
encoder.c \
postprocess.c \
$(NULL)
/*****************************************************************************
* audio.c: audio decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: audio.c,v 1.19 2003/07/10 01:33:41 fenrir Exp $
* Copyright (C) 1999-2003 VideoLAN
* $Id: audio.c,v 1.20 2003/10/27 01:04:38 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
......@@ -25,6 +26,7 @@
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/vout.h>
......@@ -36,12 +38,10 @@
#include <unistd.h> /* getpid() */
#endif
#include <errno.h>
#include <string.h>
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include "codecs.h"
#include "aout_internal.h"
......@@ -52,304 +52,241 @@
# include <avcodec.h>
#endif
//#include "postprocessing/postprocessing.h"
#include "ffmpeg.h"
#include "audio.h"
/*
* Local prototypes
*/
int E_( InitThread_Audio ) ( adec_thread_t * );
void E_( EndThread_Audio ) ( adec_thread_t * );
void E_( DecodeThread_Audio ) ( adec_thread_t * );
static unsigned int pi_channels_maps[6] =
{
0,
AOUT_CHAN_CENTER, AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
};
/*****************************************************************************
* locales Functions
*****************************************************************************/
/*****************************************************************************
*
* Functions that initialize, decode and end the decoding process
*
* Functions exported for ffmpeg.c
* * E_( InitThread_Audio )
* * E_( DecodeThread_Audio )
* * E_( EndThread_Video_Audio )
* decoder_sys_t : decoder descriptor
*****************************************************************************/
struct decoder_sys_t
{
/* Common part between video and audio decoder */
int i_cat;
int i_codec_id;
char *psz_namecodec;
AVCodecContext *p_context;
AVCodec *p_codec;
/* Temporary buffer for libavcodec */
uint8_t *p_output;
/*
* Output properties
*/
aout_instance_t *p_aout;
aout_input_t *p_aout_input;
audio_sample_format_t aout_format;
audio_date_t end_date;
};
/*****************************************************************************
* InitThread: initialize vdec output thread
* InitAudioDec: initialize audio decoder
*****************************************************************************
* 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
* flag are not modified inside this function.
*
* ffmpeg codec will be open, some memory allocated.
* The ffmpeg codec will be opened, some memory allocated.
*****************************************************************************/
int E_( InitThread_Audio )( adec_thread_t *p_adec )
int E_(InitAudioDec)( decoder_t *p_dec, AVCodecContext *p_context,
AVCodec *p_codec, int i_codec_id, char *psz_namecodec )
{
decoder_sys_t *p_sys;
WAVEFORMATEX wf, *p_wf;
if( ( p_wf = p_adec->p_fifo->p_waveformatex ) == NULL )
/* Allocate the memory needed to store the decoder's structure */
if( ( p_dec->p_sys = p_sys =
(decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
{
msg_Warn( p_adec->p_fifo, "audio informations missing" );
msg_Err( p_dec, "out of memory" );
return VLC_EGENERIC;
}
p_dec->p_sys->p_context = p_context;
p_dec->p_sys->p_codec = p_codec;
p_dec->p_sys->i_codec_id = i_codec_id;
p_dec->p_sys->psz_namecodec = psz_namecodec;
if( ( p_wf = p_dec->p_fifo->p_waveformatex ) == NULL )
{
msg_Warn( p_dec, "audio informations missing" );
p_wf = &wf;
memset( p_wf, 0, sizeof( WAVEFORMATEX ) );
}
/* ***** Fill p_context with init values ***** */
p_adec->p_context->sample_rate = p_wf->nSamplesPerSec;
p_adec->p_context->channels = p_wf->nChannels;
p_adec->p_context->block_align = p_wf->nBlockAlign;
p_adec->p_context->bit_rate = p_wf->nAvgBytesPerSec * 8;
p_sys->p_context->sample_rate = p_wf->nSamplesPerSec;
p_sys->p_context->channels = p_wf->nChannels;
p_sys->p_context->block_align = p_wf->nBlockAlign;
p_sys->p_context->bit_rate = p_wf->nAvgBytesPerSec * 8;
if( ( p_adec->p_context->extradata_size = p_wf->cbSize ) > 0 )
if( ( p_sys->p_context->extradata_size = p_wf->cbSize ) > 0 )
{
p_adec->p_context->extradata = malloc( p_wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE );
memcpy( p_adec->p_context->extradata, &p_wf[1], p_wf->cbSize);
memset( &((uint8_t*)p_adec->p_context->extradata)[p_wf->cbSize], 0, FF_INPUT_BUFFER_PADDING_SIZE );
p_sys->p_context->extradata =
malloc( p_wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE );
memcpy( p_sys->p_context->extradata, &p_wf[1], p_wf->cbSize);
memset( &((uint8_t*)p_sys->p_context->extradata)[p_wf->cbSize], 0,
FF_INPUT_BUFFER_PADDING_SIZE );
}
/* ***** Open the codec ***** */
if (avcodec_open(p_adec->p_context, p_adec->p_codec) < 0)
if (avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0)
{
msg_Err( p_adec->p_fifo,
"cannot open codec (%s)",
p_adec->psz_namecodec );
return( -1 );
msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
return VLC_EGENERIC;
}
else
{
msg_Dbg( p_adec->p_fifo,
"ffmpeg codec (%s) started",
p_adec->psz_namecodec );
msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->psz_namecodec );
}
p_adec->p_output = malloc( 3 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
p_sys->p_output = malloc( 3 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
p_sys->p_aout = NULL;
p_sys->p_aout_input = NULL;
p_adec->output_format.i_format = AOUT_FMT_S16_NE;
p_adec->output_format.i_rate = p_wf->nSamplesPerSec;
p_adec->output_format.i_physical_channels
= p_adec->output_format.i_original_channels
= pi_channels_maps[p_wf->nChannels];
aout_DateSet( &p_sys->end_date, 0 );
p_adec->p_aout = NULL;
p_adec->p_aout_input = NULL;
return( 0 );
return VLC_SUCCESS;
}
/*****************************************************************************
* DecodeThread: Called for decode one frame
* DecodeAudio: Called to decode one frame
*****************************************************************************/
void E_( DecodeThread_Audio )( adec_thread_t *p_adec )
int E_( DecodeAudio )( decoder_t *p_dec, block_t *p_block )
{
pes_packet_t *p_pes;
decoder_sys_t *p_sys = p_dec->p_sys;
aout_buffer_t *p_aout_buffer;
mtime_t i_pts;
int i_samplesperchannel;
int i_output_size;
int i_frame_size;
int i_used;
uint8_t *p;
uint8_t *p_buffer, *p_samples;
int i_buffer, i_samples;
do
if( !aout_DateGet( &p_sys->end_date ) && !p_block->i_pts )
{
input_ExtractPES( p_adec->p_fifo, &p_pes );
if( !p_pes )
{
p_adec->p_fifo->b_error = 1;
return;
/* We've just started the stream, wait for the first PTS. */
block_Release( p_block );
return VLC_SUCCESS;
}
p_adec->pts = p_pes->i_pts;
i_frame_size = p_pes->i_pes_size;
if( i_frame_size > 0 )
{
int i_need;
i_pts = p_block->i_pts;
i_buffer = p_block->i_buffer;
p_buffer = p_block->p_buffer;
i_need = i_frame_size + FF_INPUT_BUFFER_PADDING_SIZE + p_adec->i_buffer;
if( p_adec->i_buffer_size < i_need )
while( i_buffer )
{
uint8_t *p_last = p_adec->p_buffer;
int i_used, i_output;
p_adec->p_buffer = malloc( i_need );
p_adec->i_buffer_size = i_need;
if( p_adec->i_buffer > 0 )
{
memcpy( p_adec->p_buffer, p_last, p_adec->i_buffer );
}
FREE( p_last );
}
i_frame_size =
E_( GetPESData )( p_adec->p_buffer + p_adec->i_buffer,
i_frame_size,
p_pes );
/* make ffmpeg happier but I'm not sure it's needed for audio */
memset( p_adec->p_buffer + p_adec->i_buffer + i_frame_size, 0, FF_INPUT_BUFFER_PADDING_SIZE );
}
input_DeletePES( p_adec->p_fifo->p_packets_mgt, p_pes );
} while( i_frame_size <= 0 );
i_frame_size += p_adec->i_buffer;
usenextdata:
i_used = avcodec_decode_audio( p_adec->p_context,
(int16_t*)p_adec->p_output,
&i_output_size,
p_adec->p_buffer,
i_frame_size );
i_used = avcodec_decode_audio( p_sys->p_context,
(int16_t*)p_sys->p_output, &i_output,
p_buffer, i_buffer );
if( i_used < 0 )
{
msg_Warn( p_adec->p_fifo,
"cannot decode one frame (%d bytes)",
i_frame_size );
p_adec->i_buffer = 0;
return;
}
else if( i_used < i_frame_size )
{
memmove( p_adec->p_buffer,
p_adec->p_buffer + i_used,
p_adec->i_buffer_size - i_used );
p_adec->i_buffer = i_frame_size - i_used;
}
else
{
p_adec->i_buffer = 0;
msg_Warn( p_dec, "cannot decode one frame (%d bytes)", i_buffer );
break;
}
i_frame_size -= i_used;
i_buffer -= i_used;
p_buffer += i_used;
//msg_Dbg( p_adec->p_fifo, "frame size:%d buffer used:%d", i_frame_size, i_used );
if( i_output_size <= 0 )
if( p_sys->p_context->channels <= 0 || p_sys->p_context->channels > 6 )
{
msg_Warn( p_adec->p_fifo,
"decoded %d samples bytes",
i_output_size );
}
if( p_adec->p_context->channels <= 0 ||
p_adec->p_context->channels > 5 )
{
msg_Warn( p_adec->p_fifo,
"invalid channels count %d",
p_adec->p_context->channels );
msg_Warn( p_dec, "invalid channels count %d",
p_sys->p_context->channels );
break;
}
/* **** First check if we have a valid output **** */
if( ( p_adec->p_aout_input == NULL )||
( p_adec->output_format.i_original_channels !=
pi_channels_maps[p_adec->p_context->channels] ) )
if( p_sys->p_aout_input == NULL ||
p_sys->aout_format.i_original_channels !=
pi_channels_maps[p_sys->p_context->channels] )
{
if( p_adec->p_aout_input != NULL )
if( p_sys->p_aout_input != NULL )
{
/* **** Delete the old **** */
aout_DecDelete( p_adec->p_aout, p_adec->p_aout_input );
aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
}
/* **** Create a new audio output **** */
p_adec->output_format.i_physical_channels =
p_adec->output_format.i_original_channels =
pi_channels_maps[p_adec->p_context->channels];
aout_DateInit( &p_adec->date, p_adec->output_format.i_rate );
p_adec->p_aout_input = aout_DecNew( p_adec->p_fifo,
&p_adec->p_aout,
&p_adec->output_format );
p_sys->aout_format.i_format = AOUT_FMT_S16_NE;
p_sys->aout_format.i_rate = p_sys->p_context->sample_rate;
p_sys->aout_format.i_physical_channels =
p_sys->aout_format.i_original_channels =
pi_channels_maps[p_sys->p_context->channels];
aout_DateInit( &p_sys->end_date, p_sys->aout_format.i_rate );
p_sys->p_aout_input = aout_DecNew( p_dec, &p_sys->p_aout,
&p_sys->aout_format );
}
if( !p_adec->p_aout_input )
if( !p_sys->p_aout_input )
{
msg_Err( p_adec->p_fifo, "cannot create aout" );
return;
msg_Err( p_dec, "cannot create audio output" );
block_Release( p_block );
return VLC_EGENERIC;
}
if( p_adec->pts != 0 && p_adec->pts != aout_DateGet( &p_adec->date ) )
if( i_pts != 0 && i_pts != aout_DateGet( &p_sys->end_date ) )
{
aout_DateSet( &p_adec->date, p_adec->pts );
}
else if( !aout_DateGet( &p_adec->date ) )
{
return;
aout_DateSet( &p_sys->end_date, i_pts );
i_pts = 0;
}
/* **** Now we can output these samples **** */
i_samplesperchannel = i_output_size / 2
/ aout_FormatNbChannels( &p_adec->output_format );
i_samples = i_output / 2 / p_sys->p_context->channels;
p = &p_adec->p_output[0];
while( i_samplesperchannel > 0 )
p_samples = p_sys->p_output;
while( i_samples > 0 )
{
int i_samples;
int i_smaller_samples;
i_samples = __MIN( 8000, i_samplesperchannel );
i_smaller_samples = __MIN( 8000, i_samples );
p_aout_buffer = aout_DecNewBuffer( p_adec->p_aout,
p_adec->p_aout_input,
i_samples );
p_aout_buffer = aout_DecNewBuffer( p_sys->p_aout,
p_sys->p_aout_input,
i_smaller_samples );
if( !p_aout_buffer )
{
msg_Err( p_adec->p_fifo, "cannot get aout buffer" );
p_adec->p_fifo->b_error = 1;
return;
msg_Err( p_dec, "cannot get aout buffer" );
block_Release( p_block );
return VLC_EGENERIC;
}
p_aout_buffer->start_date = aout_DateGet( &p_adec->date );
p_aout_buffer->end_date = aout_DateIncrement( &p_adec->date,
i_samples );
memcpy( p_aout_buffer->p_buffer,
p,
p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );
p_aout_buffer->end_date = aout_DateIncrement( &p_sys->end_date,
i_smaller_samples );
memcpy( p_aout_buffer->p_buffer, p_samples,
p_aout_buffer->i_nb_bytes );
aout_DecPlay( p_adec->p_aout, p_adec->p_aout_input, p_aout_buffer );
p += i_samples * 2 * aout_FormatNbChannels( &p_adec->output_format );
i_samplesperchannel -= i_samples;
aout_DecPlay( p_sys->p_aout, p_sys->p_aout_input, p_aout_buffer );
p_samples += i_smaller_samples * 2 * p_sys->p_context->channels;
i_samples -= i_smaller_samples;
}
if( i_frame_size > 0 )
{
goto usenextdata;
}
return;
block_Release( p_block );
return VLC_SUCCESS;
}
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
* EndAudioDec: audio decoder destruction
*****************************************************************************/
void E_( EndThread_Audio )( adec_thread_t *p_adec )
void E_(EndAudioDec)( decoder_t *p_dec )
{
// FREE( p_adec->format.p_data );
FREE( p_adec->p_output );
decoder_sys_t *p_sys = p_dec->p_sys;
if( p_adec->p_aout_input )
if( p_sys->p_output ) free( p_sys->p_output );
if( p_sys->p_aout_input )
{
aout_DecDelete( p_adec->p_aout, p_adec->p_aout_input );
aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
}
}
/*****************************************************************************
* audio.h: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: audio.h,v 1.4 2003/02/07 01:22:55 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* 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.
*****************************************************************************/
typedef struct adec_thread_s
{
DECODER_THREAD_COMMON
// waveformatex_t format;
/*
* Output properties
*/
uint8_t * p_output;
aout_instance_t * p_aout; /* opaque */
aout_input_t * p_aout_input; /* opaque */
audio_sample_format_t output_format;
audio_date_t date;
} adec_thread_t;
/*
* Local prototypes
*/
int E_( InitThread_Audio ) ( adec_thread_t * );
void E_( EndThread_Audio ) ( adec_thread_t * );
void E_( DecodeThread_Audio ) ( adec_thread_t * );
......@@ -2,7 +2,7 @@
* chroma.c: chroma conversion using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: chroma.c,v 1.2 2003/09/26 16:10:24 gbazin Exp $
* $Id: chroma.c,v 1.3 2003/10/27 01:04:38 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
......@@ -38,7 +38,7 @@
#include "ffmpeg.h"
void E_(ffmpeg_InitLibavcodec) ( vlc_object_t *p_object );
void E_(InitLibavcodec) ( vlc_object_t *p_object );
static void ChromaConversion( vout_thread_t *, picture_t *, picture_t * );
/*****************************************************************************
......@@ -148,7 +148,7 @@ int E_(OpenChroma)( vlc_object_t *p_this )
p_vout->chroma.p_sys->i_dst_ffmpeg_chroma = i_ffmpeg_chroma[1];
/* libavcodec needs to be initialized for some chroma conversions */
E_(ffmpeg_InitLibavcodec)(p_this);
E_(InitLibavcodec)(p_this);
return VLC_SUCCESS;
}
......
/*****************************************************************************
* encoder.c: video and audio encoder using the ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: encoder.c,v 1.1 2003/10/27 01:04:38 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 <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <vlc/input.h>
#include <vlc/sout.h>
#include "aout_internal.h"
/* ffmpeg header */
#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)
/*****************************************************************************
* Local prototypes
*****************************************************************************/
int E_(OpenVideoEncoder) ( vlc_object_t * );
void E_(CloseVideoEncoder)( vlc_object_t * );
int E_(OpenAudioEncoder) ( vlc_object_t * );
void E_(CloseAudioEncoder)( vlc_object_t * );
static block_t *EncodeVideo( encoder_t *, picture_t * );
static block_t *EncodeAudio( encoder_t *, aout_buffer_t * );
/*****************************************************************************
* encoder_sys_t : ffmpeg encoder descriptor
*****************************************************************************/
struct encoder_sys_t
{
/*
* Ffmpeg properties
*/
AVCodec *p_codec;
AVCodecContext *p_context;
/*
* Packetizer output properties
*/
sout_packetizer_input_t *p_sout_input;
sout_format_t sout_format;
/*
* Common properties
*/
int i_last_block_size;
int i_samples_delay;
mtime_t i_pts;
mtime_t i_last_ref_pts;
mtime_t i_buggy_pts_detect;
int i_frame_size;
char *p_buffer;
char *p_buffer_out;
};
/*****************************************************************************
* OpenVideoEncoder: probe the encoder
*****************************************************************************/
int E_(OpenVideoEncoder)( 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_ff_codec;
/* find encoder */
i_ff_codec = E_(GetFfmpegCodec)( p_enc->i_fourcc, 0, 0, 0 );
if( !i_ff_codec )
{
return VLC_EGENERIC;
}
p_codec = avcodec_find_encoder( i_ff_codec );
if( !p_codec )
{
return VLC_EGENERIC;
}
/* libavcodec needs to be initialized */
E_(InitLibavcodec)(p_this);
/* 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_header = NULL;
p_enc->pf_encode_video = EncodeVideo;
p_enc->format.video.i_chroma = VLC_FOURCC('I','4','2','0');
if( p_enc->i_fourcc == VLC_FOURCC( 'm','p','1','v' ) ||
p_enc->i_fourcc == VLC_FOURCC( 'm','p','2','v' ) )
{
p_enc->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
}
p_sys->p_context = p_context = avcodec_alloc_context();
p_context->width = p_enc->format.video.i_width;
p_context->height = p_enc->format.video.i_height;
p_context->bit_rate = p_enc->i_bitrate;
p_context->frame_rate = p_enc->i_frame_rate;
p_context->frame_rate_base= p_enc->i_frame_rate_base;
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;
p_context->b_quant_factor = 2.0;
if( p_enc->i_vtolerance >= 0 )
{
p_context->bit_rate_tolerance = p_enc->i_vtolerance;
}
p_context->qmin = p_enc->i_qmin;
p_context->qmax = p_enc->i_qmax;
#if LIBAVCODEC_BUILD >= 4673
p_context->mb_decision = p_enc->i_hq;
#else
if( p_enc->i_hq )
{
p_context->flags |= CODEC_FLAG_HQ;
}
#endif
if( i_ff_codec == CODEC_ID_RAWVIDEO )
{
p_context->pix_fmt = E_(GetFfmpegChroma)( p_enc->i_fourcc );
}
/* 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_sys->p_codec ) )
{
msg_Err( p_enc, "cannot open encoder" );
return VLC_EGENERIC;
}
p_enc->i_extra_data = p_context->extradata_size;
p_enc->p_extra_data = p_context->extradata;
p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
p_sys->p_buffer_out = malloc( AVCODEC_MAX_VIDEO_FRAME_SIZE );
p_sys->i_last_ref_pts = 0;
p_sys->i_buggy_pts_detect = 0;
return VLC_SUCCESS;
}
/****************************************************************************
* EncodeVideo: the whole thing
****************************************************************************/
static block_t *EncodeVideo( encoder_t *p_enc, picture_t *p_pict )
{
encoder_sys_t *p_sys = p_enc->p_sys;
AVFrame frame;
int i_out, i_plane;
for( i_plane = 0; i_plane < p_pict->i_planes; i_plane++ )
{
frame.data[i_plane] = p_pict->p[i_plane].p_pixels;
frame.linesize[i_plane] = p_pict->p[i_plane].i_pitch;
}
frame.pts = p_pict->date;
/* Let ffmpeg select the frame type */
frame.pict_type = 0;
i_out = avcodec_encode_video( p_sys->p_context, p_sys->p_buffer_out,
AVCODEC_MAX_VIDEO_FRAME_SIZE, &frame );
if( i_out > 0 )
{
block_t *p_block = block_New( p_enc, i_out );
memcpy( p_block->p_buffer, p_sys->p_buffer_out, i_out );
if( p_sys->p_context->coded_frame->pts != 0 &&
p_sys->i_buggy_pts_detect != p_sys->p_context->coded_frame->pts )
{
p_sys->i_buggy_pts_detect = p_sys->p_context->coded_frame->pts;
/* FIXME, 3-2 pulldown is not handled correctly */
p_block->i_length = 0;//in->i_length;
p_block->i_pts = p_sys->p_context->coded_frame->pts;
if( !p_sys->p_context->delay ||
( p_sys->p_context->coded_frame->pict_type != FF_I_TYPE &&
p_sys->p_context->coded_frame->pict_type != FF_P_TYPE ) )
{
p_block->i_dts = p_block->i_pts;
}
else
{
if( p_sys->i_last_ref_pts )
{
p_block->i_dts = p_sys->i_last_ref_pts;
}
else
{
/* Let's put something sensible */
p_block->i_dts = p_block->i_pts;
}
p_sys->i_last_ref_pts = p_block->i_pts;
}
}
else
{
/* Buggy libavcodec which doesn't update coded_frame->pts
* correctly */
p_block->i_length = 0;//in->i_length;
p_block->i_dts = p_block->i_pts = p_pict->date;
}
return p_block;
}
return NULL;
}
/*****************************************************************************
* CloseVideoEncoder: ffmpeg video encoder destruction
*****************************************************************************/
void E_(CloseVideoEncoder)( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
avcodec_close( p_sys->p_context );
free( p_sys->p_context );
free( p_sys->p_buffer_out );
free( p_sys );
}
/*****************************************************************************
* OpenAudioEncoder: probe the encoder
*****************************************************************************/
int E_(OpenAudioEncoder)( 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_ff_codec;
i_ff_codec = E_(GetFfmpegCodec)( p_enc->i_fourcc, 0, 0, 0 );
if( i_ff_codec == 0 )
{
msg_Err( p_enc, "cannot find encoder id" );
return VLC_EGENERIC;
}
p_codec = avcodec_find_encoder( i_ff_codec );
if( !p_codec )
{
msg_Err( p_enc, "cannot find encoder (avcodec)" );
return VLC_EGENERIC;
}
/* libavcodec needs to be initialized */
E_(InitLibavcodec)(p_this);
/* 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_header = NULL;
p_enc->pf_encode_audio = EncodeAudio;
p_enc->format.audio.i_format = VLC_FOURCC('s','1','6','n');
p_sys->p_context = p_context = avcodec_alloc_context();
p_context->bit_rate = p_enc->i_bitrate;
p_context->sample_rate = p_enc->format.audio.i_rate;
p_context->channels =
aout_FormatNbChannels( &p_enc->format.audio );
/* 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;
p_sys->i_samples_delay = 0;
p_sys->i_last_block_size = 0;
p_sys->i_pts = 0;
if( avcodec_open( p_context, p_sys->p_codec ) )
{
#if 0
if( p_context->channels > 2 )
{
p_context->channels = 2;
id->f_dst.i_channels = 2;
if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
{
msg_Err( p_enc, "cannot open encoder" );
return VLC_EGENERIC;
}
msg_Warn( p_enc, "stereo mode selected (codec limitation)" );
}
else
{
msg_Err( p_enc, "cannot open encoder" );
return VLC_EGENERIC;
}
#endif
}
p_enc->i_extra_data = p_context->extradata_size;
p_enc->p_extra_data = p_context->extradata;
p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
p_sys->p_buffer = malloc( p_context->frame_size * 2 *
p_context->channels * 2 );
p_sys->p_buffer_out = malloc( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
p_sys->i_frame_size = p_sys->p_context->frame_size * 2 *
p_context->channels;
/* Hack for mp3 transcoding support */
if( p_enc->i_fourcc == VLC_FOURCC( 'm','p','3',' ' ) )
{
p_enc->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
}
return VLC_SUCCESS;
}
/****************************************************************************
* EncodeAudio: the whole thing
****************************************************************************/
static block_t *EncodeAudio( encoder_t *p_enc, aout_buffer_t *p_aout_buf )
{
encoder_sys_t *p_sys = p_enc->p_sys;
block_t *p_block, *p_chain = NULL;
char *p_buffer = p_aout_buf->p_buffer;
int i_samples = p_aout_buf->i_nb_samples;
int i_samples_delay = p_sys->i_samples_delay;
p_sys->i_pts = p_aout_buf->start_date -
(mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay /
(mtime_t)p_enc->format.audio.i_rate;
p_sys->i_samples_delay += i_samples;
while( p_sys->i_samples_delay >= p_sys->p_context->frame_size )
{
int16_t *p_samples;
int i_out;
if( i_samples_delay )
{
/* Take care of the left-over from last time */
int i_delay_size = i_samples_delay * 2 *
p_sys->p_context->channels;
int i_size = p_sys->i_frame_size - i_delay_size;
p_samples = (int16_t *)p_sys->p_buffer;
memcpy( p_sys->p_buffer + i_delay_size, p_buffer, i_size );
p_buffer -= i_delay_size;
i_samples += i_samples_delay;
i_samples_delay = 0;
}
else
{
p_samples = (int16_t *)p_buffer;
}
i_out = avcodec_encode_audio( p_sys->p_context, p_sys->p_buffer_out,
2 * AVCODEC_MAX_AUDIO_FRAME_SIZE,
p_samples );
if( i_out <= 0 )
{
break;
}
p_buffer += p_sys->i_frame_size;
p_sys->i_samples_delay -= p_sys->p_context->frame_size;
i_samples = p_sys->p_context->frame_size;
p_block = block_New( p_enc, i_out );
memcpy( p_block->p_buffer, p_sys->p_buffer_out, i_out );
p_block->i_length = (mtime_t)1000000 *
(mtime_t)p_sys->p_context->frame_size /
(mtime_t)p_sys->p_context->sample_rate;
p_block->i_dts = p_block->i_pts = p_sys->i_pts;
/* Update pts */
p_sys->i_pts += p_block->i_length;
block_ChainAppend( &p_chain, p_block );
}
/* Backup the remaining raw samples */
if( p_sys->i_samples_delay > 0 )
{
memcpy( p_sys->p_buffer, p_buffer + i_samples_delay,
i_samples * 2 * p_sys->p_context->channels );
}
return p_chain;
}
/*****************************************************************************
* CloseAudioEncoder: ffmpeg audio encoder destruction
*****************************************************************************/
void E_(CloseAudioEncoder)( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
avcodec_close( p_sys->p_context );
free( p_sys->p_context );
free( p_sys->p_buffer );
free( p_sys->p_buffer_out );
free( p_sys );
}
......@@ -2,9 +2,10 @@
* ffmpeg.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ffmpeg.c,v 1.54 2003/10/25 00:49:13 sam Exp $
* $Id: ffmpeg.c,v 1.55 2003/10/27 01:04:38 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
......@@ -25,6 +26,7 @@
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/vout.h>
......@@ -32,8 +34,6 @@
#include <vlc/decoder.h>
#include <vlc/input.h>
#include <string.h>
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
......@@ -49,7 +49,6 @@
# error You must have a libavcodec >= 4655 (get CVS)
#endif
#include "ffmpeg.h"
#ifdef LIBAVCODEC_PP
......@@ -60,117 +59,54 @@
# endif
#endif
#include "video.h" // video ffmpeg specific
#include "audio.h" // audio ffmpeg specific
/*
* Local prototypes
*/
int E_(OpenChroma) ( vlc_object_t * );
void E_(ffmpeg_InitLibavcodec) ( vlc_object_t *p_object );
/*****************************************************************************
* decoder_sys_t: decoder descriptor
*****************************************************************************/
struct decoder_sys_t
{
/* Common part between video and audio decoder */
int i_cat;
int i_codec_id;
char *psz_namecodec;
static int OpenDecoder ( vlc_object_t * );
static int RunDecoder ( decoder_fifo_t * );
AVCodecContext *p_context;
AVCodec *p_codec;
};
static int InitThread ( generic_thread_t * );
static void EndThread ( generic_thread_t * );
/****************************************************************************
* Local prototypes
****************************************************************************/
static int OpenDecoder( vlc_object_t * );
static int InitDecoder( decoder_t * );
static int EndDecoder( decoder_t * );
static int b_ffmpeginit = 0;
static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t, int *, int *, char ** );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define DR_TEXT N_("Direct rendering")
#define ERROR_TEXT N_("Error resilience")
#define ERROR_LONGTEXT N_( \
"ffmpeg can make errors resiliences. \n" \
"Nevertheless, with a buggy encoder (like ISO MPEG-4 encoder from M$) " \
"this will produce a lot of errors.\n" \
"Valid range is -1 to 99 (-1 disables all errors resiliences).")
#define BUGS_TEXT N_("Workaround bugs")
#define BUGS_LONGTEXT N_( \
"Try to fix some bugs\n" \
"1 autodetect\n" \
"2 old msmpeg4\n" \
"4 xvid interlaced\n" \
"8 ump4 \n" \
"16 no padding\n" \
"32 ac vlc\n" \
"64 Qpel chroma")
#define HURRYUP_TEXT N_("Hurry up")
#define HURRYUP_LONGTEXT N_( \
"Allow the decoder to partially decode or skip frame(s) " \
"when there is not enough time. It's useful with low CPU power " \
"but it can produce distorted pictures.")
#define TRUNC_TEXT N_("Truncated stream")
#define TRUNC_LONGTEXT N_("truncated stream -1:auto,0:disable,:1:enable")
#define PP_Q_TEXT N_("Post processing quality")
#define PP_Q_LONGTEXT N_( \
"Quality of post processing. Valid range is 0 to 6\n" \
"Higher levels require considerable more CPU power, but produce " \
"better looking pictures." )
#define LIBAVCODEC_PP_TEXT N_("Ffmpeg postproc filter chains")
/* FIXME (cut/past from ffmpeg */
#define LIBAVCODEC_PP_LONGTEXT \
"<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n" \
"long form example:\n" \
"vdeblock:autoq/hdeblock:autoq/linblenddeint default,-vdeblock\n" \
"short form example:\n" \
"vb:a/hb:a/lb de,-vb\n" \
"more examples:\n" \
"tn:64:128:256\n" \
"Filters Options\n" \
"short long name short long option Description\n" \
"* * a autoq cpu power dependant enabler\n" \
" c chrom chrominance filtring enabled\n" \
" y nochrom chrominance filtring disabled\n" \
"hb hdeblock (2 Threshold) horizontal deblocking filter\n" \
" 1. difference factor: default=64, higher -> more deblocking\n" \
" 2. flatness threshold: default=40, lower -> more deblocking\n" \
" the h & v deblocking filters share these\n" \
" so u cant set different thresholds for h / v\n" \
"vb vdeblock (2 Threshold) vertical deblocking filter\n" \
"h1 x1hdeblock Experimental h deblock filter 1\n" \
"v1 x1vdeblock Experimental v deblock filter 1\n" \
"dr dering Deringing filter\n" \
"al autolevels automatic brightness / contrast\n" \
" f fullyrange stretch luminance to (0..255)\n" \
"lb linblenddeint linear blend deinterlacer\n" \
"li linipoldeint linear interpolating deinterlace\n" \
"ci cubicipoldeint cubic interpolating deinterlacer\n" \
"md mediandeint median deinterlacer\n" \
"fd ffmpegdeint ffmpeg deinterlacer\n" \
"de default hb:a,vb:a,dr:a,al\n" \
"fa fast h1:a,v1:a,dr:a,al\n" \
"tn tmpnoise (3 Thresholds) Temporal Noise Reducer\n" \
" 1. <= 2. <= 3. larger -> stronger filtering\n" \
"fq forceQuant <quantizer> Force quantizer\n"
vlc_module_begin();
/* decoder main module */
add_category_hint( N_("ffmpeg"), NULL, VLC_FALSE );
set_capability( "decoder", 70 );
set_callbacks( OpenDecoder, NULL );
set_description( _("ffmpeg audio/video decoder((MS)MPEG4,SVQ1,H263,WMV,WMA)") );
add_bool( "ffmpeg-dr", 1, NULL, DR_TEXT, DR_TEXT, VLC_TRUE );
add_integer ( "ffmpeg-error-resilience", -1, NULL, ERROR_TEXT, ERROR_LONGTEXT, VLC_TRUE );
add_integer ( "ffmpeg-workaround-bugs", 1, NULL, BUGS_TEXT, BUGS_LONGTEXT, VLC_FALSE );
add_bool( "ffmpeg-hurry-up", 0, NULL, HURRYUP_TEXT, HURRYUP_LONGTEXT, VLC_FALSE );
add_integer( "ffmpeg-truncated", -1, NULL, TRUNC_TEXT, TRUNC_LONGTEXT, VLC_FALSE );
add_category_hint( N_("Post processing"), NULL, VLC_FALSE );
add_integer ( "ffmpeg-error-resilience", -1, NULL, ERROR_TEXT,
ERROR_LONGTEXT, VLC_TRUE );
add_integer ( "ffmpeg-workaround-bugs", 1, NULL, BUGS_TEXT, BUGS_LONGTEXT,
VLC_FALSE );
add_bool( "ffmpeg-hurry-up", 0, NULL, HURRYUP_TEXT, HURRYUP_LONGTEXT,
VLC_FALSE );
add_integer( "ffmpeg-truncated", 0, NULL, TRUNC_TEXT, TRUNC_LONGTEXT,
VLC_FALSE );
add_integer( "ffmpeg-pp-q", 0, NULL, PP_Q_TEXT, PP_Q_LONGTEXT, VLC_FALSE );
#ifdef LIBAVCODEC_PP
add_string( "ffmpeg-pp-name", "default", NULL, LIBAVCODEC_PP_TEXT, LIBAVCODEC_PP_LONGTEXT, VLC_TRUE );
add_integer( "ffmpeg-pp-q", 0, NULL, PP_Q_TEXT, PP_Q_LONGTEXT, VLC_FALSE );
add_string( "ffmpeg-pp-name", "default", NULL, LIBAVCODEC_PP_TEXT,
LIBAVCODEC_PP_LONGTEXT, VLC_TRUE );
#endif
/* chroma conversion submodule */
......@@ -179,234 +115,124 @@ vlc_module_begin();
set_callbacks( E_(OpenChroma), NULL );
set_description( _("ffmpeg chroma conversion") );
/* video encoder submodule */
add_submodule();
set_description( _("ffmpeg video encoder") );
set_capability( "video encoder", 100 );
set_callbacks( E_(OpenVideoEncoder), E_(CloseVideoEncoder) );
/* audio encoder submodule */
add_submodule();
set_description( _("ffmpeg audio encoder") );
set_capability( "audio encoder", 10 );
set_callbacks( E_(OpenAudioEncoder), E_(CloseAudioEncoder) );
var_Create( p_module->p_libvlc, "avcodec", VLC_VAR_MUTEX );
vlc_module_end();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to chose.
*****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t*) p_this;
int i_cat;
if( !ffmpeg_GetFfmpegCodec( p_dec->p_fifo->i_fourcc, NULL, NULL, NULL ) )
if( !E_(GetFfmpegCodec)( p_dec->p_fifo->i_fourcc, &i_cat, NULL, NULL ) )
{
return VLC_EGENERIC;
}
p_dec->pf_run = RunDecoder;
p_dec->pf_init = InitDecoder;
p_dec->pf_decode = (i_cat == VIDEO_ES) ? E_(DecodeVideo) : E_(DecodeAudio);
p_dec->pf_end = EndDecoder;
return VLC_SUCCESS;
}
typedef union decoder_thread_u
{
generic_thread_t gen;
adec_thread_t audio;
vdec_thread_t video;
} decoder_thread_t;
/*****************************************************************************
* RunDecoder: this function is called just after the thread is created
*****************************************************************************/
static int RunDecoder( decoder_fifo_t *p_fifo )
{
generic_thread_t *p_decoder;
int b_error;
if ( !(p_decoder = malloc( sizeof( decoder_thread_t ) ) ) )
{
msg_Err( p_fifo, "out of memory" );
DecoderError( p_fifo );
return( -1 );
}
memset( p_decoder, 0, sizeof( decoder_thread_t ) );
p_decoder->p_fifo = p_fifo;
if( InitThread( p_decoder ) != 0 )
{
msg_Err( p_fifo, "initialization failed" );
DecoderError( p_fifo );
return( -1 );
}
while( (!p_decoder->p_fifo->b_die) && (!p_decoder->p_fifo->b_error) )
{
switch( p_decoder->i_cat )
{
case VIDEO_ES:
E_( DecodeThread_Video )( (vdec_thread_t*)p_decoder );
break;
case AUDIO_ES:
E_( DecodeThread_Audio )( (adec_thread_t*)p_decoder );
break;
}
}
if( ( b_error = p_decoder->p_fifo->b_error ) )
{
DecoderError( p_decoder->p_fifo );
}
EndThread( p_decoder );
if( b_error )
{
return( -1 );
}
return( 0 );
}
/*****************************************************************************
*
* Functions that initialize, decode and end the decoding process
*
*****************************************************************************/
/*****************************************************************************
* InitThread: initialize vdec output thread
*****************************************************************************
* 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
* flag are not modified inside this function.
*
* ffmpeg codec will be open, some memory allocated. But Vout is not yet
* open (done after the first decoded frame)
* InitDecoder: Initalize the decoder
*****************************************************************************/
static int InitThread( generic_thread_t *p_decoder )
static int InitDecoder( decoder_t *p_dec )
{
int i_result;
int i_cat, i_codec_id, i_result;
char *psz_namecodec;
AVCodecContext *p_context;
AVCodec *p_codec;
E_(ffmpeg_InitLibavcodec)(VLC_OBJECT(p_decoder->p_fifo));
E_(InitLibavcodec)( VLC_OBJECT(p_dec->p_fifo) );
/* *** determine codec type *** */
ffmpeg_GetFfmpegCodec( p_decoder->p_fifo->i_fourcc,
&p_decoder->i_cat,
&p_decoder->i_codec_id,
&p_decoder->psz_namecodec );
E_(GetFfmpegCodec)( p_dec->p_fifo->i_fourcc,
&i_cat, &i_codec_id, &psz_namecodec );
/* *** ask ffmpeg for a decoder *** */
if( !( p_decoder->p_codec =
avcodec_find_decoder( p_decoder->i_codec_id ) ) )
if( !( p_codec = avcodec_find_decoder( i_codec_id ) ) )
{
msg_Err( p_decoder->p_fifo,
"codec not found (%s)",
p_decoder->psz_namecodec );
return( -1 );
msg_Err( p_dec, "codec not found (%s)", psz_namecodec );
return VLC_EGENERIC;
}
/* *** Get a p_context *** */
p_decoder->p_context = avcodec_alloc_context();
/* *** get a p_context *** */
p_context = avcodec_alloc_context();
switch( p_decoder->i_cat )
switch( i_cat )
{
case VIDEO_ES:
i_result = E_( InitThread_Video )( (vdec_thread_t*)p_decoder );
i_result = E_( InitVideoDec )( p_dec, p_context, p_codec,
i_codec_id, psz_namecodec );
p_dec->pf_decode = E_(DecodeVideo);
break;
case AUDIO_ES:
i_result = E_( InitThread_Audio )( (adec_thread_t*)p_decoder );
i_result = E_( InitAudioDec )( p_dec, p_context, p_codec,
i_codec_id, psz_namecodec );
p_dec->pf_decode = E_(DecodeAudio);
break;
default:
i_result = -1;
i_result = VLC_EGENERIC;
}
p_decoder->pts = 0;
p_decoder->p_buffer = NULL;
p_decoder->i_buffer = 0;
p_decoder->i_buffer_size = 0;
p_dec->p_sys->i_cat = i_cat;
return( i_result );
return i_result;
}
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
* EndDecoder: decoder destruction
*****************************************************************************/
static void EndThread( generic_thread_t *p_decoder )
static int EndDecoder( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
if( !p_decoder )
if( !p_sys->p_context )
{
return;
}
if( p_sys->p_context->extradata )
free( p_sys->p_context->extradata );
if( p_decoder->p_context != NULL)
{
FREE( p_decoder->p_context->extradata );
avcodec_close( p_decoder->p_context );
msg_Dbg( p_decoder->p_fifo,
"ffmpeg codec (%s) stopped",
p_decoder->psz_namecodec );
free( p_decoder->p_context );
avcodec_close( p_sys->p_context );
msg_Dbg( p_dec, "ffmpeg codec (%s) stopped", p_sys->psz_namecodec );
free( p_sys->p_context );
}
FREE( p_decoder->p_buffer );
switch( p_decoder->i_cat )
switch( p_sys->i_cat )
{
case AUDIO_ES:
E_( EndThread_Audio )( (adec_thread_t*)p_decoder );
E_( EndAudioDec )( p_dec );
break;
case VIDEO_ES:
E_( EndThread_Video )( (vdec_thread_t*)p_decoder );
E_( EndVideoDec )( p_dec );
break;
}
free( p_decoder );
free( p_sys );
return VLC_SUCCESS;
}
/*****************************************************************************
* locales Functions
* local Functions
*****************************************************************************/
int E_( GetPESData )( uint8_t *p_buf, int i_max, pes_packet_t *p_pes )
{
int i_copy;
int i_count;
data_packet_t *p_data;
i_count = 0;
p_data = p_pes->p_first;
while( p_data != NULL && i_count < i_max )
{
i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
i_max - i_count );
if( i_copy > 0 )
{
memcpy( p_buf,
p_data->p_payload_start,
i_copy );
}
p_data = p_data->p_next;
i_count += i_copy;
p_buf += i_copy;
}
if( i_count < i_max )
{
memset( p_buf, 0, i_max - i_count );
}
return( i_count );
}
static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
int *pi_cat,
int *pi_ffmpeg_codec,
char **ppsz_name )
int E_(GetFfmpegCodec)( vlc_fourcc_t i_fourcc, int *pi_cat,
int *pi_ffmpeg_codec, char **ppsz_name )
{
int i_cat;
int i_codec;
......@@ -414,297 +240,386 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
switch( i_fourcc )
{
case FOURCC_mpgv:
/*
* Video Codecs
*/
/* MPEG-1 Video */
case VLC_FOURCC('m','p','1','v'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MPEG1VIDEO;
psz_name = "MPEG-1/2 Video";
break;
case FOURCC_DIV1:
case FOURCC_div1:
case FOURCC_MPG4:
case FOURCC_mpg4:
/* MPEG-2 Video */
case VLC_FOURCC('m','p','2','v'):
case VLC_FOURCC('m','p','g','v'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MPEG2VIDEO;
psz_name = "MPEG-2 Video";
break;
/* MPEG-4 Video */
case VLC_FOURCC('D','I','V','X'):
case VLC_FOURCC('d','i','v','x'):
case VLC_FOURCC('M','P','4','S'):
case VLC_FOURCC('m','p','4','s'):
case VLC_FOURCC('M','4','S','2'):
case VLC_FOURCC('m','4','s','2'):
case VLC_FOURCC('x','v','i','d'):
case VLC_FOURCC('X','V','I','D'):
case VLC_FOURCC('X','v','i','D'):
case VLC_FOURCC('D','X','5','0'):
case VLC_FOURCC('m','p','4','v'):
case VLC_FOURCC( 4, 0, 0, 0 ):
case VLC_FOURCC('m','4','c','c'):
case VLC_FOURCC('M','4','C','C'):
/* 3ivx delta 3.5 Unsupported
* putting it here gives extreme distorted images
case VLC_FOURCC('3','I','V','1'):
case VLC_FOURCC('3','i','v','1'): */
/* 3ivx delta 4 */
case VLC_FOURCC('3','I','V','2'):
case VLC_FOURCC('3','i','v','2'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MPEG4;
psz_name = "MPEG-4";
break;
/* MSMPEG4 v1 */
case VLC_FOURCC('D','I','V','1'):
case VLC_FOURCC('d','i','v','1'):
case VLC_FOURCC('M','P','G','4'):
case VLC_FOURCC('m','p','g','4'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSMPEG4V1;
psz_name = "MS MPEG-4 v1";
break;
case FOURCC_DIV2:
case FOURCC_div2:
case FOURCC_MP42:
case FOURCC_mp42:
/* MSMPEG4 v2 */
case VLC_FOURCC('D','I','V','2'):
case VLC_FOURCC('d','i','v','2'):
case VLC_FOURCC('M','P','4','2'):
case VLC_FOURCC('m','p','4','2'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSMPEG4V2;
psz_name = "MS MPEG-4 v2";
break;
case FOURCC_MPG3:
case FOURCC_mpg3:
case FOURCC_div3:
case FOURCC_MP43:
case FOURCC_mp43:
case FOURCC_DIV3:
case FOURCC_DIV4:
case FOURCC_div4:
case FOURCC_DIV5:
case FOURCC_div5:
case FOURCC_DIV6:
case FOURCC_div6:
case FOURCC_AP41:
case FOURCC_3VID:
case FOURCC_3vid:
case FOURCC_3IVD:
case FOURCC_3ivd:
/* MSMPEG4 v3 / M$ mpeg4 v3 */
case VLC_FOURCC('M','P','G','3'):
case VLC_FOURCC('m','p','g','3'):
case VLC_FOURCC('d','i','v','3'):
case VLC_FOURCC('M','P','4','3'):
case VLC_FOURCC('m','p','4','3'):
/* DivX 3.20 */
case VLC_FOURCC('D','I','V','3'):
case VLC_FOURCC('D','I','V','4'):
case VLC_FOURCC('d','i','v','4'):
case VLC_FOURCC('D','I','V','5'):
case VLC_FOURCC('d','i','v','5'):
case VLC_FOURCC('D','I','V','6'):
case VLC_FOURCC('d','i','v','6'):
/* AngelPotion stuff */
case VLC_FOURCC('A','P','4','1'):
/* 3ivx doctered divx files */
case VLC_FOURCC('3','I','V','D'):
case VLC_FOURCC('3','i','v','d'):
/* who knows? */
case VLC_FOURCC('3','V','I','D'):
case VLC_FOURCC('3','v','i','d'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSMPEG4V3;
psz_name = "MS MPEG-4 v3";
break;
case FOURCC_SVQ1:
/* Sorenson v1 */
case VLC_FOURCC('S','V','Q','1'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_SVQ1;
psz_name = "SVQ-1 (Sorenson Video v1)";
break;
#if LIBAVCODEC_BUILD >= 4666
case FOURCC_SVQ3:
/* Sorenson v3 */
case VLC_FOURCC('S','V','Q','3'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_SVQ3;
psz_name = "SVQ-3 (Sorenson Video v3)";
break;
#endif
case FOURCC_DIVX:
case FOURCC_divx:
case FOURCC_MP4S:
case FOURCC_mp4s:
case FOURCC_M4S2:
case FOURCC_m4s2:
case FOURCC_xvid:
case FOURCC_XVID:
case FOURCC_XviD:
case FOURCC_DX50:
case FOURCC_mp4v:
case FOURCC_4:
case FOURCC_m4cc:
case FOURCC_M4CC:
/* 3iv1 is unsupported by ffmpeg
putting it here gives extreme distorted images
case FOURCC_3IV1:
case FOURCC_3iv1:
*/
case FOURCC_3IV2:
case FOURCC_3iv2:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MPEG4;
psz_name = "MPEG-4";
break;
/* H263 and H263i */
/* H263(+) is also known as Real Video 1.0 */
/* FIXME FOURCC_H263P exist but what fourcc ? */
case FOURCC_H263:
case FOURCC_h263:
case FOURCC_U263:
/* H263 */
case VLC_FOURCC('H','2','6','3'):
case VLC_FOURCC('h','2','6','3'):
case VLC_FOURCC('U','2','6','3'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_H263;
psz_name = "H263";
break;
case FOURCC_I263:
case FOURCC_i263:
/* H263i */
case VLC_FOURCC('I','2','6','3'):
case VLC_FOURCC('i','2','6','3'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_H263I;
psz_name = "I263.I";
break;
case FOURCC_WMV1:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_WMV1;
psz_name ="Windows Media Video 1";
break;
case FOURCC_WMV2:
#if LIBAVCODEC_BUILD >= 4669
/* Flash (H263) variant */
case VLC_FOURCC('F','L','V','1'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_WMV2;
psz_name ="Windows Media Video 2";
i_codec = CODEC_ID_FLV1;
psz_name = "Flash Video";
break;
case FOURCC_MJPG:
case FOURCC_mjpg:
case FOURCC_mjpa:
case FOURCC_jpeg:
case FOURCC_JPEG:
case FOURCC_JFIF:
case FOURCC_JPGL:
#endif
/* MJPEG */
case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
case VLC_FOURCC( 'm', 'j', 'p', 'g' ):
case VLC_FOURCC( 'm', 'j', 'p', 'a' ): /* for mov file */
case VLC_FOURCC( 'j', 'p', 'e', 'g' ):
case VLC_FOURCC( 'J', 'P', 'E', 'G' ):
case VLC_FOURCC( 'J', 'F', 'I', 'F' ):
case VLC_FOURCC( 'J', 'P', 'G', 'L' ):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MJPEG;
psz_name = "Motion JPEG";
break;
case FOURCC_mjpb:
case VLC_FOURCC( 'm', 'j', 'p', 'b' ): /* for mov file */
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MJPEGB;
psz_name = "Motion JPEG B";
break;
case FOURCC_dvsl:
case FOURCC_dvsd:
case FOURCC_DVSD:
case FOURCC_dvhd:
case FOURCC_dvc:
case FOURCC_dvp:
case FOURCC_CDVC:
/* DV */
case VLC_FOURCC('d','v','s','l'):
case VLC_FOURCC('d','v','s','d'):
case VLC_FOURCC('D','V','S','D'):
case VLC_FOURCC('d','v','h','d'):
case VLC_FOURCC('d','v','c',' '):
case VLC_FOURCC('d','v','p',' '):
case VLC_FOURCC('C','D','V','C'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_DVVIDEO;
psz_name = "DV video";
break;
case FOURCC_MAC3:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_MACE3;
psz_name = "MACE-3 audio";
/* Windows Media Video */
case VLC_FOURCC('W','M','V','1'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_WMV1;
psz_name ="Windows Media Video 1";
break;
case FOURCC_MAC6:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_MACE6;
psz_name = "MACE-6 audio";
case VLC_FOURCC('W','M','V','2'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_WMV2;
psz_name ="Windows Media Video 2";
break;
case FOURCC_dvau:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_DVAUDIO;
psz_name = "DV audio";
#if LIBAVCODEC_BUILD >= 4683
/* Microsoft Video 1 */
case VLC_FOURCC('M','S','V','C'):
case VLC_FOURCC('m','s','v','c'):
case VLC_FOURCC('C','R','A','M'):
case VLC_FOURCC('c','r','a','m'):
case VLC_FOURCC('W','H','A','M'):
case VLC_FOURCC('w','h','a','m'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSVIDEO1;
psz_name = "Microsoft Video 1";
break;
case FOURCC_WMA1:
case FOURCC_wma1:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_WMAV1;
psz_name ="Windows Media Audio 1";
/* Microsoft RLE */
case VLC_FOURCC('m','r','l','e'):
case VLC_FOURCC(0x1,0x0,0x0,0x0):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSRLE;
psz_name = "Microsoft RLE";
break;
case FOURCC_WMA2:
case FOURCC_wma2:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_WMAV2;
psz_name ="Windows Media Audio 2";
#endif
#if( ( LIBAVCODEC_BUILD >= 4663 ) && ( !defined( WORDS_BIGENDIAN ) ) )
/* Indeo Video Codecs (Quality of this decoder on ppc is not good) */
case VLC_FOURCC('I','V','3','1'):
case VLC_FOURCC('i','v','3','1'):
case VLC_FOURCC('I','V','3','2'):
case VLC_FOURCC('i','v','3','2'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_INDEO3;
psz_name = "Indeo v3";
break;
#endif
case FOURCC_HFYU:
/* Huff YUV */
case VLC_FOURCC('H','F','Y','U'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_HUFFYUV;
psz_name ="Huff YUV";
break;
case FOURCC_CYUV:
/* Creative YUV */
case VLC_FOURCC('C','Y','U','V'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_CYUV;
psz_name ="Creative YUV";
break;
#if( ( LIBAVCODEC_BUILD >= 4663 ) && ( !defined( WORDS_BIGENDIAN ) ) )
/* Quality of this decoder on ppc is not good */
case FOURCC_IV31:
case FOURCC_iv31:
case FOURCC_IV32:
case FOURCC_iv32:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_INDEO3;
psz_name = "Indeo v3";
break;
#endif
#if LIBAVCODEC_BUILD >= 4668
/* Sorta works */
case FOURCC_vp31:
case FOURCC_VP31:
/* On2 VP3 Video Codecs */
case VLC_FOURCC('V','P','3','1'):
case VLC_FOURCC('v','p','3','1'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_VP3;
psz_name = "On2's VP3 Video";
break;
#endif
#if ( !defined( WORDS_BIGENDIAN ) )
/* Another thing that doesn't work */
case FOURCC_ASV1:
#if LIBAVCODEC_BUILD >= 4668
/* Asus Video (Another thing that doesn't work on PPC) */
case VLC_FOURCC('A','S','V','1'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_ASV1;
psz_name = "Asus V1";
break;
#endif
#if LIBAVCODEC_BUILD >= 4677
case VLC_FOURCC('A','S','V','2'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_ASV2;
psz_name = "Asus V2";
break;
#endif
#endif
case FOURCC_FFV1:
#if LIBAVCODEC_BUILD >= 4668
/* FFMPEG Video 1 (lossless codec) */
case VLC_FOURCC('F','F','V','1'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_FFV1;
psz_name = "FFMpeg Video 1";
break;
case FOURCC_RA10:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_RA_144;
psz_name = "RealAudio 1.0";
break;
case FOURCC_RA20:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_RA_288;
psz_name = "RealAudio 2.0";
break;
#endif
#if LIBAVCODEC_BUILD >= 4669
case FOURCC_FLV1:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_FLV1;
psz_name = "Flash Video";
break;
case FOURCC_VCR1:
/* ATI VCR1 */
case VLC_FOURCC('V','C','R','1'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_VCR1;
psz_name = "ATI VCR1";
break;
#endif
#if LIBAVCODEC_BUILD >= 4672
case FOURCC_CLJR:
/* Cirrus Logic AccuPak */
case VLC_FOURCC('C','L','J','R'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_CLJR;
psz_name = "Creative Logic AccuPak";
break;
#endif
#if LIBAVCODEC_BUILD >= 4677
case FOURCC_ASV2:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_ASV2;
psz_name = "Asus V2";
break;
#endif
#if LIBAVCODEC_BUILD >= 4683
case FOURCC_rpza:
/* Apple Video */
case VLC_FOURCC('r','p','z','a'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_RPZA;
psz_name = "Apple Video";
break;
#endif
case FOURCC_cvid:
#if LIBAVCODEC_BUILD >= 4683
/* Cinepak */
case VLC_FOURCC('c','v','i','d'):
i_cat = VIDEO_ES;
i_codec = CODEC_ID_CINEPAK;
psz_name = "Cinepak";
break;
#endif
case FOURCC_mrle:
case FOURCC_1000:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSRLE;
psz_name = "Microsoft RLE";
/*
* Audio Codecs
*/
/* Windows Media Audio 1 */
case VLC_FOURCC('W','M','A','1'):
case VLC_FOURCC('w','m','a','1'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_WMAV1;
psz_name ="Windows Media Audio 1";
break;
case FOURCC_cram:
case FOURCC_CRAM:
case FOURCC_msvc:
case FOURCC_MSVC:
case FOURCC_wham:
case FOURCC_WHAM:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSVIDEO1;
psz_name = "Microsoft Video 1";
/* Windows Media Audio 2 */
case VLC_FOURCC('W','M','A','2'):
case VLC_FOURCC('w','m','a','2'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_WMAV2;
psz_name ="Windows Media Audio 2";
break;
/* DV Audio */
case VLC_FOURCC('d','v','a','u'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_DVAUDIO;
psz_name = "DV audio";
break;
/* MACE-3 Audio */
case VLC_FOURCC('M','A','C','3'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_MACE3;
psz_name = "MACE-3 audio";
break;
/* MACE-6 Audio */
case VLC_FOURCC('M','A','C','6'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_MACE6;
psz_name = "MACE-6 audio";
break;
#if LIBAVCODEC_BUILD >= 4668
/* RealAudio 1.0 */
case VLC_FOURCC('1','4','_','4'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_RA_144;
psz_name = "RealAudio 1.0";
break;
/* RealAudio 2.0 */
case VLC_FOURCC('2','8','_','8'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_RA_288;
psz_name = "RealAudio 2.0";
break;
#endif
/* MPEG Audio layer 1/2/3 */
case VLC_FOURCC('m','p','g','a'):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_MP2;
psz_name = "MPEG Audio layer 1/2";
break;
case VLC_FOURCC('m','p','3',' '):
i_cat = AUDIO_ES;
i_codec = CODEC_ID_MP3;
psz_name = "MPEG Audio layer 1/2/3";
break;
/* A52 Audio (aka AC3) */
case VLC_FOURCC('a','5','2',' '):
case VLC_FOURCC('a','5','2','b'): /* VLC specific hack */
i_cat = AUDIO_ES;
i_codec = CODEC_ID_AC3;
psz_name = "A52 Audio (aka AC3)";
break;
default:
i_cat = UNKNOWN_ES;
i_codec = CODEC_ID_NONE;
......@@ -723,7 +638,34 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
return( VLC_FALSE );
}
void E_ (ffmpeg_InitLibavcodec) ( vlc_object_t *p_object )
int E_(GetFfmpegChroma)( vlc_fourcc_t i_chroma )
{
switch( i_chroma )
{
case VLC_FOURCC( 'I', '4', '2', '0' ):
return PIX_FMT_YUV420P;
case VLC_FOURCC( 'I', '4', '2', '2' ):
return PIX_FMT_YUV422P;
case VLC_FOURCC( 'I', '4', '4', '4' ):
return PIX_FMT_YUV444P;
case VLC_FOURCC( 'R', 'V', '1', '5' ):
return PIX_FMT_RGB555;
case VLC_FOURCC( 'R', 'V', '1', '6' ):
return PIX_FMT_RGB565;
case VLC_FOURCC( 'R', 'V', '2', '4' ):
return PIX_FMT_RGB24;
case VLC_FOURCC( 'R', 'V', '3', '2' ):
return PIX_FMT_RGBA32;
case VLC_FOURCC( 'G', 'R', 'E', 'Y' ):
return PIX_FMT_GRAY8;
case VLC_FOURCC( 'Y', 'U', 'Y', '2' ):
return PIX_FMT_YUV422;
default:
return 0;
}
}
void E_(InitLibavcodec)( vlc_object_t *p_object )
{
vlc_value_t lockval;
......
/*****************************************************************************
* ffmpeg_vdec.h: video decoder using ffmpeg library
* ffmpeg.h: decoder using the ffmpeg library
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ffmpeg.h,v 1.26 2003/10/25 00:49:13 sam Exp $
* $Id: ffmpeg.h,v 1.27 2003/10/27 01:04:38 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -23,214 +23,121 @@
#include "codecs.h" /* BITMAPINFOHEADER */
#define DECODER_THREAD_COMMON \
decoder_fifo_t *p_fifo; \
\
int i_cat; /* AUDIO_ES, VIDEO_ES */ \
int i_codec_id; \
char *psz_namecodec; \
\
AVCodecContext *p_context; \
AVCodec *p_codec; \
mtime_t input_pts_previous; \
mtime_t input_pts; \
mtime_t pts; \
\
/* Private stuff for frame gathering */ \
uint8_t *p_buffer; /* buffer for gather pes */ \
int i_buffer_size; /* size of allocated p_buffer */ \
int i_buffer; /* bytes already present in p_buffer */
typedef struct generic_thread_s
{
DECODER_THREAD_COMMON
} generic_thread_t;
#if LIBAVCODEC_BUILD >= 4663
# define LIBAVCODEC_PP
#else
# undef LIBAVCODEC_PP
#endif
#define FREE( p ) if( p ) free( p ); p = NULL
struct picture_t;
struct AVFrame;
struct AVCodecContext;
struct AVCodec;
int E_( GetPESData )( uint8_t *p_buf, int i_max, pes_packet_t *p_pes );
void E_(InitLibavcodec)( vlc_object_t * );
int E_(GetFfmpegCodec)( vlc_fourcc_t, int *, int *, char ** );
int E_(GetFfmpegChroma)( vlc_fourcc_t );
/*****************************************************************************
* Video codec fourcc
*****************************************************************************/
/* Video decoder module */
int E_( InitVideoDec )( decoder_t *, AVCodecContext *, AVCodec *,
int, char * );
void E_( EndVideoDec ) ( decoder_t * );
int E_( DecodeVideo ) ( decoder_t *, block_t * );
/* MPEG 1/2 video */
#define FOURCC_mpgv VLC_FOURCC('m','p','g','v')
/* MPEG4 video */
#define FOURCC_DIVX VLC_FOURCC('D','I','V','X')
#define FOURCC_divx VLC_FOURCC('d','i','v','x')
#define FOURCC_DIV1 VLC_FOURCC('D','I','V','1')
#define FOURCC_div1 VLC_FOURCC('d','i','v','1')
#define FOURCC_MP4S VLC_FOURCC('M','P','4','S')
#define FOURCC_mp4s VLC_FOURCC('m','p','4','s')
#define FOURCC_M4S2 VLC_FOURCC('M','4','S','2')
#define FOURCC_m4s2 VLC_FOURCC('m','4','s','2')
#define FOURCC_xvid VLC_FOURCC('x','v','i','d')
#define FOURCC_XVID VLC_FOURCC('X','V','I','D')
#define FOURCC_XviD VLC_FOURCC('X','v','i','D')
#define FOURCC_DX50 VLC_FOURCC('D','X','5','0')
#define FOURCC_mp4v VLC_FOURCC('m','p','4','v')
#define FOURCC_4 VLC_FOURCC( 4, 0, 0, 0 )
#define FOURCC_m4cc VLC_FOURCC('m','4','c','c')
#define FOURCC_M4CC VLC_FOURCC('M','4','C','C')
/* MSMPEG4 v2 */
#define FOURCC_MPG4 VLC_FOURCC('M','P','G','4')
#define FOURCC_mpg4 VLC_FOURCC('m','p','g','4')
#define FOURCC_DIV2 VLC_FOURCC('D','I','V','2')
#define FOURCC_div2 VLC_FOURCC('d','i','v','2')
#define FOURCC_MP42 VLC_FOURCC('M','P','4','2')
#define FOURCC_mp42 VLC_FOURCC('m','p','4','2')
/* MSMPEG4 v3 / M$ mpeg4 v3 */
#define FOURCC_MPG3 VLC_FOURCC('M','P','G','3')
#define FOURCC_mpg3 VLC_FOURCC('m','p','g','3')
#define FOURCC_div3 VLC_FOURCC('d','i','v','3')
#define FOURCC_MP43 VLC_FOURCC('M','P','4','3')
#define FOURCC_mp43 VLC_FOURCC('m','p','4','3')
/* DivX 3.20 */
#define FOURCC_DIV3 VLC_FOURCC('D','I','V','3')
#define FOURCC_DIV4 VLC_FOURCC('D','I','V','4')
#define FOURCC_div4 VLC_FOURCC('d','i','v','4')
#define FOURCC_DIV5 VLC_FOURCC('D','I','V','5')
#define FOURCC_div5 VLC_FOURCC('d','i','v','5')
#define FOURCC_DIV6 VLC_FOURCC('D','I','V','6')
#define FOURCC_div6 VLC_FOURCC('d','i','v','6')
/* AngelPotion stuff */
#define FOURCC_AP41 VLC_FOURCC('A','P','4','1')
/* 3ivx doctered divx files */
#define FOURCC_3IVD VLC_FOURCC('3','I','V','D')
#define FOURCC_3ivd VLC_FOURCC('3','i','v','d')
/* 3ivx delta 3.5 Unsupported */
#define FOURCC_3IV1 VLC_FOURCC('3','I','V','1')
#define FOURCC_3iv1 VLC_FOURCC('3','i','v','1')
/* 3ivx delta 4 */
#define FOURCC_3IV2 VLC_FOURCC('3','I','V','2')
#define FOURCC_3iv2 VLC_FOURCC('3','i','v','2')
/* who knows? */
#define FOURCC_3VID VLC_FOURCC('3','V','I','D')
#define FOURCC_3vid VLC_FOURCC('3','v','i','d')
/* H263 and H263i */
/* H263(+) is also known as Real Video 1.0 */
#define FOURCC_H263 VLC_FOURCC('H','2','6','3')
#define FOURCC_h263 VLC_FOURCC('h','2','6','3')
#define FOURCC_U263 VLC_FOURCC('U','2','6','3')
#define FOURCC_I263 VLC_FOURCC('I','2','6','3')
#define FOURCC_i263 VLC_FOURCC('i','2','6','3')
/* Flash (H263) variant */
#define FOURCC_FLV1 VLC_FOURCC('F','L','V','1')
/* Sorenson v1/3 */
#define FOURCC_SVQ1 VLC_FOURCC('S','V','Q','1')
#define FOURCC_SVQ3 VLC_FOURCC('S','V','Q','3')
/* mjpeg */
#define FOURCC_MJPG VLC_FOURCC( 'M', 'J', 'P', 'G' )
#define FOURCC_mjpg VLC_FOURCC( 'm', 'j', 'p', 'g' )
/* for mov file */
#define FOURCC_mjpa VLC_FOURCC( 'm', 'j', 'p', 'a' )
/* for mov file XXX: untested */
#define FOURCC_mjpb VLC_FOURCC( 'm', 'j', 'p', 'b' )
#define FOURCC_jpeg VLC_FOURCC( 'j', 'p', 'e', 'g' )
#define FOURCC_JPEG VLC_FOURCC( 'J', 'P', 'E', 'G' )
#define FOURCC_JFIF VLC_FOURCC( 'J', 'F', 'I', 'F' )
#define FOURCC_JPGL VLC_FOURCC( 'J', 'P', 'G', 'L' )
/* Microsoft Video 1 */
#define FOURCC_MSVC VLC_FOURCC('M','S','V','C')
#define FOURCC_msvc VLC_FOURCC('m','s','v','c')
#define FOURCC_CRAM VLC_FOURCC('C','R','A','M')
#define FOURCC_cram VLC_FOURCC('c','r','a','m')
#define FOURCC_WHAM VLC_FOURCC('W','H','A','M')
#define FOURCC_wham VLC_FOURCC('w','h','a','m')
/* Windows Screen Video */
#define FOURCC_MSS1 VLC_FOURCC('M','S','S','1')
/* Microsoft RLE */
#define FOURCC_mrle VLC_FOURCC('m','r','l','e')
#define FOURCC_1000 VLC_FOURCC(0x1,0x0,0x0,0x0)
/* Windows Media Video */
#define FOURCC_WMV1 VLC_FOURCC('W','M','V','1')
#define FOURCC_WMV2 VLC_FOURCC('W','M','V','2')
/* DV */
#define FOURCC_dvsl VLC_FOURCC('d','v','s','l')
#define FOURCC_dvsd VLC_FOURCC('d','v','s','d')
#define FOURCC_DVSD VLC_FOURCC('D','V','S','D')
#define FOURCC_dvhd VLC_FOURCC('d','v','h','d')
#define FOURCC_dvc VLC_FOURCC('d','v','c',' ')
#define FOURCC_dvp VLC_FOURCC('d','v','p',' ')
#define FOURCC_CDVC VLC_FOURCC('C','D','V','C')
/* Indeo Video Codecs */
#define FOURCC_IV31 VLC_FOURCC('I','V','3','1')
#define FOURCC_iv31 VLC_FOURCC('i','v','3','1')
#define FOURCC_IV32 VLC_FOURCC('I','V','3','2')
#define FOURCC_iv32 VLC_FOURCC('i','v','3','2')
/* On2 VP3 Video Codecs */
#define FOURCC_VP31 VLC_FOURCC('V','P','3','1')
#define FOURCC_vp31 VLC_FOURCC('v','p','3','1')
/* Asus Video */
#define FOURCC_ASV1 VLC_FOURCC('A','S','V','1')
#define FOURCC_ASV2 VLC_FOURCC('A','S','V','2')
/* ATI VCR1 */
#define FOURCC_VCR1 VLC_FOURCC('V','C','R','1')
/* FFMPEG Video 1 (lossless codec) */
#define FOURCC_FFV1 VLC_FOURCC('F','F','V','1')
/* Cirrus Logic AccuPak */
#define FOURCC_CLJR VLC_FOURCC('C','L','J','R')
/* Creative YUV */
#define FOURCC_CYUV VLC_FOURCC('C','Y','U','V')
/* Huff YUV */
#define FOURCC_HFYU VLC_FOURCC('H','F','Y','U')
/* Apple Video */
#define FOURCC_rpza VLC_FOURCC('r','p','z','a')
/* Cinepak */
#define FOURCC_cvid VLC_FOURCC('c','v','i','d')
/* Audio decoder module */
int E_( InitAudioDec )( decoder_t *, AVCodecContext *, AVCodec *,
int, char * );
void E_( EndAudioDec ) ( decoder_t * );
int E_( DecodeAudio ) ( decoder_t *, block_t * );
/* Chroma conversion module */
int E_(OpenChroma)( vlc_object_t * );
/*****************************************************************************
* Audio codec fourcc
*****************************************************************************/
#define FOURCC_WMA1 VLC_FOURCC('W','M','A','1')
#define FOURCC_wma1 VLC_FOURCC('w','m','a','1')
#define FOURCC_WMA2 VLC_FOURCC('W','M','A','2')
#define FOURCC_wma2 VLC_FOURCC('w','m','a','2')
#define FOURCC_dvau VLC_FOURCC('d','v','a','u')
/* Video encoder module */
int E_(OpenVideoEncoder) ( vlc_object_t * );
void E_(CloseVideoEncoder)( vlc_object_t * );
#define FOURCC_MAC3 VLC_FOURCC('M','A','C','3')
#define FOURCC_MAC6 VLC_FOURCC('M','A','C','6')
/* Audio encoder module */
int E_(OpenAudioEncoder) ( vlc_object_t * );
void E_(CloseAudioEncoder)( vlc_object_t * );
#define FOURCC_RA10 VLC_FOURCC('1','4','_','4')
#define FOURCC_RA20 VLC_FOURCC('2','8','_','8')
/* Postprocessing module */
int E_(OpenPostproc)( decoder_t *, void ** );
int E_(InitPostproc)( decoder_t *, void *, int, int, int );
int E_(PostprocPict)( decoder_t *, void *, picture_t *, AVFrame * );
void E_(ClosePostproc)( decoder_t *, void * );
/*****************************************************************************
* Module descriptor help strings
*****************************************************************************/
#define DR_TEXT N_("Direct rendering")
#define ERROR_TEXT N_("Error resilience")
#define ERROR_LONGTEXT N_( \
"ffmpeg can make errors resiliences. \n" \
"Nevertheless, with a buggy encoder (like ISO MPEG-4 encoder from M$) " \
"this will produce a lot of errors.\n" \
"Valid range is -1 to 99 (-1 disables all errors resiliences).")
#define BUGS_TEXT N_("Workaround bugs")
#define BUGS_LONGTEXT N_( \
"Try to fix some bugs\n" \
"1 autodetect\n" \
"2 old msmpeg4\n" \
"4 xvid interlaced\n" \
"8 ump4 \n" \
"16 no padding\n" \
"32 ac vlc\n" \
"64 Qpel chroma")
#define HURRYUP_TEXT N_("Hurry up")
#define HURRYUP_LONGTEXT N_( \
"Allow the decoder to partially decode or skip frame(s) " \
"when there is not enough time. It's useful with low CPU power " \
"but it can produce distorted pictures.")
#define TRUNC_TEXT N_("Truncated stream")
#define TRUNC_LONGTEXT N_("truncated stream -1:auto,0:disable,:1:enable")
#define PP_Q_TEXT N_("Post processing quality")
#define PP_Q_LONGTEXT N_( \
"Quality of post processing. Valid range is 0 to 6\n" \
"Higher levels require considerable more CPU power, but produce " \
"better looking pictures." )
#define LIBAVCODEC_PP_TEXT N_("Ffmpeg postproc filter chains")
/* FIXME (cut/past from ffmpeg */
#define LIBAVCODEC_PP_LONGTEXT \
"<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n" \
"long form example:\n" \
"vdeblock:autoq/hdeblock:autoq/linblenddeint default,-vdeblock\n" \
"short form example:\n" \
"vb:a/hb:a/lb de,-vb\n" \
"more examples:\n" \
"tn:64:128:256\n" \
"Filters Options\n" \
"short long name short long option Description\n" \
"* * a autoq cpu power dependant enabler\n" \
" c chrom chrominance filtring enabled\n" \
" y nochrom chrominance filtring disabled\n" \
"hb hdeblock (2 Threshold) horizontal deblocking filter\n" \
" 1. difference factor: default=64, higher -> more deblocking\n" \
" 2. flatness threshold: default=40, lower -> more deblocking\n" \
" the h & v deblocking filters share these\n" \
" so u cant set different thresholds for h / v\n" \
"vb vdeblock (2 Threshold) vertical deblocking filter\n" \
"h1 x1hdeblock Experimental h deblock filter 1\n" \
"v1 x1vdeblock Experimental v deblock filter 1\n" \
"dr dering Deringing filter\n" \
"al autolevels automatic brightness / contrast\n" \
" f fullyrange stretch luminance to (0..255)\n" \
"lb linblenddeint linear blend deinterlacer\n" \
"li linipoldeint linear interpolating deinterlace\n" \
"ci cubicipoldeint cubic interpolating deinterlacer\n" \
"md mediandeint median deinterlacer\n" \
"fd ffmpegdeint ffmpeg deinterlacer\n" \
"de default hb:a,vb:a,dr:a,al\n" \
"fa fast h1:a,v1:a,dr:a,al\n" \
"tn tmpnoise (3 Thresholds) Temporal Noise Reducer\n" \
" 1. <= 2. <= 3. larger -> stronger filtering\n" \
"fq forceQuant <quantizer> Force quantizer\n"
/*****************************************************************************
* postprocess.c: video postprocessing using the ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: postprocess.c,v 1.1 2003/10/27 01:04:38 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.
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
/* ffmpeg header */
#ifdef HAVE_FFMPEG_AVCODEC_H
# include <ffmpeg/avcodec.h>
#else
# include <avcodec.h>
#endif
#include "ffmpeg.h"
#ifdef LIBAVCODEC_PP
#ifdef HAVE_POSTPROC_POSTPROCESS_H
# include <postproc/postprocess.h>
#else
# include <libpostproc/postprocess.h>
#endif
/*****************************************************************************
* video_postproc_sys_t : ffmpeg video postprocessing descriptor
*****************************************************************************/
typedef struct video_postproc_sys_t
{
pp_context_t *pp_context;
pp_mode_t *pp_mode;
int i_width;
int i_height;
} video_postproc_sys_t;
/*****************************************************************************
* OpenPostproc: probe and open the postproc
*****************************************************************************/
int E_(OpenPostproc)( decoder_t *p_dec, void **pp_data )
{
video_postproc_sys_t **pp_sys = (video_postproc_sys_t **)pp_data;
pp_mode_t *pp_mode;
vlc_value_t val;
/* ***** Load post processing if enabled ***** */
var_Create( p_dec, "ffmpeg-pp-q", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Get( p_dec, "ffmpeg-pp-q", &val );
if( val.i_int > 0 )
{
int i_quality = val.i_int;
char *psz_name = config_GetPsz( p_dec, "ffmpeg-pp-name" );
if( !psz_name )
{
psz_name = strdup( "default" );
}
else if( *psz_name == '\0' )
{
free( psz_name );
psz_name = strdup( "default" );
}
pp_mode = pp_get_mode_by_name_and_quality( psz_name, i_quality );
if( !pp_mode )
{
msg_Err( p_dec, "failed geting mode for postproc" );
}
else
{
msg_Info( p_dec, "postprocessing activated" );
}
free( psz_name );
*pp_sys = malloc( sizeof(video_postproc_sys_t) );
(*pp_sys)->pp_context = NULL;
(*pp_sys)->pp_mode = NULL;
return VLC_SUCCESS;
}
else
{
msg_Dbg( p_dec, "no postprocessing enabled" );
return VLC_EGENERIC;
}
}
/*****************************************************************************
* InitPostproc:
*****************************************************************************/
int E_(InitPostproc)( decoder_t *p_dec, void *p_data,
int i_width, int i_height, int pix_fmt )
{
video_postproc_sys_t *p_sys = (video_postproc_sys_t *)p_data;
int32_t i_cpu = p_dec->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( 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_sys->pp_context = pp_get_context( i_width, i_height, i_flags );
p_sys->i_width = i_width;
p_sys->i_height = i_height;
return VLC_SUCCESS;
}
/*****************************************************************************
* PostprocPict:
*****************************************************************************/
int E_(PostprocPict)( decoder_t *p_dec, void *p_data,
picture_t *p_pic, AVFrame *p_ff_pic )
{
video_postproc_sys_t *p_sys = (video_postproc_sys_t *)p_data;
uint8_t *src[3], *dst[3];
int i_plane, i_src_stride[3], i_dst_stride[3];
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
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;
}
pp_postprocess( src, i_src_stride, dst, i_dst_stride,
p_sys->i_width, p_sys->i_height,
p_ff_pic->qscale_table, p_ff_pic->qstride,
p_sys->pp_mode, p_sys->pp_context,
p_ff_pic->pict_type );
return VLC_SUCCESS;
}
/*****************************************************************************
* ClosePostproc:
*****************************************************************************/
void E_(ClosePostproc)( decoder_t *p_dec, void *p_data )
{
video_postproc_sys_t *p_sys = (video_postproc_sys_t *)p_data;
if( p_sys && p_sys->pp_mode )
{
pp_free_mode( p_sys->pp_mode );
if( p_sys->pp_context ) pp_free_context( p_sys->pp_context );
}
}
#endif /* LIBAVCODEC_PP */
/*****************************************************************************
* video.c: video decoder using ffmpeg library
* video.c: video decoder using the ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: video.c,v 1.41 2003/10/21 18:33:53 gbazin Exp $
* $Id: video.c,v 1.42 2003/10/27 01:04:38 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
......@@ -26,15 +26,13 @@
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#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
......@@ -48,26 +46,55 @@
#include "ffmpeg.h"
#ifdef LIBAVCODEC_PP
# ifdef HAVE_POSTPROC_POSTPROCESS_H
# include <postproc/postprocess.h>
# else
# include <libpostproc/postprocess.h>
# endif
#else
# include "postprocessing/postprocessing.h"
#endif
/*****************************************************************************
* decoder_sys_t : decoder descriptor
*****************************************************************************/
struct decoder_sys_t
{
/* Common part between video and audio decoder */
int i_cat;
int i_codec_id;
char *psz_namecodec;
AVCodecContext *p_context;
AVCodec *p_codec;
/* Video decoder specific part */
mtime_t input_pts;
mtime_t i_pts;
#include "video.h"
AVFrame *p_ff_pic;
BITMAPINFOHEADER *p_format;
vout_thread_t *p_vout;
/* for frame skipping algo */
int b_hurry_up;
int i_frame_error;
int i_frame_skip;
/* how many decoded frames are late */
int i_late_frames;
mtime_t i_late_frames_start;
/* for direct rendering */
int b_direct_rendering;
vlc_bool_t b_has_b_frames;
int i_buffer;
char *p_buffer;
/* Postprocessing handle */
void *p_pp;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void ffmpeg_CopyPicture( picture_t *, AVFrame *, vdec_thread_t * );
static void ffmpeg_CopyPicture ( decoder_t *, picture_t *, AVFrame * );
static int ffmpeg_GetFrameBuf ( struct AVCodecContext *, AVFrame * );
static void ffmpeg_ReleaseFrameBuf ( struct AVCodecContext *, AVFrame * );
static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * );
/*****************************************************************************
* Local Functions
......@@ -82,7 +109,6 @@ static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
return( VLC_FOURCC('I','4','2','0') );
case PIX_FMT_RGB24:
return( VLC_FOURCC('R','V','2','4') );
case PIX_FMT_YUV422P:
return( VLC_FOURCC('I','4','2','2') );
case PIX_FMT_YUV444P:
......@@ -91,12 +117,12 @@ static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
case PIX_FMT_YUV411P:
case PIX_FMT_BGR24:
default:
return( 0 );
return 0;
}
}
/* Return a Vout */
static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t *p_vdec,
static vout_thread_t *ffmpeg_CreateVout( decoder_t *p_dec,
AVCodecContext *p_context )
{
vout_thread_t *p_vout;
......@@ -129,577 +155,402 @@ static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t *p_vdec,
/* 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. */
p_vout = vout_Request( p_vdec->p_fifo, p_vdec->p_vout,
p_vout = vout_Request( p_dec, p_dec->p_sys->p_vout,
i_width, i_height, i_chroma, i_aspect );
#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 );
}
#ifdef LIBAVCODEC_PP
if( p_dec->p_sys->p_pp )
E_(InitPostproc)( p_dec, p_dec->p_sys->p_pp, i_width, i_height,
p_context->pix_fmt );
#endif
return p_vout;
}
/*****************************************************************************
*
* 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
* InitVideo: initialize the video decoder
*****************************************************************************
* 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
* flag are not modified inside this function.
*
* ffmpeg codec will be open, some memory allocated. But Vout is not yet
* open (done after the first decoded frame)
* the ffmpeg codec will be opened, some memory allocated. The vout is not yet
* opened (done after the first decoded frame).
*****************************************************************************/
static inline void SetDWBE( void *data, uint32_t dw )
{
uint8_t *p = data;
p[0] = (dw >> 24 )&0xff;
p[1] = (dw >> 16 )&0xff;
p[2] = (dw >> 8 )&0xff;
p[3] = (dw )&0xff;
}
int E_( InitThread_Video )( vdec_thread_t *p_vdec )
int E_(InitVideoDec)( decoder_t *p_dec, AVCodecContext *p_context,
AVCodec *p_codec, int i_codec_id, char *psz_namecodec )
{
decoder_sys_t *p_sys;
vlc_value_t val;
int i_tmp;
int i_truncated;
p_vdec->p_ff_pic = avcodec_alloc_frame();
/* Allocate the memory needed to store the decoder's structure */
if( ( p_dec->p_sys = p_sys =
(decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
{
msg_Err( p_dec, "out of memory" );
return VLC_EGENERIC;
}
p_dec->p_sys->p_context = p_context;
p_dec->p_sys->p_codec = p_codec;
p_dec->p_sys->i_codec_id = i_codec_id;
p_dec->p_sys->psz_namecodec = psz_namecodec;
p_sys->p_ff_pic = avcodec_alloc_frame();
if( ( p_vdec->p_format =
(BITMAPINFOHEADER *)p_vdec->p_fifo->p_bitmapinfoheader ) != NULL )
if( ( p_sys->p_format =
(BITMAPINFOHEADER *)p_dec->p_fifo->p_bitmapinfoheader ) != NULL )
{
/* ***** 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;
p_sys->p_context->width = p_sys->p_format->biWidth;
p_sys->p_context->height = p_sys->p_format->biHeight;
}
else
{
msg_Warn( p_vdec->p_fifo, "display informations missing" );
p_vdec->p_format = NULL;
msg_Warn( p_dec, "display informations missing" );
p_sys->p_format = NULL;
}
/* ***** 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 );
if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
{
p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
}
i_tmp = config_GetInt( p_dec, "ffmpeg-workaround-bugs" );
p_sys->p_context->workaround_bugs = __MAX( __MIN( i_tmp, 99 ), 0 );
p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
i_tmp = config_GetInt( p_dec, "ffmpeg-error-resilience" );
p_sys->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
/* CODEC_FLAG_TRUNCATED */
var_Create( p_dec, "grayscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Get( p_dec, "grayscale", &val );
if( val.b_bool ) p_sys->p_context->flags |= CODEC_FLAG_GRAY;
/* FIXME search real LIBAVCODEC_BUILD */
/* Decide if we set CODEC_FLAG_TRUNCATED */
#if LIBAVCODEC_BUILD >= 4662
i_truncated = config_GetInt( p_vdec->p_fifo, "ffmpeg-truncated" );
if( i_truncated == 1 )
#if 0
||
( i_truncated == -1 && ( p_vdec->p_context->width == 0 || p_vdec->p_context->height == 0 ) ) )
#endif
{
p_vdec->p_context->flags |= CODEC_FLAG_TRUNCATED;
}
var_Create( p_dec, "ffmpeg-truncated", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
var_Get( p_dec, "ffmpeg-truncated", &val );
if( val.i_int > 0 ) p_sys->p_context->flags |= CODEC_FLAG_TRUNCATED;
#endif
/* ***** Open the codec ***** */
if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
if( avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0 )
{
msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
p_vdec->psz_namecodec );
return( VLC_EGENERIC );
msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
return VLC_EGENERIC;
}
else
{
msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
p_vdec->psz_namecodec );
msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->psz_namecodec );
}
p_vdec->b_direct_rendering = 0;
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 ) &&
/* ***** ffmpeg frame skipping ***** */
var_Create( p_dec, "ffmpeg-hurry-up", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Get( p_dec, "ffmpeg-hurry-up", &val );
p_sys->b_hurry_up = val.b_bool;
/* ***** ffmpeg direct rendering ***** */
p_sys->b_direct_rendering = 0;
var_Create( p_dec, "ffmpeg-dr", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Get( p_dec, "ffmpeg-dr", &val );
if( val.b_bool && (p_sys->p_codec->capabilities & CODEC_CAP_DR1) &&
ffmpeg_PixFmtToChroma( p_sys->p_context->pix_fmt ) &&
/* Apparently direct rendering doesn't work with YUV422P */
p_vdec->p_context->pix_fmt != PIX_FMT_YUV422P &&
!(p_vdec->p_context->width % 16) && !(p_vdec->p_context->height % 16) )
p_sys->p_context->pix_fmt != PIX_FMT_YUV422P &&
!(p_sys->p_context->width % 16) && !(p_sys->p_context->height % 16) )
{
/* Some codecs set pix_fmt only after the 1st frame has been decoded,
* so we need to do another check in ffmpeg_GetFrameBuf() */
p_vdec->b_direct_rendering = 1;
p_sys->b_direct_rendering = 1;
}
/* ***** Load post processing ***** */
#ifdef LIBAVCODEC_PP
p_vdec->pp_context = NULL;
p_vdec->pp_mode = NULL;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )
if( E_(OpenPostproc)( p_dec, &p_sys->p_pp ) == VLC_SUCCESS )
{
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" );
}
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 );
/* for now we cannot do postproc and dr */
p_vdec->b_direct_rendering = 0;
}
else
{
msg_Dbg( p_vdec->p_fifo, "no postproc" );
p_sys->b_direct_rendering = 0;
}
#endif
/* ffmpeg doesn't properly release old pictures when frames are skipped */
if( p_vdec->b_hurry_up ) p_vdec->b_direct_rendering = 0;
if( p_sys->b_hurry_up ) p_sys->b_direct_rendering = 0;
if( p_sys->b_direct_rendering )
{
msg_Dbg( p_dec, "using direct rendering" );
p_sys->p_context->flags |= CODEC_FLAG_EMU_EDGE;
}
/* Always use our get_buffer wrapper so we can calculate the
* PTS correctly */
p_vdec->p_context->get_buffer = ffmpeg_GetFrameBuf;
p_vdec->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
p_vdec->p_context->opaque = p_vdec;
if( p_vdec->b_direct_rendering )
{
msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
p_vdec->p_context->flags |= CODEC_FLAG_EMU_EDGE;
}
p_sys->p_context->get_buffer = ffmpeg_GetFrameBuf;
p_sys->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
p_sys->p_context->opaque = p_dec;
/* ***** init this codec with special data ***** */
if( p_vdec->p_format &&
p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
if( p_sys->p_format && p_sys->p_format->biSize > sizeof(BITMAPINFOHEADER) )
{
int b_gotpicture;
int i_size = p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
int i_size = p_sys->p_format->biSize - sizeof(BITMAPINFOHEADER);
if( p_vdec->i_codec_id == CODEC_ID_MPEG4 )
if( p_sys->i_codec_id == CODEC_ID_MPEG4 )
{
uint8_t *p_vol = malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
memcpy( p_vol, &p_vdec->p_format[1], i_size );
memcpy( p_vol, &p_sys->p_format[1], i_size );
memset( &p_vol[i_size], 0, FF_INPUT_BUFFER_PADDING_SIZE );
avcodec_decode_video( p_vdec->p_context, p_vdec->p_ff_pic,
&b_gotpicture,
p_vol,
i_size );
avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic,
&b_gotpicture, p_vol, i_size );
free( p_vol );
}
#if LIBAVCODEC_BUILD >= 4666
else if( p_vdec->i_codec_id == CODEC_ID_SVQ3 )
else if( p_sys->i_codec_id == CODEC_ID_SVQ3 )
{
uint8_t *p;
p_vdec->p_context->extradata_size = i_size + 12;
p = p_vdec->p_context->extradata =
malloc( p_vdec->p_context->extradata_size );
p_sys->p_context->extradata_size = i_size + 12;
p = p_sys->p_context->extradata =
malloc( p_sys->p_context->extradata_size );
memcpy( &p[0], "SVQ3", 4 );
memset( &p[4], 0, 8 );
memcpy( &p[12], &p_vdec->p_format[1], i_size );
memcpy( &p[12], &p_sys->p_format[1], i_size );
}
#endif
else
{
p_vdec->p_context->extradata_size = i_size;
p_vdec->p_context->extradata =
p_sys->p_context->extradata_size = i_size;
p_sys->p_context->extradata =
malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
memcpy( p_vdec->p_context->extradata,
&p_vdec->p_format[1], i_size );
memset( &((uint8_t*)p_vdec->p_context->extradata)[i_size],
memcpy( p_sys->p_context->extradata,
&p_sys->p_format[1], i_size );
memset( &((uint8_t*)p_sys->p_context->extradata)[i_size],
0, FF_INPUT_BUFFER_PADDING_SIZE );
}
}
p_vdec->p_vout = NULL;
p_vdec->input_pts_previous = 0;
p_vdec->input_pts = 0;
p_vdec->b_has_b_frames = VLC_FALSE;
/* ***** misc init ***** */
p_sys->p_vout = NULL;
p_sys->input_pts = 0;
p_sys->i_pts = 0;
p_sys->b_has_b_frames = VLC_FALSE;
p_sys->i_late_frames = 0;
p_sys->i_buffer = 1;
p_sys->p_buffer = malloc( p_sys->i_buffer );
p_sys->p_pp = NULL;
return( VLC_SUCCESS );
return VLC_SUCCESS;
}
/*****************************************************************************
* DecodeThread: Called to decode one frame
*****************************************************************************
* We have to get a frame stored in a pes, give it to ffmpeg decoder and send
* the image to the output.
* DecodeVideo: Called to decode one or more frames
*****************************************************************************/
void E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
int E_(DecodeVideo)( decoder_t *p_dec, block_t *p_block )
{
pes_packet_t *p_pes;
int i_frame_size;
int i_used;
int b_drawpicture;
int b_gotpicture;
picture_t *p_pic; /* vlc picture */
decoder_sys_t *p_sys = p_dec->p_sys;
int i_buffer, b_drawpicture;
char *p_buffer;
if( p_block->i_pts > 0 )
{
p_sys->input_pts = p_block->i_pts;
}
/* TODO implement it in a better way */
/* A good idea could be to decode all I pictures and see for the other */
if( p_vdec->b_hurry_up && p_vdec->i_frame_late > 4 )
if( p_sys->b_hurry_up && p_sys->i_late_frames > 4 )
{
b_drawpicture = 0;
if( p_vdec->i_frame_late < 8 )
if( p_sys->i_late_frames < 8 )
{
p_vdec->p_context->hurry_up = 2;
p_sys->p_context->hurry_up = 2;
}
else
{
/* too much late picture, won't decode
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;
/* picture too late, won't decode
* but break picture until a new I, and for mpeg4 ...*/
p_sys->i_late_frames--; /* needed else it will never be decrease */
block_Release( p_block );
return VLC_SUCCESS;
}
}
else
{
b_drawpicture = 1;
p_vdec->p_context->hurry_up = 0;
}
if( p_vdec->i_frame_late > 0 &&
mdate() - p_vdec->i_frame_late_start > (mtime_t)5000000 )
{
msg_Err( p_vdec->p_fifo, "more than 5 seconds of late video -> "
"dropping (to slow computer ?)" );
do
{
input_ExtractPES( p_vdec->p_fifo, &p_pes );
if( !p_pes )
{
p_vdec->p_fifo->b_error = 1;
return;
p_sys->p_context->hurry_up = 0;
}
if( p_pes->i_pts > 0 )
if( p_sys->i_late_frames > 0 &&
mdate() - p_sys->i_late_frames_start > I64C(5000000) )
{
p_vdec->input_pts_previous = p_vdec->input_pts;
p_vdec->input_pts = p_pes->i_pts;
}
input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
} while( p_vdec->input_pts <= 0 || p_vdec->input_pts < mdate() );
msg_Err( p_dec, "more than 5 seconds of late video -> "
"dropping frame (computer too slow ?)" );
block_Release( p_block );
p_sys->i_pts = 0; /* To make sure we recover properly */
p_sys->i_late_frames--;
return VLC_SUCCESS;
}
if( !p_vdec->p_context->width || !p_vdec->p_context->height )
if( !p_sys->p_context->width || !p_sys->p_context->height )
{
p_vdec->p_context->hurry_up = 5;
p_sys->p_context->hurry_up = 5;
}
do
{
input_ExtractPES( p_vdec->p_fifo, &p_pes );
if( !p_pes )
{
p_vdec->p_fifo->b_error = 1;
return;
}
/*
* Do the actual decoding now
*/
if( p_pes->i_pts > 0 )
{
p_vdec->input_pts_previous = p_vdec->input_pts;
p_vdec->input_pts = p_pes->i_pts;
}
i_frame_size = p_pes->i_pes_size;
if( i_frame_size > 0 )
{
uint8_t *p_last;
int i_need;
/* XXX Don't forget that ffmpeg required a little more bytes
/* Don't forget that ffmpeg requires a little more bytes
* that the real frame size */
i_need = i_frame_size + FF_INPUT_BUFFER_PADDING_SIZE + p_vdec->i_buffer;
if( p_vdec->i_buffer_size < i_need)
{
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 )
i_buffer = p_block->i_buffer;
if( i_buffer + FF_INPUT_BUFFER_PADDING_SIZE > p_sys->i_buffer )
{
memcpy( p_vdec->p_buffer, p_last, p_vdec->i_buffer );
}
FREE( p_last );
free( p_sys->p_buffer );
p_sys->p_buffer = malloc( i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
}
i_frame_size =
E_( GetPESData )( p_vdec->p_buffer + p_vdec->i_buffer,
i_frame_size , p_pes );
memset( p_vdec->p_buffer + p_vdec->i_buffer + i_frame_size,
0, FF_INPUT_BUFFER_PADDING_SIZE );
}
input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
p_buffer = p_sys->p_buffer;
p_dec->p_vlc->pf_memcpy( p_buffer, p_block->p_buffer, p_block->i_buffer );
memset( p_buffer + i_buffer, 0, FF_INPUT_BUFFER_PADDING_SIZE );
} while( i_frame_size <= 0 );
i_frame_size += p_vdec->i_buffer;
while( i_buffer )
{
int i_used, b_gotpicture;
picture_t *p_pic;
usenextdata:
i_used = avcodec_decode_video( p_vdec->p_context,
p_vdec->p_ff_pic,
i_used = avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic,
&b_gotpicture,
p_vdec->p_buffer,
i_frame_size );
if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error ) return;
#if 0
msg_Dbg( p_vdec->p_fifo,
"used:%d framesize:%d (%s picture)",
i_used, i_frame_size, b_gotpicture ? "got":"no got" );
#endif
p_buffer, i_buffer );
if( i_used < 0 )
{
msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
i_frame_size );
p_vdec->i_frame_error++;
p_vdec->i_buffer = 0;
return;
msg_Warn( p_dec, "cannot decode one frame (%d bytes)", i_buffer );
p_sys->i_frame_error++;
block_Release( p_block );
return VLC_SUCCESS;
}
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 );
p_vdec->i_buffer = i_frame_size - i_used;
}
else
{
p_vdec->i_buffer = 0;
}
/* Consumed bytes */
i_buffer -= i_used;
p_buffer += i_used;
/* consumed bytes */
i_frame_size -= i_used;
/* Nothing to display */
if( !b_gotpicture ) continue;
/* Update frame late count*/
if( p_vdec->pts <= mdate() )
if( p_sys->i_pts && p_sys->i_pts <= mdate() )
{
p_vdec->i_frame_late++;
if( p_vdec->i_frame_late == 1 )
{
p_vdec->i_frame_late_start = mdate();
}
p_sys->i_late_frames++;
if( p_sys->i_late_frames == 1 )
p_sys->i_late_frames_start = mdate();
}
else
{
p_vdec->i_frame_late = 0;
p_sys->i_late_frames = 0;
}
if( !b_gotpicture || p_vdec->p_ff_pic->linesize[0] == 0 || !b_drawpicture )
if( !b_drawpicture || p_sys->p_ff_pic->linesize[0] == 0 )
{
return;
/* Do not display the picture */
continue;
}
if( !p_vdec->b_direct_rendering )
if( !p_sys->b_direct_rendering )
{
p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
if( !p_vdec->p_vout )
p_sys->p_vout = ffmpeg_CreateVout( p_dec, p_sys->p_context );
if( !p_sys->p_vout )
{
msg_Err( p_vdec->p_fifo, "cannot create vout" );
p_vdec->p_fifo->b_error = 1; /* abort */
return;
msg_Err( p_dec, "cannot create vout" );
block_Release( p_block );
return VLC_EGENERIC;
}
/* Get a new picture */
while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
{
if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )
{
return;
block_Release( p_block );
return VLC_EGENERIC;
}
msleep( VOUT_OUTMEM_SLEEP );
}
/* fill p_picture_t from AVVideoFrame and do chroma conversion
/* Fill p_picture_t from AVVideoFrame and do chroma conversion
* if needed */
ffmpeg_CopyPicture( p_pic, p_vdec->p_ff_pic, p_vdec );
ffmpeg_CopyPicture( p_dec, p_pic, p_sys->p_ff_pic );
}
else
{
p_pic = (picture_t *)p_vdec->p_ff_pic->opaque;
p_pic = (picture_t *)p_sys->p_ff_pic->opaque;
}
/* Set the PTS
* There is an ugly hack here because some demuxers pass us a dts instead
* of a pts so this screw up things for streams with B frames. */
if( p_vdec->p_ff_pic->pict_type == FF_B_TYPE )
p_vdec->b_has_b_frames = VLC_TRUE;
if( p_vdec->p_ff_pic->pts &&
( !p_vdec->p_context->has_b_frames || !p_vdec->b_has_b_frames ||
p_vdec->p_ff_pic->pict_type == FF_B_TYPE ) )
* There is an ugly hack here because some demuxers pass us a dts
* instead of a pts so this screw up things for streams with
* B frames. */
if( p_sys->p_ff_pic->pict_type == FF_B_TYPE )
p_sys->b_has_b_frames = VLC_TRUE;
if( p_sys->p_ff_pic->pts &&
( !p_sys->p_context->has_b_frames || !p_sys->b_has_b_frames ||
p_sys->p_ff_pic->pict_type == FF_B_TYPE ) )
{
p_vdec->pts = p_vdec->p_ff_pic->pts;
}
if( p_vdec->pts <= 0 )
{
p_vdec->pts = mdate() + DEFAULT_PTS_DELAY; // FIXME
p_sys->i_pts = p_sys->p_ff_pic->pts;
}
/* Send decoded frame to vout */
vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->pts );
vout_DisplayPicture( p_vdec->p_vout, p_pic );
if( p_sys->i_pts )
{
vout_DatePicture( p_sys->p_vout, p_pic, p_sys->i_pts );
vout_DisplayPicture( p_sys->p_vout, p_pic );
/* interpolate the next PTS */
if( p_vdec->p_context->frame_rate > 0 )
if( p_sys->p_context->frame_rate > 0 )
{
p_vdec->pts += I64C(1000000) * (2 + p_vdec->p_ff_pic->repeat_pict) *
p_vdec->p_context->frame_rate_base /
(2 * p_vdec->p_context->frame_rate);
p_sys->i_pts += I64C(1000000) *
(2 + p_sys->p_ff_pic->repeat_pict) *
p_sys->p_context->frame_rate_base /
(2 * p_sys->p_context->frame_rate);
}
if( i_frame_size > 0 )
{
goto usenextdata; /* try to use all data */
}
}
block_Release( p_block );
return VLC_SUCCESS;
}
/*****************************************************************************
* EndThread: thread destruction
* EndVideo: decoder destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
void E_( EndThread_Video )( vdec_thread_t *p_vdec )
void E_(EndVideoDec)( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
if( p_sys->p_ff_pic ) free( p_sys->p_ff_pic );
#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 );
}
}
E_(ClosePostproc)( p_dec, p_sys->p_pp );
#endif
if( p_vdec->p_ff_pic )
{
free( p_vdec->p_ff_pic );
}
free( p_sys->p_buffer );
/* 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 );
vout_Request( p_dec, p_sys->p_vout, 0, 0, 0, 0 );
}
/*****************************************************************************
* ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
* picture_t structure (when not in direct rendering mode).
*****************************************************************************/
static void ffmpeg_CopyPicture( picture_t *p_pic,
AVFrame *p_ff_pic,
vdec_thread_t *p_vdec )
static void ffmpeg_CopyPicture( decoder_t *p_dec,
picture_t *p_pic, AVFrame *p_ff_pic )
{
int i_plane;
int i_size;
int i_line;
decoder_sys_t *p_sys = p_dec->p_sys;
uint8_t *p_dst;
uint8_t *p_src;
int i_src_stride;
int i_dst_stride;
if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
if( ffmpeg_PixFmtToChroma( p_sys->p_context->pix_fmt ) )
{
#ifdef LIBAVCODEC_PP
if( p_vdec->pp_mode && p_vdec->pp_context )
{
uint8_t *src[3], *dst[3];
int i_src_stride[3], i_dst_stride[3];
if( p_sys->p_pp )
E_(PostprocPict)( p_dec, p_sys->p_pp, p_pic, p_ff_pic );
#else
int i_plane, i_size, i_line;
uint8_t *p_dst, *p_src;
int i_src_stride, i_dst_stride;
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
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;
}
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 );
}
else
{
#endif
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
p_src = p_ff_pic->data[i_plane];
......@@ -710,23 +561,21 @@ static void ffmpeg_CopyPicture( picture_t *p_pic,
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_dec->p_vlc->pf_memcpy( p_dst, p_src, i_size );
p_src += i_src_stride;
p_dst += i_dst_stride;
}
}
#ifdef LIBAVCODEC_PP
}
#endif
}
else
{
/* we need to convert to I420 */
switch( p_vdec->p_context->pix_fmt )
{
AVPicture dest_pic;
int i;
/* we need to convert to I420 */
switch( p_sys->p_context->pix_fmt )
{
case( PIX_FMT_YUV410P ):
case( PIX_FMT_YUV411P ):
for( i = 0; i < p_pic->i_planes; i++ )
......@@ -736,14 +585,14 @@ static void ffmpeg_CopyPicture( picture_t *p_pic,
}
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 );
p_sys->p_context->pix_fmt,
p_sys->p_context->width,
p_sys->p_context->height );
break;
default:
msg_Err( p_vdec->p_fifo, "don't know how to convert chroma %i",
p_vdec->p_context->pix_fmt );
p_vdec->p_fifo->b_error = 1;
msg_Err( p_dec, "don't know how to convert chroma %i",
p_sys->p_context->pix_fmt );
p_dec->p_fifo->b_error = 1;
break;
}
}
......@@ -758,23 +607,16 @@ static void ffmpeg_CopyPicture( picture_t *p_pic,
static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
AVFrame *p_ff_pic )
{
vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
decoder_t *p_dec = (decoder_t *)p_context->opaque;
decoder_sys_t *p_sys = p_dec->p_sys;
picture_t *p_pic;
/* Set picture PTS */
if( p_context->flags & CODEC_FLAG_TRUNCATED )
{
p_ff_pic->pts = p_vdec->input_pts_previous;
p_vdec->input_pts_previous = 0;
}
else
{
p_ff_pic->pts = p_vdec->input_pts;
p_vdec->input_pts = 0;
}
p_ff_pic->pts = p_sys->input_pts;
p_sys->input_pts = 0;
/* Not much to do in indirect rendering mode */
if( !p_vdec->b_direct_rendering )
if( !p_sys->b_direct_rendering )
{
return avcodec_default_get_buffer( p_context, p_ff_pic );
}
......@@ -782,36 +624,36 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
/* Some codecs set pix_fmt only after the 1st frame has been decoded,
* so this check is necessary. */
if( !ffmpeg_PixFmtToChroma( p_context->pix_fmt ) ||
p_vdec->p_context->width % 16 || p_vdec->p_context->height % 16 )
p_sys->p_context->width % 16 || p_sys->p_context->height % 16 )
{
msg_Dbg( p_vdec->p_fifo, "disabling direct rendering" );
p_vdec->b_direct_rendering = 0;
msg_Dbg( p_dec, "disabling direct rendering" );
p_sys->b_direct_rendering = 0;
return avcodec_default_get_buffer( p_context, p_ff_pic );
}
/* Check and (re)create our vout if needed */
p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
if( !p_vdec->p_vout )
p_sys->p_vout = ffmpeg_CreateVout( p_dec, p_sys->p_context );
if( !p_sys->p_vout )
{
msg_Err( p_vdec->p_fifo, "cannot create vout" );
p_vdec->p_fifo->b_error = 1; /* abort */
p_vdec->b_direct_rendering = 0;
msg_Err( p_dec, "cannot create vout" );
p_dec->p_fifo->b_error = 1; /* abort */
p_sys->b_direct_rendering = 0;
return avcodec_default_get_buffer( p_context, p_ff_pic );
}
p_vdec->p_vout->render.b_allow_modify_pics = 0;
p_sys->p_vout->render.b_allow_modify_pics = 0;
/* Get a new picture */
while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
{
if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )
{
p_vdec->b_direct_rendering = 0;
p_sys->b_direct_rendering = 0;
return avcodec_default_get_buffer( p_context, p_ff_pic );
}
msleep( VOUT_OUTMEM_SLEEP );
}
p_vdec->p_context->draw_horiz_band = NULL;
p_sys->p_context->draw_horiz_band = NULL;
p_ff_pic->opaque = (void*)p_pic;
p_ff_pic->type = FF_BUFFER_TYPE_USER;
......@@ -827,8 +669,9 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
if( p_ff_pic->reference != 0 )
{
vout_LinkPicture( p_vdec->p_vout, p_pic );
vout_LinkPicture( p_sys->p_vout, p_pic );
}
/* FIXME what is that, should give good value */
p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
......@@ -838,7 +681,8 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
AVFrame *p_ff_pic )
{
vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
decoder_t *p_dec = (decoder_t *)p_context->opaque;
decoder_sys_t *p_sys = p_dec->p_sys;
picture_t *p_pic;
if( p_ff_pic->type != FF_BUFFER_TYPE_USER )
......@@ -856,6 +700,6 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
if( p_ff_pic->reference != 0 )
{
vout_UnlinkPicture( p_vdec->p_vout, p_pic );
vout_UnlinkPicture( p_sys->p_vout, p_pic );
}
}
/*****************************************************************************
* video.h: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: video.h,v 1.11 2003/08/12 17:01:35 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* 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.
*****************************************************************************/
typedef struct vdec_thread_s
{
DECODER_THREAD_COMMON
AVFrame *p_ff_pic;
BITMAPINFOHEADER *p_format;
vout_thread_t *p_vout;
/* for post processing */
#ifdef LIBAVCODEC_PP
pp_context_t *pp_context;
pp_mode_t *pp_mode;
#endif
/* for frame skipping algo */
int b_hurry_up;
int i_frame_error;
int i_frame_skip;
vlc_bool_t b_has_b_frames;
int i_frame_late; /* how many decoded frames are late */
mtime_t i_frame_late_start;
/* for direct rendering */
int b_direct_rendering;
} vdec_thread_t;
int E_( InitThread_Video ) ( vdec_thread_t * );
void E_( EndThread_Video ) ( vdec_thread_t * );
void E_( DecodeThread_Video ) ( vdec_thread_t * );
......@@ -2,7 +2,7 @@
* vorbis.c: vorbis decoder module making use of libvorbis.
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: vorbis.c,v 1.19 2003/09/28 16:50:05 gbazin Exp $
* $Id: vorbis.c,v 1.20 2003/10/27 01:04:38 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
......@@ -37,10 +37,21 @@
#include <vlc/input.h>
#include <ogg/ogg.h>
#ifdef MODULE_NAME_IS_tremor
#include <tremor/ivorbiscodec.h>
#else
#include <vorbis/codec.h>
/* vorbis header */
#ifdef HAVE_VORBIS_VORBISENC_H
# include <vorbis/vorbisenc.h>
# ifndef OV_ECTL_RATEMANAGE_AVG
# define OV_ECTL_RATEMANAGE_AVG 0x0
# endif
#endif
#endif
/*****************************************************************************
......@@ -121,10 +132,18 @@ static void Interleave ( int32_t *, const int32_t **, int, int );
static void Interleave ( float *, const float **, int, int );
#endif
#ifndef MODULE_NAME_IS_tremor
static int OpenEncoder ( vlc_object_t * );
static void CloseEncoder ( vlc_object_t * );
static block_t *Headers ( encoder_t * );
static block_t *Encode ( encoder_t *, aout_buffer_t * );
#endif
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("Vorbis audio decoder") );
#ifdef MODULE_NAME_IS_tremor
set_capability( "decoder", 90 );
......@@ -137,6 +156,14 @@ vlc_module_begin();
set_description( _("Vorbis audio packetizer") );
set_capability( "packetizer", 100 );
set_callbacks( OpenPacketizer, NULL );
#ifndef MODULE_NAME_IS_tremor
add_submodule();
set_description( _("Vorbis audio encoder") );
set_capability( "audio encoder", 100 );
set_callbacks( OpenEncoder, CloseEncoder );
#endif
vlc_module_end();
/*****************************************************************************
......@@ -576,3 +603,229 @@ static int EndDecoder( decoder_t * p_dec )
return VLC_SUCCESS;
}
#if defined(HAVE_VORBIS_VORBISENC_H) && !defined(MODULE_NAME_IS_tremor)
/*****************************************************************************
* encoder_sys_t : theora encoder descriptor
*****************************************************************************/
struct encoder_sys_t
{
/*
* Input properties
*/
int i_headers;
/*
* Vorbis properties
*/
vorbis_info vi; /* struct that stores all the static vorbis bitstream
settings */
vorbis_comment vc; /* struct that stores all the bitstream user
* comments */
vorbis_dsp_state vd; /* central working state for the packet->PCM
* decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
int i_last_block_size;
int i_samples_delay;
/*
* Packetizer output properties
*/
sout_packetizer_input_t *p_sout_input;
sout_format_t sout_format;
/*
* Common properties
*/
mtime_t i_pts;
};
/*****************************************************************************
* OpenEncoder: probe the encoder and return score
*****************************************************************************/
static int OpenEncoder( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
if( p_enc->i_fourcc != VLC_FOURCC('v','o','r','b') )
{
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_enc->pf_header = Headers;
p_enc->pf_encode_audio = Encode;
p_enc->format.audio.i_format = VLC_FOURCC('f','l','3','2');
/* Initialize vorbis encoder */
vorbis_info_init( &p_sys->vi );
if( vorbis_encode_setup_managed( &p_sys->vi,
aout_FormatNbChannels( &p_enc->format.audio ),
p_enc->format.audio.i_rate, -1, p_enc->i_bitrate, -1 ) ||
vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) ||
vorbis_encode_setup_init( &p_sys->vi ) ){}
/* add a comment */
vorbis_comment_init( &p_sys->vc);
vorbis_comment_add_tag( &p_sys->vc, "ENCODER", "VLC media player");
/* set up the analysis state and auxiliary encoding storage */
vorbis_analysis_init( &p_sys->vd, &p_sys->vi );
vorbis_block_init( &p_sys->vd, &p_sys->vb );
p_sys->i_last_block_size = 0;
p_sys->i_samples_delay = 0;
p_sys->i_headers = 0;
p_sys->i_pts = 0;
return VLC_SUCCESS;
}
/****************************************************************************
* Encode: the whole thing
****************************************************************************
* This function spits out ogg packets.
****************************************************************************/
static block_t *Headers( encoder_t *p_enc )
{
encoder_sys_t *p_sys = p_enc->p_sys;
block_t *p_block, **pp_block = NULL;
/* Create theora headers */
if( !p_sys->i_headers )
{
ogg_packet header[3];
int i;
vorbis_analysis_headerout( &p_sys->vd, &p_sys->vc,
&header[0], &header[1], &header[2]);
for( i = 0; i < 3; i++ )
{
p_block = block_New( p_enc, header[i].bytes );
memcpy( p_block->p_buffer, header[i].packet, header[i].bytes );
p_block->i_dts = p_block->i_pts = p_block->i_length = 0;
block_ChainAppend( pp_block, p_block );
}
p_sys->i_headers = 3;
return *pp_block;
}
return NULL;
}
/****************************************************************************
* Encode: the whole thing
****************************************************************************
* This function spits out ogg packets.
****************************************************************************/
static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf )
{
encoder_sys_t *p_sys = p_enc->p_sys;
ogg_packet oggpacket;
block_t *p_block, *p_chain = NULL;
float **buffer;
int i_samples;
p_sys->i_pts = p_aout_buf->start_date -
(mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay /
(mtime_t)p_enc->format.audio.i_rate;
i_samples = p_aout_buf->i_nb_samples;
p_sys->i_samples_delay += i_samples;
buffer = vorbis_analysis_buffer( &p_sys->vd, i_samples );
#if 0
if( id->ff_dec_c->channels != id->ff_enc_c->channels )
{
int i, j;
/* dumb downmixing */
for( i = 0; i < id->ff_enc_c->frame_size; i++ )
{
for( j = 0 ; j < id->f_dst.i_channels; j++ )
{
p_buffer[i*id->f_dst.i_channels+j] =
p_buffer[i*id->f_src.i_channels+j];
}
}
}
/* convert samples to float and uninterleave */
for( i = 0; i < id->f_dst.i_channels; i++ )
{
for( j = 0 ; j < i_samples ; j++ )
{
buffer[i][j]= ((float)( ((int16_t *)id->p_buffer)
[j*id->f_src.i_channels + i ] ))/ 32768.f;
}
}
#endif
vorbis_analysis_wrote( &p_sys->vd, i_samples );
while( vorbis_analysis_blockout( &p_sys->vd, &p_sys->vb ) == 1 )
{
vorbis_analysis( &p_sys->vb, NULL );
vorbis_bitrate_addblock( &p_sys->vb );
while( vorbis_bitrate_flushpacket( &p_sys->vd, &oggpacket ) )
{
int i_block_size;
p_block = block_New( p_enc, oggpacket.bytes );
memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
i_block_size = vorbis_packet_blocksize( &p_sys->vi, &oggpacket );
if( i_block_size < 0 ) i_block_size = 0;
i_samples = ( p_sys->i_last_block_size + i_block_size ) >> 2;
p_sys->i_last_block_size = i_block_size;
p_block->i_length = (mtime_t)1000000 *
(mtime_t)i_samples / (mtime_t)p_enc->format.audio.i_rate;
p_block->i_dts = p_block->i_pts = p_sys->i_pts;
p_sys->i_samples_delay -= i_samples;
/* Update pts */
p_sys->i_pts += p_block->i_length;
block_ChainAppend( &p_chain, p_block );
}
}
return p_chain;
}
/*****************************************************************************
* CloseEncoder: theora encoder destruction
*****************************************************************************/
static void CloseEncoder( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
vorbis_block_clear( &p_sys->vb );
vorbis_dsp_clear( &p_sys->vd );
vorbis_comment_clear( &p_sys->vc );
vorbis_info_clear( &p_sys->vi ); /* must be called last */
free( p_sys );
}
#endif /* HAVE_VORBIS_VORBISENC_H && !MODULE_NAME_IS_tremor */
......@@ -2,9 +2,10 @@
* transcode.c
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: transcode.c,v 1.43 2003/10/24 21:27:06 gbazin Exp $
* $Id: transcode.c,v 1.44 2003/10/27 01:04:38 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
......@@ -40,14 +41,6 @@
# include <avcodec.h>
#endif
/* vorbis header */
#ifdef HAVE_VORBIS_VORBISENC_H
# include <vorbis/vorbisenc.h>
# ifndef OV_ECTL_RATEMANAGE_AVG
# define OV_ECTL_RATEMANAGE_AVG 0x0
# endif
#endif
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
......@@ -68,6 +61,17 @@ static int transcode_video_ffmpeg_process( sout_stream_t *, sout_stream_id_t *,
static int transcode_video_ffmpeg_getframebuf( struct AVCodecContext *, AVFrame *);
static int pi_channels_maps[6] =
{
0,
AOUT_CHAN_CENTER, AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
};
/*****************************************************************************
* Module descriptor
*****************************************************************************/
......@@ -106,9 +110,6 @@ struct sout_stream_sys_t
mtime_t i_input_pts;
mtime_t i_output_pts;
mtime_t i_last_ref_pts;
mtime_t i_buggy_pts_detect;
};
/*****************************************************************************
......@@ -303,7 +304,6 @@ static int Open( vlc_object_t *p_this )
/*****************************************************************************
* Close:
*****************************************************************************/
static void Close( vlc_object_t * p_this )
{
sout_stream_t *p_stream = (sout_stream_t*)p_this;
......@@ -325,16 +325,12 @@ struct sout_stream_id_t
/* Encoder */
encoder_t *p_encoder;
vlc_fourcc_t b_enc_inited;
/* ffmpeg part */
AVCodec *ff_dec;
AVCodecContext *ff_dec_c;
vlc_fourcc_t b_enc_inited;
AVCodec *ff_enc;
AVCodecContext *ff_enc_c;
mtime_t i_dts;
mtime_t i_length;
......@@ -346,28 +342,12 @@ struct sout_stream_id_t
int i_buffer_pos;
uint8_t *p_buffer;
int i_buffer_out;
int i_buffer_out_pos;
uint8_t *p_buffer_out;
AVFrame *p_ff_pic;
AVFrame *p_ff_pic_tmp0; /* to do deinterlace */
AVFrame *p_ff_pic_tmp1; /* to do pix conversion */
AVFrame *p_ff_pic_tmp2; /* to do resample */
ImgReSampleContext *p_vresample;
#ifdef HAVE_VORBIS_VORBISENC_H
/* Vorbis part */
vorbis_info *p_vi;
vorbis_dsp_state *p_vd;
vorbis_block *p_vb;
vorbis_comment *p_vc;
int i_last_block_size;
int i_samples_delay;
vlc_bool_t b_headers_sent;
#endif
};
......@@ -672,7 +652,6 @@ static int transcode_audio_ffmpeg_new( sout_stream_t *p_stream,
}
}
/* find encoder */
id->i_buffer_in = 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
id->i_buffer_in_pos = 0;
id->p_buffer_in = malloc( id->i_buffer_in );
......@@ -681,97 +660,33 @@ static int transcode_audio_ffmpeg_new( sout_stream_t *p_stream,
id->i_buffer_pos = 0;
id->p_buffer = malloc( id->i_buffer );
id->i_buffer_out = 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
id->i_buffer_out_pos = 0;
id->p_buffer_out = malloc( id->i_buffer_out );
/* Sanity check for audio channels */
id->f_dst.i_channels = __MIN( id->f_dst.i_channels, id->f_src.i_channels );
#ifdef HAVE_VORBIS_VORBISENC_H
if( id->f_dst.i_fourcc == VLC_FOURCC('v','o','r','b') )
{
id->p_vi = (vorbis_info *)malloc( sizeof(vorbis_info) );
id->p_vd = (vorbis_dsp_state *)malloc( sizeof(vorbis_dsp_state) );
id->p_vb = (vorbis_block *)malloc( sizeof(vorbis_block) );
id->p_vc = (vorbis_comment *)malloc( sizeof(vorbis_comment) );
vorbis_info_init( id->p_vi );
if( vorbis_encode_setup_managed( id->p_vi, id->f_dst.i_channels,
id->f_dst.i_sample_rate, -1, id->f_dst.i_bitrate, -1 ) ||
vorbis_encode_ctl( id->p_vi, OV_ECTL_RATEMANAGE_AVG, NULL ) ||
vorbis_encode_setup_init( id->p_vi ) ){}
/* add a comment */
vorbis_comment_init( id->p_vc);
vorbis_comment_add_tag( id->p_vc, "ENCODER", "VLC media player");
/* set up the analysis state and auxiliary encoding storage */
vorbis_analysis_init( id->p_vd, id->p_vi );
vorbis_block_init( id->p_vd, id->p_vb );
id->b_headers_sent = VLC_FALSE;
id->i_last_block_size = 0;
id->i_samples_delay = 0;
return VLC_SUCCESS;
}
#endif
i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
if( i_ff_codec == 0 )
{
msg_Err( p_stream, "cannot find encoder id" );
return VLC_EGENERIC;
}
id->ff_enc = avcodec_find_encoder( i_ff_codec );
if( !id->ff_enc )
{
msg_Err( p_stream, "cannot find encoder (avcodec)" );
return VLC_EGENERIC;
}
/* find encoder */
id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
id->p_encoder->i_fourcc = id->f_dst.i_fourcc;
id->p_encoder->format.audio.i_format = AOUT_FMT_S16_NE;
id->p_encoder->format.audio.i_rate = id->f_dst.i_sample_rate;
id->p_encoder->format.audio.i_physical_channels =
id->p_encoder->format.audio.i_original_channels =
pi_channels_maps[id->f_dst.i_channels];
id->p_encoder->i_bitrate = id->f_dst.i_bitrate;
id->p_encoder->i_extra_data = 0;
id->p_encoder->p_extra_data = NULL;
/* Hack for mp3 transcoding support */
if( id->f_dst.i_fourcc == VLC_FOURCC( 'm','p','3',' ' ) )
id->p_encoder->p_module =
module_Need( id->p_encoder, "audio encoder", NULL );
if( !id->p_encoder->p_module )
{
id->f_dst.i_fourcc = VLC_FOURCC( 'm','p','g','a' );
vlc_object_destroy( id->p_encoder );
id->p_encoder = NULL;
}
id->ff_enc_c = avcodec_alloc_context();
id->ff_enc_c->bit_rate = id->f_dst.i_bitrate;
id->ff_enc_c->sample_rate = id->f_dst.i_sample_rate;
id->ff_enc_c->channels = id->f_dst.i_channels;
/* Make sure we get extradata filled by the encoder */
id->ff_enc_c->extradata_size = 0;
id->ff_enc_c->extradata = NULL;
id->ff_enc_c->flags |= CODEC_FLAG_GLOBAL_HEADER;
if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
{
if( id->ff_enc_c->channels > 2 )
{
id->ff_enc_c->channels = 2;
id->f_dst.i_channels = 2;
if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
{
msg_Err( p_stream, "cannot open encoder" );
return VLC_EGENERIC;
}
msg_Warn( p_stream, "stereo mode selected (codec limitation)" );
}
else
{
msg_Err( p_stream, "cannot open encoder" );
return VLC_EGENERIC;
}
}
id->b_enc_inited = VLC_FALSE;
id->f_dst.i_extra_data = id->ff_enc_c->extradata_size;
id->f_dst.p_extra_data = id->ff_enc_c->extradata;
id->ff_enc_c->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
id->f_dst.i_extra_data = id->p_encoder->i_extra_data;
id->f_dst.p_extra_data = id->p_encoder->p_extra_data;
return VLC_SUCCESS;
}
......@@ -782,32 +697,14 @@ static void transcode_audio_ffmpeg_close( sout_stream_t *p_stream,
if( id->ff_dec )
{
avcodec_close( id->ff_dec_c );
free( id->ff_dec_c );
}
#ifdef HAVE_VORBIS_VORBISENC_H
if( id->f_dst.i_fourcc == VLC_FOURCC('v','o','r','b') )
{
vorbis_block_clear( id->p_vb );
vorbis_dsp_clear( id->p_vd );
vorbis_comment_clear( id->p_vc );
vorbis_info_clear( id->p_vi ); /* must be called last */
free( id->p_vi );
free( id->p_vd );
free( id->p_vb );
free( id->p_vc );
}
else
#endif
avcodec_close( id->ff_enc_c );
free( id->ff_dec_c );
if( id->f_dst.i_fourcc != VLC_FOURCC('v','o','r','b') )
free( id->ff_enc_c );
module_Unneed( id->p_encoder, id->p_encoder->p_module );
vlc_object_destroy( id->p_encoder );
free( id->p_buffer_in );
free( id->p_buffer );
free( id->p_buffer_out );
}
static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
......@@ -816,17 +713,11 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
sout_buffer_t **out )
{
vlc_bool_t b_again = VLC_FALSE;
aout_buffer_t aout_buf;
block_t *p_block;
*out = NULL;
/* gather data into p_buffer_in */
#ifdef HAVE_VORBIS_VORBISENC_H
if( id->f_dst.i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
id->i_dts = in->i_dts -
(mtime_t)1000000 * (mtime_t)id->i_samples_delay /
(mtime_t)id->f_dst.i_sample_rate;
else
#endif
id->i_dts = in->i_dts -
(mtime_t)1000000 *
(mtime_t)(id->i_buffer_pos / 2 / id->ff_dec_c->channels )/
......@@ -844,8 +735,6 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
do
{
int i_buffer_pos;
/* decode as much data as possible */
if( id->ff_dec )
{
......@@ -854,20 +743,21 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
int i_buffer_size;
int i_used;
i_buffer_size = id->i_buffer - id->i_buffer_pos;
i_used = avcodec_decode_audio( id->ff_dec_c,
(int16_t*)&id->p_buffer[id->i_buffer_pos],
(int16_t*)&id->p_buffer,
&i_buffer_size, id->p_buffer_in,
id->i_buffer_in_pos );
/* msg_Warn( p_stream, "avcodec_decode_audio: %d used",
i_used ); */
#if 0
msg_Warn( p_stream, "avcodec_decode_audio: %d used on %d",
i_used, id->i_buffer_in_pos );
#endif
id->i_buffer_pos += i_buffer_size;
if( i_used < 0 )
{
msg_Warn( p_stream, "error");
msg_Warn( p_stream, "error audio decoding");
id->i_buffer_in_pos = 0;
break;
}
......@@ -977,164 +867,48 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
id->i_buffer_in_pos -= i_used;
}
i_buffer_pos = id->i_buffer_pos;
/* encode as much data as possible */
#ifdef HAVE_VORBIS_VORBISENC_H
if( id->i_buffer_pos == 0 );
else if( id->f_dst.i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
{
float **buffer;
int i, j, i_samples;
sout_buffer_t *p_out;
ogg_packet op;
if( id->i_buffer_pos == 0 ) continue;
if( !id->b_headers_sent )
/* Encode as much data as possible */
if( id->b_enc_inited )
{
ogg_packet header[3];
vorbis_analysis_headerout( id->p_vd, id->p_vc,
&header[0], &header[1], &header[2]);
for( i = 0; i < 3; i++ )
while( id->p_encoder->pf_header &&
(p_block = id->p_encoder->pf_header( id->p_encoder )) )
{
p_out = sout_BufferNew( p_stream->p_sout, header[i].bytes);
memcpy( p_out->p_buffer, header[i].packet,
header[i].bytes );
p_out->i_size = header[i].bytes;
p_out->i_length = 0;
p_out->i_dts = p_out->i_pts = id->i_dts;
sout_buffer_t *p_out;
p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
memcpy( p_out->p_buffer, p_block->p_buffer, p_block->i_buffer);
p_out->i_dts = in->i_dts;
p_out->i_pts = in->i_dts;
sout_BufferChain( out, p_out );
}
id->b_headers_sent = VLC_TRUE;
}
i_samples = id->i_buffer_pos / id->f_src.i_channels / 2;
id->i_samples_delay += i_samples;
id->i_buffer_pos = 0;
buffer = vorbis_analysis_buffer( id->p_vd, i_samples );
/* convert samples to float and uninterleave */
for( i = 0; i < id->f_dst.i_channels; i++ )
{
for( j = 0 ; j < i_samples ; j++ )
{
buffer[i][j]= ((float)( ((int16_t *)id->p_buffer)
[j*id->f_src.i_channels + i ] ))/ 32768.f;
}
id->b_enc_inited = VLC_TRUE;
}
vorbis_analysis_wrote( id->p_vd, i_samples );
while( vorbis_analysis_blockout( id->p_vd, id->p_vb ) == 1 )
{
vorbis_analysis( id->p_vb, NULL );
vorbis_bitrate_addblock( id->p_vb );
while( vorbis_bitrate_flushpacket( id->p_vd, &op ) )
{
int i_block_size;
p_out = sout_BufferNew( p_stream->p_sout, op.bytes );
memcpy( p_out->p_buffer, op.packet, op.bytes );
i_block_size = vorbis_packet_blocksize( id->p_vi, &op );
if( i_block_size < 0 ) i_block_size = 0;
i_samples = ( id->i_last_block_size +
i_block_size ) >> 2;
id->i_last_block_size = i_block_size;
p_out->i_size = op.bytes;
p_out->i_length = (mtime_t)1000000 *
(mtime_t)i_samples /
(mtime_t)id->f_dst.i_sample_rate;
//msg_Err( p_stream, "i_dts: %lld", id->i_dts );
/* FIXME */
p_out->i_dts = id->i_dts;
p_out->i_pts = id->i_dts;
aout_buf.p_buffer = id->p_buffer;
aout_buf.i_nb_bytes = id->i_buffer_pos;
aout_buf.i_nb_samples = id->i_buffer_pos / 2 / id->ff_dec_c->channels;
aout_buf.start_date = id->i_dts;
aout_buf.end_date = id->i_dts;
id->i_samples_delay -= i_samples;
/* update dts */
id->i_dts += p_out->i_length;
sout_BufferChain( out, p_out );
}
}
}
else
#endif
for( ;; )
p_block = id->p_encoder->pf_encode_audio( id->p_encoder, &aout_buf );
while( p_block )
{
int i_frame_size = id->ff_enc_c->frame_size * 2 *
id->ff_dec_c->channels;
int i_out_size, i, j;
sout_buffer_t *p_out;
int16_t *p_buffer = (int16_t *)(id->p_buffer + i_buffer_pos -
id->i_buffer_pos);
if( id->i_buffer_pos < i_frame_size )
{
break;
}
if( id->ff_dec_c->channels != id->ff_enc_c->channels )
{
/* dumb downmixing */
for( i = 0; i < id->ff_enc_c->frame_size; i++ )
{
for( j = 0 ; j < id->f_dst.i_channels; j++ )
{
p_buffer[i*id->f_dst.i_channels+j] = p_buffer[i*id->f_src.i_channels+j];
}
}
}
/* msg_Warn( p_stream, "avcodec_encode_audio: frame size%d",
i_frame_size); */
i_out_size = avcodec_encode_audio( id->ff_enc_c,
id->p_buffer_out, id->i_buffer_out, p_buffer );
if( i_out_size <= 0 )
{
break;
}
id->i_buffer_pos -= i_frame_size;
p_out = sout_BufferNew( p_stream->p_sout, i_out_size );
memcpy( p_out->p_buffer, id->p_buffer_out, i_out_size );
p_out->i_size = i_out_size;
p_out->i_length = (mtime_t)1000000 *
(mtime_t)id->ff_enc_c->frame_size /
(mtime_t)id->ff_enc_c->sample_rate;
/* FIXME */
p_out->i_dts = id->i_dts;
p_out->i_pts = id->i_dts;
/* update dts */
id->i_dts += p_out->i_length;
/* msg_Warn( p_stream, "frame dts=%lld len %lld out=%d",
p_out->i_dts, p_out->i_length, i_out_size ); */
block_t *p_prev_block = p_block;
p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
memcpy( p_out->p_buffer, p_block->p_buffer, p_block->i_buffer);
p_out->i_dts = p_block->i_dts;
p_out->i_pts = p_block->i_pts;
p_out->i_length = p_block->i_length;
sout_BufferChain( out, p_out );
}
/* Copy the remaining raw samples */
if( id->i_buffer_pos != 0 )
{
memmove( id->p_buffer,
&id->p_buffer[i_buffer_pos - id->i_buffer_pos],
id->i_buffer_pos );
p_block = p_block->p_next;
block_Release( p_prev_block );
}
id->i_buffer_pos = 0;
} while( b_again );
......@@ -1152,6 +926,7 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
int i_ff_codec;
/* Open decoder */
if( id->f_src.i_fourcc == VLC_FOURCC( 'I', '4', '2', '0' ) ||
id->f_src.i_fourcc == VLC_FOURCC( 'I', '4', '2', '2' ) ||
id->f_src.i_fourcc == VLC_FOURCC( 'I', '4', '4', '4' ) ||
......@@ -1221,154 +996,88 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
}
}
/* find encoder */
id->ff_enc = id->ff_enc_c = NULL;
i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
if( i_ff_codec != 0 )
{
id->ff_enc = avcodec_find_encoder( i_ff_codec );
}
/* Hack for external encoders */
if( !id->ff_enc )
{
/* Open encoder */
id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
id->p_encoder->i_fourcc = id->f_dst.i_fourcc;
id->p_encoder->format.video.i_width = p_sys->i_width;
id->p_encoder->format.video.i_height = p_sys->i_height;
id->p_encoder->i_bitrate = p_sys->i_vbitrate;
id->p_encoder->i_vtolerance = p_sys->i_vtolerance;
id->p_encoder->i_key_int = p_sys->i_key_int;
id->p_encoder->i_b_frames = p_sys->i_b_frames;
id->p_encoder->i_qmin = p_sys->i_qmin;
id->p_encoder->i_qmax = p_sys->i_qmax;
id->p_encoder->i_hq = p_sys->i_hq;
if( id->p_encoder->format.video.i_width <= 0 )
{
id->p_encoder->format.video.i_width = id->f_dst.i_width =
id->ff_dec_c->width - p_sys->i_crop_left -
p_sys->i_crop_right;
id->ff_dec_c->width - p_sys->i_crop_left - p_sys->i_crop_right;
}
if( id->p_encoder->format.video.i_height <= 0 )
{
id->p_encoder->format.video.i_height = id->f_dst.i_height =
id->ff_dec_c->height - p_sys->i_crop_top -
p_sys->i_crop_bottom;
}
id->p_encoder->p_module =
module_Need( id->p_encoder, "video encoder", NULL );
if( !id->p_encoder->p_module )
{
free( id->p_encoder );
id->p_encoder = NULL;
}
}
/* End hack for external encoders */
if( !id->ff_enc && !id->p_encoder )
{
msg_Err( p_stream, "cannot find encoder" );
return VLC_EGENERIC;
id->ff_dec_c->height - p_sys->i_crop_top - p_sys->i_crop_bottom;
}
/* XXX open it only when we have the first frame */
id->b_enc_inited = VLC_FALSE;
id->i_buffer_in = 0;
id->i_buffer_in_pos = 0;
id->p_buffer_in = NULL;
id->i_buffer = 3*1024*1024;
id->i_buffer_pos = 0;
id->p_buffer = malloc( id->i_buffer );
id->i_buffer_out = 0;
id->i_buffer_out_pos = 0;
id->p_buffer_out = NULL;
id->p_ff_pic = avcodec_alloc_frame();
id->p_ff_pic_tmp0 = NULL;
id->p_ff_pic_tmp1 = NULL;
id->p_ff_pic_tmp2 = NULL;
id->p_vresample = NULL;
p_sys->i_last_ref_pts = 0;
p_sys->i_buggy_pts_detect = 0;
/* This is enough for external encoders */
if( id->p_encoder && id->p_encoder->p_module ) return VLC_SUCCESS;
if( id->f_dst.i_fourcc == VLC_FOURCC( 'm','p','1','v' )||
id->f_dst.i_fourcc == VLC_FOURCC( 'm','p','2','v' ) )
{
id->f_dst.i_fourcc = VLC_FOURCC( 'm','p','g','v' );
}
id->ff_enc_c = avcodec_alloc_context();
id->ff_enc_c->width = id->f_dst.i_width;
id->ff_enc_c->height = id->f_dst.i_height;
id->ff_enc_c->bit_rate = id->f_dst.i_bitrate;
if( id->ff_dec )
{
id->ff_enc_c->frame_rate = id->ff_dec_c->frame_rate;
id->p_encoder->i_frame_rate = id->ff_dec_c->frame_rate;
#if LIBAVCODEC_BUILD >= 4662
id->ff_enc_c->frame_rate_base= id->ff_dec_c->frame_rate_base;
id->p_encoder->i_frame_rate_base= id->ff_dec_c->frame_rate_base;
#endif
}
else
{
#if LIBAVCODEC_BUILD >= 4662
id->ff_enc_c->frame_rate = 25 ; /* FIXME as it break mpeg */
id->ff_enc_c->frame_rate_base= 1;
id->p_encoder->i_frame_rate = 25 ; /* FIXME as it break mpeg */
id->p_encoder->i_frame_rate_base= 1;
#else
id->ff_enc_c->frame_rate = 25 * FRAME_RATE_BASE;
id->p_encoder->i_frame_rate = 25 * FRAME_RATE_BASE;
#endif
}
id->ff_enc_c->gop_size = p_sys->i_key_int >= 0 ? p_sys->i_key_int : 50;
id->ff_enc_c->max_b_frames = __MIN( p_sys->i_b_frames, FF_MAX_B_FRAMES );
id->ff_enc_c->b_frame_strategy = 0;
id->ff_enc_c->b_quant_factor = 2.0;
id->p_encoder->p_module =
module_Need( id->p_encoder, "video encoder", NULL );
if( p_sys->i_vtolerance >= 0 )
if( !id->p_encoder->p_module )
{
id->ff_enc_c->bit_rate_tolerance = p_sys->i_vtolerance;
vlc_object_destroy( id->p_encoder );
msg_Err( p_stream, "cannot find encoder" );
return VLC_EGENERIC;
}
id->ff_enc_c->qmin = p_sys->i_qmin;
id->ff_enc_c->qmax = p_sys->i_qmax;
#if LIBAVCODEC_BUILD >= 4673
id->ff_enc_c->mb_decision = p_sys->i_hq;
#else
if( p_sys->i_hq )
{
id->ff_enc_c->flags |= CODEC_FLAG_HQ;
}
#endif
/* Close the encoder.
* We'll open it only when we have the first frame */
module_Unneed( id->p_encoder, id->p_encoder->p_module );
if( i_ff_codec == CODEC_ID_RAWVIDEO )
{
id->ff_enc_c->pix_fmt = get_ff_chroma( id->f_dst.i_fourcc );
}
id->b_enc_inited = VLC_FALSE;
return VLC_SUCCESS;
}
static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_id_t *id )
static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream,
sout_stream_id_t *id )
{
/* Close decoder */
if( id->ff_dec )
{
avcodec_close( id->ff_dec_c );
free( id->ff_dec_c );
}
if( id->p_encoder )
{
/* External encoding */
/* Close encoder */
module_Unneed( id->p_encoder, id->p_encoder->p_module );
vlc_object_destroy( id->p_encoder->p_module );
}
else if( id->b_enc_inited )
{
avcodec_close( id->ff_enc_c );
}
vlc_object_destroy( id->p_encoder );
/* Misc cleanup */
if( id->p_ff_pic)
{
free( id->p_ff_pic );
......@@ -1393,10 +1102,6 @@ static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_
{
free( id->p_vresample );
}
free( id->ff_dec_c );
if( id->ff_enc_c ) free( id->ff_enc_c );
free( id->p_buffer );
}
static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
......@@ -1404,7 +1109,6 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
int i_used;
int i_out;
int b_gotpicture;
AVFrame *frame;
......@@ -1461,37 +1165,54 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
p_sys->i_output_pts = frame->pts;
}
if( !id->b_enc_inited && id->p_encoder )
if( !id->b_enc_inited )
{
block_t *p_block;
/* XXX hack because of copy packetizer and mpeg4video that can fail
* detecting size */
#if 0
if( id->p_encoder->i_width <= 0 )
if( id->p_encoder->format.video.i_width <= 0 )
{
id->p_encoder->i_width = id->f_dst.i_width =
id->p_encoder->format.video.i_width = id->f_dst.i_width =
id->ff_dec_c->width - p_sys->i_crop_left -
p_sys->i_crop_right;
}
if( id->p_encoder->i_height <= 0 )
if( id->p_encoder->format.video.i_height <= 0 )
{
id->p_encoder->i_height = id->f_dst.i_height =
id->p_encoder->format.video.i_height = id->f_dst.i_height =
id->ff_dec_c->height - p_sys->i_crop_top -
p_sys->i_crop_bottom;
}
#endif
id->p_encoder->i_bitrate = p_sys->i_vbitrate;
if( !( id->id = p_stream->p_sys->p_out->pf_add( p_stream->p_sys->p_out, &id->f_dst ) ) )
id->p_encoder->i_extra_data = 0;
id->p_encoder->p_extra_data = NULL;
id->p_encoder->p_module =
module_Need( id->p_encoder, "video encoder", NULL );
if( !id->p_encoder->p_module )
{
vlc_object_destroy( id->p_encoder );
msg_Err( p_stream, "cannot find encoder" );
return VLC_EGENERIC;
}
id->f_dst.i_extra_data = id->p_encoder->i_extra_data;
id->f_dst.p_extra_data = id->p_encoder->p_extra_data;
if( !( id->id =
p_stream->p_sys->p_out->pf_add( p_stream->p_sys->p_out,
&id->f_dst ) ) )
{
msg_Err( p_stream, "cannot add this stream" );
transcode_video_ffmpeg_close( p_stream, id );
id->b_transcode = VLC_FALSE;
return VLC_EGENERIC;
}
while( (p_block = id->p_encoder->pf_header( id->p_encoder )) )
while( id->p_encoder->pf_header &&
(p_block = id->p_encoder->pf_header( id->p_encoder )) )
{
sout_buffer_t *p_out;
p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
......@@ -1506,49 +1227,6 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
id->b_enc_inited = VLC_TRUE;
}
else if( !id->b_enc_inited )
{
/* XXX hack because of copy packetizer and mpeg4video that can fail
* detecting size */
if( id->ff_enc_c->width <= 0 )
{
id->ff_enc_c->width =
id->f_dst.i_width = id->ff_dec_c->width - p_sys->i_crop_left - p_sys->i_crop_right;
}
if( id->ff_enc_c->height <= 0 )
{
id->ff_enc_c->height =
id->f_dst.i_height = id->ff_dec_c->height - p_sys->i_crop_top - p_sys->i_crop_bottom;
}
/* Make sure we get extradata filled by the encoder */
id->ff_enc_c->extradata_size = 0;
id->ff_enc_c->extradata = NULL;
id->ff_enc_c->flags |= CODEC_FLAG_GLOBAL_HEADER;
if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
{
msg_Err( p_stream, "cannot open encoder" );
return VLC_EGENERIC;
}
id->f_dst.i_extra_data = id->ff_enc_c->extradata_size;
id->f_dst.p_extra_data = id->ff_enc_c->extradata;
id->ff_enc_c->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
if( !( id->id = p_stream->p_sys->p_out->pf_add( p_stream->p_sys->p_out, &id->f_dst ) ) )
{
msg_Err( p_stream, "cannot add this stream" );
transcode_video_ffmpeg_close( p_stream, id );
id->b_transcode = VLC_FALSE;
return VLC_EGENERIC;
}
id->i_inter_pixfmt = id->ff_enc_c->pix_fmt;
id->b_enc_inited = VLC_TRUE;
}
/* deinterlace */
if( p_stream->p_sys->b_deinterlace )
......@@ -1653,9 +1331,7 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
id->ff_dec_c->frame_rate_base / (2 * id->ff_dec_c->frame_rate);
}
if( id->p_encoder )
{
/* External encoding */
/* Encoding */
block_t *p_block;
picture_t pic;
int i_plane;
......@@ -1675,74 +1351,20 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
pic.date = frame->pts;
p_block = id->p_encoder->pf_encode_video( id->p_encoder, &pic );
if( p_block )
while( p_block )
{
sout_buffer_t *p_out;
block_t *p_prev_block = p_block;
p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
memcpy( p_out->p_buffer, p_block->p_buffer, p_block->i_buffer);
p_out->i_dts = p_block->i_dts;
p_out->i_pts = p_block->i_pts;
p_out->i_length = p_block->i_length;
sout_BufferChain( out, p_out );
block_Release( p_block );
}
return VLC_SUCCESS;
}
/* Let ffmpeg select the frame type */
frame->pict_type = 0;
i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer,
id->i_buffer, frame );
if( i_out > 0 )
{
sout_buffer_t *p_out;
p_out = sout_BufferNew( p_stream->p_sout, i_out );
memcpy( p_out->p_buffer, id->p_buffer, i_out );
p_out->i_size = i_out;
if( id->ff_enc_c->coded_frame->pts != 0 &&
p_sys->i_buggy_pts_detect != id->ff_enc_c->coded_frame->pts )
{
p_sys->i_buggy_pts_detect = id->ff_enc_c->coded_frame->pts;
/* FIXME, 3-2 pulldown is not handled correctly */
p_out->i_length = in->i_length;
p_out->i_pts = id->ff_enc_c->coded_frame->pts;
if( !id->ff_enc_c->delay ||
( id->ff_enc_c->coded_frame->pict_type != FF_I_TYPE &&
id->ff_enc_c->coded_frame->pict_type != FF_P_TYPE ) )
{
p_out->i_dts = p_out->i_pts;
}
else
{
if( p_sys->i_last_ref_pts )
{
p_out->i_dts = p_sys->i_last_ref_pts;
}
else
{
/* Let's put something sensible */
p_out->i_dts = p_out->i_pts;
}
p_sys->i_last_ref_pts = p_out->i_pts;
}
}
else
{
/* Buggy libavcodec which doesn't update coded_frame->pts
* correctly */
p_out->i_length = in->i_length;
p_out->i_dts = in->i_dts;
p_out->i_pts = in->i_dts;
}
sout_BufferChain( out, p_out );
p_block = p_block->p_next;
block_Release( p_prev_block );
}
if( i_data <= 0 )
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment