Commit 4764ebc9 authored by Laurent Aimar's avatar Laurent Aimar

* all : add audio decoding support in ffmpeg module, since they have

added wma1/2 decoder... :))
parent ec8efba6
SOURCES_ffmpeg = modules/codec/ffmpeg/ffmpeg.c
SOURCES_ffmpeg = modules/codec/ffmpeg/ffmpeg.c \
modules/codec/ffmpeg/video.c \
modules/codec/ffmpeg/audio.c
noinst_HEADERS += modules/codec/ffmpeg/ffmpeg.h
noinst_HEADERS += modules/codec/ffmpeg/ffmpeg.h \
modules/codec/ffmpeg/video.h \
modules/codec/ffmpeg/audio.h
/*****************************************************************************
* audio.c: audio decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: audio.c,v 1.1 2002/10/28 06:26:11 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* getpid() */
#endif
#include <errno.h>
#include <string.h>
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include "avcodec.h" /* ffmpeg */
#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 int i_channels_maps[6] =
{
0,
AOUT_CHAN_MONO, AOUT_CHAN_STEREO,
AOUT_CHAN_3F, AOUT_CHAN_2F2R,
AOUT_CHAN_3F2R
};
/*****************************************************************************
* locales Functions
*****************************************************************************/
static void ffmpeg_GetWaveFormatEx( waveformatex_t *p_wh,
u8 *p_data )
{
p_wh->i_formattag = GetWLE( p_data );
p_wh->i_channels = GetWLE( p_data + 2 );
p_wh->i_samplespersec = GetDWLE( p_data + 4 );
p_wh->i_avgbytespersec= GetDWLE( p_data + 8 );
p_wh->i_blockalign = GetWLE( p_data + 12 );
p_wh->i_bitspersample = GetWLE( p_data + 14 );
p_wh->i_size = GetWLE( p_data + 16 );
if( p_wh->i_size )
{
p_wh->p_data = malloc( p_wh->i_size );
memcpy( p_wh->p_data, p_data + 18, p_wh->i_size );
}
}
/*****************************************************************************
*
* Functions that initialize, decode and end the decoding process
*
* Functions exported for ffmpeg.c
* * E_( InitThread_Audio )
* * E_( DecodeThread_Audio )
* * E_( EndThread_Video_Audio )
*****************************************************************************/
/*****************************************************************************
* 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.
*****************************************************************************/
int E_( InitThread_Audio )( adec_thread_t *p_adec )
{
if( p_adec->p_fifo->p_demux_data )
{
ffmpeg_GetWaveFormatEx( &p_adec->format,
(u8*)p_adec->p_fifo->p_demux_data );
}
else
{
msg_Warn( p_adec->p_fifo, "audio informations missing" );
}
/* ***** Fill p_context with init values ***** */
p_adec->p_context->sample_rate = p_adec->format.i_samplespersec;
p_adec->p_context->channels = p_adec->format.i_channels;
p_adec->p_context->block_align = p_adec->format.i_blockalign;
p_adec->p_context->bit_rate = p_adec->format.i_avgbytespersec * 8;
if( ( p_adec->p_context->extradata_size = p_adec->format.i_size ) > 0 )
{
p_adec->p_context->extradata =
malloc( p_adec->format.i_size );
memcpy( p_adec->p_context->extradata,
p_adec->format.p_data,
p_adec->format.i_size );
}
/* ***** Open the codec ***** */
if (avcodec_open(p_adec->p_context, p_adec->p_codec) < 0)
{
msg_Err( p_adec->p_fifo,
"cannot open codec (%s)",
p_adec->psz_namecodec );
return( -1 );
}
else
{
msg_Dbg( p_adec->p_fifo,
"ffmpeg codec (%s) started",
p_adec->psz_namecodec );
}
p_adec->p_output = malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE );
p_adec->output_format.i_format = AOUT_FMT_S16_NE;
p_adec->output_format.i_rate = p_adec->format.i_samplespersec;
p_adec->output_format.i_channels = p_adec->format.i_channels;
p_adec->p_aout = NULL;
p_adec->p_aout_input = NULL;
return( 0 );
}
/*****************************************************************************
* DecodeThread: Called for decode one frame
*****************************************************************************/
void E_( DecodeThread_Audio )( adec_thread_t *p_adec )
{
pes_packet_t *p_pes;
aout_buffer_t *p_aout_buffer;
int i_samplesperchannel;
int i_output_size;
int i_frame_size;
int i_status;
do
{
input_ExtractPES( p_adec->p_fifo, &p_pes );
if( !p_pes )
{
p_adec->p_fifo->b_error = 1;
return;
}
p_adec->pts = p_pes->i_pts;
i_frame_size = p_pes->i_pes_size;
if( i_frame_size > 0 )
{
if( p_adec->i_buffer < i_frame_size + 16 )
{
FREE( p_adec->p_buffer );
p_adec->p_buffer = malloc( i_frame_size + 16 );
p_adec->i_buffer = i_frame_size + 16;
}
E_( GetPESData )( p_adec->p_buffer, p_adec->i_buffer, p_pes );
}
input_DeletePES( p_adec->p_fifo->p_packets_mgt, p_pes );
} while( i_frame_size <= 0 );
i_status = avcodec_decode_audio( p_adec->p_context,
(s16*)p_adec->p_output,
&i_output_size,
p_adec->p_buffer,
i_frame_size );
if( i_status < 0 )
{
msg_Warn( p_adec->p_fifo,
"cannot decode one frame (%d bytes)",
i_frame_size );
return;
}
if( i_output_size <= 0 )
{
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",
p_adec->p_context->channels );
}
/* **** Now we can output these samples **** */
i_samplesperchannel = i_output_size / 2 / p_adec->output_format.i_channels;
/* **** First check if we have a valid output **** */
if( ( !p_adec->p_aout_input )||
( p_adec->output_format.i_channels !=
p_adec->p_context->channels ) )
{
if( p_adec->p_aout_input )
{
/* **** Delete the old **** */
aout_DecDelete( p_adec->p_aout, p_adec->p_aout_input );
}
/* **** Create a new audio output **** */
p_adec->output_format.i_channels =
i_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 );
}
if( !p_adec->p_aout_input )
{
msg_Err( p_adec->p_fifo, "cannot create aout" );
return;
}
if( p_adec->pts != 0 && p_adec->pts != aout_DateGet( &p_adec->date ) )
{
aout_DateSet( &p_adec->date, p_adec->pts );
}
else if( !aout_DateGet( &p_adec->date ) )
{
return;
}
p_aout_buffer = aout_DecNewBuffer( p_adec->p_aout,
p_adec->p_aout_input,
i_samplesperchannel );
if( !p_aout_buffer )
{
msg_Err( p_adec->p_fifo, "cannot get aout buffer" );
p_adec->p_fifo->b_error = 1;
return;
}
p_aout_buffer->start_date = aout_DateGet( &p_adec->date );
p_aout_buffer->end_date = aout_DateIncrement( &p_adec->date,
i_samplesperchannel );
memcpy( p_aout_buffer->p_buffer,
p_adec->p_output,
p_aout_buffer->i_nb_bytes );
aout_DecPlay( p_adec->p_aout, p_adec->p_aout_input, p_aout_buffer );
return;
}
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
void E_( EndThread_Audio )( adec_thread_t *p_adec )
{
FREE( p_adec->format.p_data );
if( p_adec->p_aout_input )
{
aout_DecDelete( p_adec->p_aout, p_adec->p_aout_input );
}
}
/*****************************************************************************
* audio.h: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: audio.h,v 1.1 2002/10/28 06:26:11 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.
*****************************************************************************/
/* for an audio stream */
typedef struct waveformatex_s
{
u16 i_formattag;
u16 i_channels;
u32 i_samplespersec;
u32 i_avgbytespersec;
u16 i_blockalign;
u16 i_bitspersample;
u16 i_size; /* the extra size in bytes */
u8 *p_data; /* The extra data */
} waveformatex_t;
typedef struct adec_thread_s
{
DECODER_THREAD_COMMON
waveformatex_t format;
/*
* Output properties
*/
u8 * 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 @@
* ffmpeg.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ffmpeg.c,v 1.11 2002/10/27 16:58:13 gbazin Exp $
* $Id: ffmpeg.c,v 1.12 2002/10/28 06:26:11 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -28,6 +28,7 @@
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <vlc/input.h>
......@@ -47,19 +48,23 @@
#include "postprocessing/postprocessing.h"
#include "ffmpeg.h"
#include "video.h" // video ffmpeg specific
#include "audio.h" // audio ffmpeg specific
/*
* Local prototypes
*/
static int OpenDecoder ( vlc_object_t * );
static int RunDecoder ( decoder_fifo_t * );
static int InitThread ( videodec_thread_t * );
static void EndThread ( videodec_thread_t * );
static void DecodeThread ( videodec_thread_t * );
static int InitThread ( generic_thread_t * );
static void EndThread ( generic_thread_t * );
static int b_ffmpeginit = 0;
static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t, int *, int *, char ** );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
......@@ -131,7 +136,7 @@ vlc_module_begin();
"force chrominance deringing",
"force chrominance deringing (override other settings)" );
set_description( _("ffmpeg video decoder((MS)MPEG4,SVQ1,H263)") );
set_description( _("ffmpeg audio/video decoder((MS)MPEG4,SVQ1,H263,WMV,WMA)") );
set_capability( "decoder", 70 );
set_callbacks( OpenDecoder, NULL );
vlc_module_end();
......@@ -146,7 +151,7 @@ static int OpenDecoder( vlc_object_t *p_this )
{
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
if( ffmpeg_GetFfmpegCodec( p_fifo->i_fourcc, NULL, NULL ) )
if( ffmpeg_GetFfmpegCodec( p_fifo->i_fourcc, NULL, NULL, NULL ) )
{
p_fifo->pf_run = RunDecoder;
return VLC_SUCCESS;
......@@ -155,41 +160,59 @@ static int OpenDecoder( vlc_object_t *p_this )
return VLC_EGENERIC;
}
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 )
{
videodec_thread_t *p_vdec;
generic_thread_t *p_decoder;
int b_error;
if ( !(p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t))) )
if ( !(p_decoder = malloc( sizeof( decoder_thread_t ) ) ) )
{
msg_Err( p_fifo, "out of memory" );
DecoderError( p_fifo );
return( -1 );
}
memset( p_vdec, 0, sizeof( videodec_thread_t ) );
memset( p_decoder, 0, sizeof( decoder_thread_t ) );
p_vdec->p_fifo = p_fifo;
p_decoder->p_fifo = p_fifo;
if( InitThread( p_vdec ) != 0 )
if( InitThread( p_decoder ) != 0 )
{
msg_Err( p_fifo, "initialization failed" );
DecoderError( p_fifo );
return( -1 );
}
while( (!p_vdec->p_fifo->b_die) && (!p_vdec->p_fifo->b_error) )
while( (!p_decoder->p_fifo->b_die) && (!p_decoder->p_fifo->b_error) )
{
DecodeThread( p_vdec );
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_vdec->p_fifo->b_error ) )
if( ( b_error = p_decoder->p_fifo->b_error ) )
{
DecoderError( p_vdec->p_fifo );
DecoderError( p_decoder->p_fifo );
}
EndThread( p_vdec );
EndThread( p_decoder );
if( b_error )
{
......@@ -199,355 +222,6 @@ static int RunDecoder( decoder_fifo_t *p_fifo )
return( 0 );
}
/*****************************************************************************
* locales Functions
*****************************************************************************/
#define GetWLE( p ) \
( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) )
#define GetDWLE( p ) \
( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) + \
( *((u8*)(p)+2) << 16 ) + ( *((u8*)(p)+3) << 24 ) )
#define FREE( p ) if( p ) free( p ); p = NULL
static void ffmpeg_ParseBitMapInfoHeader( bitmapinfoheader_t *p_bh,
u8 *p_data )
{
p_bh->i_size = GetDWLE( p_data );
p_bh->i_width = GetDWLE( p_data + 4 );
p_bh->i_height = GetDWLE( p_data + 8 );
p_bh->i_planes = GetWLE( p_data + 12 );
p_bh->i_bitcount = GetWLE( p_data + 14 );
p_bh->i_compression = GetDWLE( p_data + 16 );
p_bh->i_sizeimage = GetDWLE( p_data + 20 );
p_bh->i_xpelspermeter = GetDWLE( p_data + 24 );
p_bh->i_ypelspermeter = GetDWLE( p_data + 28 );
p_bh->i_clrused = GetDWLE( p_data + 32 );
p_bh->i_clrimportant = GetDWLE( p_data + 36 );
if( p_bh->i_size > 40 )
{
p_bh->i_data = p_bh->i_size - 40;
if( ( p_bh->p_data = malloc( p_bh->i_data ) ) )
{
memcpy( p_bh->p_data, p_data + 40, p_bh->i_data );
}
else
{
p_bh->i_data = 0;
}
}
else
{
p_bh->i_data = 0;
p_bh->p_data = NULL;
}
}
static void GetPESData( u8 *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 );
}
}
/* Check if we have a Vout with good parameters */
static int ffmpeg_CheckVout( vout_thread_t *p_vout,
int i_width,
int i_height,
int i_aspect,
int i_chroma )
{
if( !p_vout )
{
return( 0 );
}
if( !i_chroma )
{
/* we will try to make conversion */
i_chroma = VLC_FOURCC('I','4','2','0');
}
if( ( p_vout->render.i_width != i_width )||
( p_vout->render.i_height != i_height )||
( p_vout->render.i_chroma != i_chroma )||
( p_vout->render.i_aspect !=
ffmpeg_FfAspect( i_width, i_height, i_aspect ) ) )
{
return( 0 );
}
else
{
return( 1 );
}
}
/* Return a Vout */
static vout_thread_t *ffmpeg_CreateVout( videodec_thread_t *p_vdec,
int i_width,
int i_height,
int i_aspect,
int i_chroma )
{
vout_thread_t *p_vout;
if( (!i_width)||(!i_height) )
{
return( NULL ); /* Can't create a new vout without display size */
}
if( !i_chroma )
{
/* we make conversion if possible*/
i_chroma = VLC_FOURCC('I','4','2','0');
msg_Warn( p_vdec->p_fifo, "Internal chroma conversion (FIXME)");
/* It's mainly for I410 -> I420 conversion that I've made,
it's buggy and very slow */
}
i_aspect = ffmpeg_FfAspect( i_width, i_height, i_aspect );
/* 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 = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
FIND_CHILD );
if( !p_vout )
{
p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
FIND_ANYWHERE );
}
if( p_vout )
{
if( !ffmpeg_CheckVout( p_vout,
i_width, i_height, i_aspect,i_chroma ) )
{
/* We are not interested in this format, close this vout */
vlc_object_detach( p_vout );
vlc_object_release( p_vout );
vout_DestroyThread( p_vout );
p_vout = NULL;
}
else
{
/* This video output is cool! Hijack it. */
vlc_object_detach( p_vout );
vlc_object_attach( p_vout, p_vdec->p_fifo );
vlc_object_release( p_vout );
}
}
if( p_vout == NULL )
{
msg_Dbg( p_vdec->p_fifo, "no vout present, spawning one" );
p_vout = vout_CreateThread( p_vdec->p_fifo,
i_width, i_height,
i_chroma, i_aspect );
}
return( p_vout );
}
/* FIXME FIXME FIXME this is a big shit
does someone want to rewrite this function ?
or said to me how write a better thing
FIXME FIXME FIXME
*/
static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
AVPicture *p_avpicture,
videodec_thread_t *p_vdec )
{
u8 *p_src, *p_dst;
u8 *p_plane[3];
int i_plane;
int i_stride, i_lines;
int i_height, i_width;
int i_y, i_x;
i_height = p_vdec->p_context->height;
i_width = p_vdec->p_context->width;
p_dst = p_pic->p[0].p_pixels;
p_src = p_avpicture->data[0];
/* copy first plane */
for( i_y = 0; i_y < i_height; i_y++ )
{
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width);
p_dst += p_pic->p[0].i_pitch;
p_src += p_avpicture->linesize[0];
}
/* process each plane in a temporary buffer */
for( i_plane = 1; i_plane < 3; i_plane++ )
{
i_stride = p_avpicture->linesize[i_plane];
i_lines = i_height / 4;
p_dst = p_plane[i_plane] = malloc( i_lines * i_stride * 2 * 2 );
p_src = p_avpicture->data[i_plane];
/* for each source line */
for( i_y = 0; i_y < i_lines; i_y++ )
{
for( i_x = 0; i_x < i_stride - 1; i_x++ )
{
p_dst[2 * i_x ] = p_src[i_x];
p_dst[2 * i_x + 1] = ( p_src[i_x] + p_src[i_x + 1]) / 2;
}
p_dst[2 * i_stride - 2] = p_src[i_x];
p_dst[2 * i_stride - 1] = p_src[i_x];
p_dst += 4 * i_stride; /* process the next even lines */
p_src += i_stride;
}
}
for( i_plane = 1; i_plane < 3; i_plane++ )
{
i_stride = p_avpicture->linesize[i_plane];
i_lines = i_height / 4;
p_dst = p_plane[i_plane] + 2*i_stride;
p_src = p_plane[i_plane];
for( i_y = 0; i_y < i_lines - 1; i_y++ )
{
for( i_x = 0; i_x < 2 * i_stride ; i_x++ )
{
p_dst[i_x] = ( p_src[i_x] + p_src[i_x + 4*i_stride])/2;
}
p_dst += 4 * i_stride; /* process the next odd lines */
p_src += 4 * i_stride;
}
/* last line */
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, 2*i_stride );
}
/* copy to p_pic, by block
if I do pixel per pixel it segfault. It's why I use
temporaries buffers */
for( i_plane = 1; i_plane < 3; i_plane++ )
{
int i_size;
p_src = p_plane[i_plane];
p_dst = p_pic->p[i_plane].p_pixels;
i_size = __MIN( 2*i_stride, p_pic->p[i_plane].i_pitch);
for( i_y = 0; i_y < __MIN(p_pic->p[i_plane].i_lines, 2 * i_lines); i_y++ )
{
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
p_src += 2 * i_stride;
p_dst += p_pic->p[i_plane].i_pitch;
}
free( p_plane[i_plane] );
}
}
static void ffmpeg_GetPicture( picture_t *p_pic,
AVPicture *p_avpicture,
videodec_thread_t *p_vdec )
{
int i_plane;
int i_size;
int i_line;
u8 *p_dst;
u8 *p_src;
int i_src_stride;
int i_dst_stride;
if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
{
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
p_src = p_avpicture->data[i_plane];
p_dst = p_pic->p[i_plane].p_pixels;
i_src_stride = p_avpicture->linesize[i_plane];
i_dst_stride = p_pic->p[i_plane].i_pitch;
i_size = __MIN( i_src_stride, i_dst_stride );
for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
{
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
p_src += i_src_stride;
p_dst += i_dst_stride;
}
}
if( ( p_vdec->i_pp_mode )&&
( ( p_vdec->p_vout->render.i_chroma ==
VLC_FOURCC( 'I','4','2','0' ) )||
( p_vdec->p_vout->render.i_chroma ==
VLC_FOURCC( 'Y','V','1','2' ) ) ) )
{
/* Make postproc */
#if LIBAVCODEC_BUILD > 4313
p_vdec->p_pp->pf_postprocess( p_pic,
p_vdec->p_context->quant_store,
p_vdec->p_context->qstride,
p_vdec->i_pp_mode );
#endif
}
}
else
{
/* we need to convert to I420 */
switch( p_vdec->p_context->pix_fmt )
{
#if LIBAVCODEC_BUILD >= 4615
case( PIX_FMT_YUV410P ):
ffmpeg_ConvertPictureI410toI420( p_pic, p_avpicture, p_vdec );
break;
#endif
default:
p_vdec->p_fifo->b_error = 1;
break;
}
}
}
/*****************************************************************************
*
* Functions that initialize, decode and end the decoding process
......@@ -564,404 +238,282 @@ static void ffmpeg_GetPicture( picture_t *p_pic,
* ffmpeg codec will be open, some memory allocated. But Vout is not yet
* open (done after the first decoded frame)
*****************************************************************************/
static int InitThread( videodec_thread_t *p_vdec )
{
int i_ffmpeg_codec;
int i_tmp;
if( p_vdec->p_fifo->p_demux_data )
{
ffmpeg_ParseBitMapInfoHeader( &p_vdec->format,
(u8*)p_vdec->p_fifo->p_demux_data );
}
else
{
msg_Warn( p_vdec->p_fifo, "display informations missing" );
}
static int InitThread( generic_thread_t *p_decoder )
{
int i_result;
/* **** init ffmpeg library (libavcodec) ***** */
/* *** init ffmpeg library (libavcodec) *** */
if( !b_ffmpeginit )
{
avcodec_init();
avcodec_register_all();
b_ffmpeginit = 1;
msg_Dbg( p_vdec->p_fifo, "library ffmpeg initialized" );
msg_Dbg( p_decoder->p_fifo, "library ffmpeg initialized" );
}
else
{
msg_Dbg( p_vdec->p_fifo, "library ffmpeg already initialized" );
msg_Dbg( p_decoder->p_fifo, "library ffmpeg already initialized" );
}
/* ***** Search for codec ***** */
ffmpeg_GetFfmpegCodec( p_vdec->p_fifo->i_fourcc,
&i_ffmpeg_codec,
&p_vdec->psz_namecodec );
p_vdec->p_codec =
avcodec_find_decoder( i_ffmpeg_codec );
/* *** determine codec type *** */
ffmpeg_GetFfmpegCodec( p_decoder->p_fifo->i_fourcc,
&p_decoder->i_cat,
&p_decoder->i_codec_id,
&p_decoder->psz_namecodec );
if( !p_vdec->p_codec )
/* *** ask ffmpeg for a decoder *** */
if( !( p_decoder->p_codec =
avcodec_find_decoder( p_decoder->i_codec_id ) ) )
{
msg_Err( p_vdec->p_fifo, "codec not found (%s)",
p_vdec->psz_namecodec );
msg_Err( p_decoder->p_fifo,
"codec not found (%s)",
p_decoder->psz_namecodec );
return( -1 );
}
/* ***** Fill p_context with init values ***** */
/* *** Get a p_context *** */
#if LIBAVCODEC_BUILD >= 4624
p_vdec->p_context = avcodec_alloc_context();
p_decoder->p_context = avcodec_alloc_context();
#else
p_vdec->p_context = malloc( sizeof( AVCodecContext ) );
memset( p_vdec->p_context, 0, sizeof( AVCodecContext ) );
#endif
p_vdec->p_context->width = p_vdec->format.i_width;
p_vdec->p_context->height = p_vdec->format.i_height;
/* ***** Get configuration of ffmpeg plugin ***** */
#if LIBAVCODEC_BUILD >= 4611
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 );
#endif
#if LIBAVCODEC_BUILD >= 4614
if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
{
p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
}
p_decoder->p_context = malloc( sizeof( AVCodecContext ) );
memset( p_decoder->p_context, 0, sizeof( AVCodecContext ) );
#endif
p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
/* ***** Open the codec ***** */
if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0)
switch( p_decoder->i_cat )
{
msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
p_vdec->psz_namecodec );
return( -1 );
}
else
{
msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
p_vdec->psz_namecodec );
}
/* ***** init this codec with special data ***** */
if( p_vdec->format.i_data )
{
AVPicture avpicture;
int b_gotpicture;
switch( i_ffmpeg_codec )
{
case( CODEC_ID_MPEG4 ):
avcodec_decode_video( p_vdec->p_context, &avpicture,
&b_gotpicture,
p_vdec->format.p_data,
p_vdec->format.i_data );
case VIDEO_ES:
i_result = E_( InitThread_Video )( (vdec_thread_t*)p_decoder );
break;
default:
if( p_vdec->p_fifo->i_fourcc == FOURCC_MP4S ||
p_vdec->p_fifo->i_fourcc == FOURCC_mp4s ||
p_vdec->p_fifo->i_fourcc == FOURCC_M4S2 ||
p_vdec->p_fifo->i_fourcc == FOURCC_m4s2 )
{
p_vdec->p_context->extradata_size = p_vdec->format.i_data;
p_vdec->p_context->extradata = malloc( p_vdec->format.i_data );
memcpy( p_vdec->p_context->extradata,
p_vdec->format.p_data,
p_vdec->format.i_data );
}
break;
}
}
/* ***** Load post processing ***** */
/* get overridding settings */
p_vdec->i_pp_mode = 0;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
p_vdec->i_pp_mode |= PP_DERING_Y;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
p_vdec->i_pp_mode |= PP_DERING_C;
if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" ) )||
( p_vdec->i_pp_mode != 0 ) )
{
/* check if the codec support postproc. */
switch( i_ffmpeg_codec )
{
#if LIBAVCODEC_BUILD > 4608
case( CODEC_ID_MSMPEG4V1 ):
case( CODEC_ID_MSMPEG4V2 ):
case( CODEC_ID_MSMPEG4V3 ):
#else
case( CODEC_ID_MSMPEG4 ):
#endif
case( CODEC_ID_MPEG4 ):
case( CODEC_ID_H263 ):
// case( CODEC_ID_H263P ): I don't use it up to now
case( CODEC_ID_H263I ):
/* Ok we can make postprocessing :)) */
/* first try to get a postprocess module */
#if LIBAVCODEC_BUILD > 4613
p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
sizeof( postprocessing_t ) );
p_vdec->p_pp->psz_object_name = "postprocessing";
p_vdec->p_pp->p_module =
module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
if( !p_vdec->p_pp->p_module )
{
msg_Warn( p_vdec->p_fifo,
"no suitable postprocessing module" );
vlc_object_destroy( p_vdec->p_pp );
p_vdec->p_pp = NULL;
p_vdec->i_pp_mode = 0;
}
else
{
/* get mode upon quality */
p_vdec->i_pp_mode |=
p_vdec->p_pp->pf_getmode(
config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
);
/* allocate table for postprocess */
p_vdec->p_context->quant_store =
malloc( sizeof( int ) * ( MBR + 1 ) * ( MBC + 1 ) );
p_vdec->p_context->qstride = MBC + 1;
}
#else
p_vdec->i_pp_mode = 0;
msg_Warn( p_vdec->p_fifo,
"post-processing not supported, upgrade ffmpeg" );
#endif
case AUDIO_ES:
i_result = E_( InitThread_Audio )( (adec_thread_t*)p_decoder );
break;
default:
p_vdec->i_pp_mode = 0;
msg_Warn( p_vdec->p_fifo,
"Post processing unsupported for this codec" );
break;
i_result = -1;
}
}
// memset( &p_vdec->statistic, 0, sizeof( statistic_t ) );
return( 0 );
p_decoder->pts = 0;
return( i_result );
}
/*****************************************************************************
* DecodeThread: Called for decode one frame
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static void DecodeThread( videodec_thread_t *p_vdec )
static void EndThread( generic_thread_t *p_decoder )
{
pes_packet_t *p_pes;
int i_frame_size;
int i_status;
int b_drawpicture;
int b_gotpicture;
AVPicture avpicture; /* ffmpeg picture */
picture_t *p_pic; /* videolan picture */
/* we have to get a frame stored in a pes
give it to ffmpeg decoder
and send the image to the output */
/* 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 LIBAVCODEC_BUILD > 4603
b_drawpicture = 0;
if( p_vdec->i_frame_late < 8 )
{
p_vdec->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;
}
#else
if( p_vdec->i_frame_late < 8 )
{
b_drawpicture = 0; /* not really good but .. UPGRADE FFMPEG !! */
}
else
if( !p_decoder )
{
/* 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;
}
#endif
}
else
{
b_drawpicture = 1;
#if LIBAVCODEC_BUILD > 4603
p_vdec->p_context->hurry_up = 0;
#endif
}
do
if( p_decoder->p_context != NULL)
{
input_ExtractPES( p_vdec->p_fifo, &p_pes );
if( !p_pes )
{
p_vdec->p_fifo->b_error = 1;
return;
FREE( p_decoder->p_context->quant_store );
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 );
}
p_vdec->i_pts = p_pes->i_pts;
i_frame_size = p_pes->i_pes_size;
if( i_frame_size > 0 )
{
if( p_vdec->i_buffer < i_frame_size + 16 )
FREE( p_decoder->p_buffer );
switch( p_decoder->i_cat )
{
FREE( p_vdec->p_buffer );
p_vdec->p_buffer = malloc( i_frame_size + 16 );
p_vdec->i_buffer = i_frame_size + 16;
case AUDIO_ES:
E_( EndThread_Audio )( (adec_thread_t*)p_decoder );
break;
case VIDEO_ES:
E_( EndThread_Video )( (vdec_thread_t*)p_decoder );
break;
}
GetPESData( p_vdec->p_buffer, p_vdec->i_buffer, p_pes );
}
input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
} while( i_frame_size <= 0 );
free( p_decoder );
}
/*****************************************************************************
* locales Functions
*****************************************************************************/
i_status = avcodec_decode_video( p_vdec->p_context,
&avpicture,
&b_gotpicture,
p_vdec->p_buffer,
i_frame_size );
void E_( GetPESData )( u8 *p_buf, int i_max, pes_packet_t *p_pes )
{
int i_copy;
int i_count;
data_packet_t *p_data;
if( i_status < 0 )
{
msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
i_frame_size );
p_vdec->i_frame_error++;
return;
}
/* Update frame late count*/
/* I don't make statistic on decoding time */
if( p_vdec->i_pts <= mdate())
{
p_vdec->i_frame_late++;
}
else
i_count = 0;
p_data = p_pes->p_first;
while( p_data != NULL && i_count < i_max )
{
p_vdec->i_frame_late = 0;
}
if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture)
{
return;
}
i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
i_max - i_count );
/* Check our vout */
if( !ffmpeg_CheckVout( p_vdec->p_vout,
p_vdec->p_context->width,
p_vdec->p_context->height,
p_vdec->p_context->aspect_ratio_info,
ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) )
{
p_vdec->p_vout =
ffmpeg_CreateVout( p_vdec,
p_vdec->p_context->width,
p_vdec->p_context->height,
p_vdec->p_context->aspect_ratio_info,
ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt));
if( !p_vdec->p_vout )
if( i_copy > 0 )
{
msg_Err( p_vdec->p_fifo, "cannot create vout" );
p_vdec->p_fifo->b_error = 1; /* abort */
return;
memcpy( p_buf,
p_data->p_payload_start,
i_copy );
}
p_data = p_data->p_next;
i_count += i_copy;
p_buf += i_copy;
}
/* Get a new picture */
while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
{
if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
if( i_count < i_max )
{
return;
}
msleep( VOUT_OUTMEM_SLEEP );
memset( p_buf, 0, i_max - i_count );
}
/* fill p_picture_t from avpicture, do I410->I420 if needed
and do post-processing if requested */
ffmpeg_GetPicture( p_pic, &avpicture, p_vdec );
}
/* FIXME correct avi and use i_dts */
/* Send decoded frame to vout */
vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->i_pts);
vout_DisplayPicture( p_vdec->p_vout, p_pic );
static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
int *pi_cat,
int *pi_ffmpeg_codec,
char **ppsz_name )
{
int i_cat;
int i_codec;
char *psz_name;
switch( i_fourcc )
{
#if LIBAVCODEC_BUILD >= 4608
case FOURCC_DIV1:
case FOURCC_div1:
case FOURCC_MPG4:
case FOURCC_mpg4:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSMPEG4V1;
psz_name = "MS MPEG-4 v1";
break;
return;
}
case FOURCC_DIV2:
case FOURCC_div2:
case FOURCC_MP42:
case FOURCC_mp42:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MSMPEG4V2;
psz_name = "MS MPEG-4 v2";
break;
#endif
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_3IV1:
i_cat = VIDEO_ES;
#if LIBAVCODEC_BUILD >= 4608
i_codec = CODEC_ID_MSMPEG4V3;
#else
i_codec = CODEC_ID_MSMPEG4;
#endif
psz_name = "MS MPEG-4 v3";
break;
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static void EndThread( videodec_thread_t *p_vdec )
{
#if LIBAVCODEC_BUILD >= 4615
case FOURCC_SVQ1:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_SVQ1;
psz_name = "SVQ-1 (Sorenson Video v1)";
break;
#endif
if( !p_vdec )
{
return;
}
if( p_vdec->p_pp )
{
/* release postprocessing module */
module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
vlc_object_destroy( p_vdec->p_pp );
p_vdec->p_pp = NULL;
}
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_3IV2:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MPEG4;
psz_name = "MPEG-4";
break;
/* FIXME FOURCC_H263P exist but what fourcc ? */
case FOURCC_H263:
case FOURCC_h263:
case FOURCC_U263:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_H263;
psz_name = "H263";
break;
case FOURCC_I263:
case FOURCC_i263:
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:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_WMV2;
psz_name ="Windows Media Video 2";
break;
#if LIBAVCODEC_BUILD >= 4632
case FOURCC_WMA1:
case FOURCC_wma1:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_WMAV1;
psz_name ="Windows Media Audio 1";
break;
case FOURCC_WMA2:
case FOURCC_wma2:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_WMAV2;
psz_name ="Windows Media Audio 2";
break;
default:
i_cat = UNKNOWN_ES;
i_codec = CODEC_ID_NONE;
psz_name = NULL;
break;
#endif
if( p_vdec->p_context != NULL)
{
FREE( p_vdec->p_context->quant_store );
FREE( p_vdec->p_context->extradata );
avcodec_close( p_vdec->p_context );
msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) stopped",
p_vdec->psz_namecodec );
free( p_vdec->p_context );
}
if( p_vdec->p_vout != NULL )
if( i_codec != CODEC_ID_NONE )
{
/* We are about to die. Reattach video output to p_vlc. */
vlc_object_detach( p_vdec->p_vout );
vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc );
if( pi_cat ) *pi_cat = i_cat;
if( pi_ffmpeg_codec ) *pi_ffmpeg_codec = i_codec;
if( ppsz_name ) *ppsz_name = psz_name;
return( VLC_TRUE );
}
FREE( p_vdec->format.p_data );
FREE( p_vdec->p_buffer );
free( p_vdec );
return( VLC_FALSE );
}
......@@ -2,7 +2,7 @@
* ffmpeg_vdec.h: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ffmpeg.h,v 1.6 2002/10/24 10:33:09 fenrir Exp $
* $Id: ffmpeg.h,v 1.7 2002/10/28 06:26:11 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -21,69 +21,44 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/* Pour un flux video */
typedef struct bitmapinfoheader_s
{
u32 i_size; /* size of header */
u32 i_width;
u32 i_height;
u16 i_planes;
u16 i_bitcount;
u32 i_compression;
u32 i_sizeimage;
u32 i_xpelspermeter;
u32 i_ypelspermeter;
u32 i_clrused;
u32 i_clrimportant;
int i_data;
u8 *p_data;
} bitmapinfoheader_t;
#if 0
typedef struct statistic_s
{
mtime_t i_frame_time[3]; /* total time to decode frame */
int i_frame_count[3]; /* number of frame to calculate frame_time */
int i_frame_late[3]; /* number of frame consecutively late */
int i_frame_skip[3]; /* number of frame skip */
#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 pts; \
\
/* Private stuff for frame gathering */ \
u8 *p_buffer; /* buffer for gather pes */ \
int i_buffer; /* size of allocated p_framedata */
} statistic_t;
#endif
typedef struct videodec_thread_s
typedef struct generic_thread_s
{
decoder_fifo_t *p_fifo;
bitmapinfoheader_t format;
DECODER_THREAD_COMMON
AVCodecContext *p_context;
AVCodec *p_codec;
vout_thread_t *p_vout;
} generic_thread_t;
/* for post processing */
u32 i_pp_mode; /* valid only with I420 and YV12 */
postprocessing_t *p_pp;
#define GetWLE( p ) \
( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) )
char *psz_namecodec;
#define GetDWLE( p ) \
( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) + \
( *((u8*)(p)+2) << 16 ) + ( *((u8*)(p)+3) << 24 ) )
/* for frame skipping algo */
// statistic_s statistic;
#define FREE( p ) if( p ) free( p ); p = NULL
int b_hurry_up;
int i_frame_error;
int i_frame_skip;
int i_frame_late; /* how may frame decoded are in late */
void E_( GetPESData )( u8 *p_buf, int i_max, pes_packet_t *p_pes );
/* private */
mtime_t i_pts;
u8 *p_buffer; /* buffer for gather pes */
int i_buffer; /* size of allocated p_framedata */
} videodec_thread_t;
/*****************************************************************************
* Video codec fourcc
*****************************************************************************/
/* MPEG4 video */
#define FOURCC_DIVX VLC_FOURCC('D','I','V','X')
......@@ -146,152 +121,12 @@ typedef struct videodec_thread_s
#define FOURCC_WMV1 VLC_FOURCC('W','M','V','1')
#define FOURCC_WMV2 VLC_FOURCC('W','M','V','2')
static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
int *pi_ffmpeg_codec,
char **ppsz_name )
{
int i_codec = 0;
char *psz_name = NULL;
switch( i_fourcc )
{
#if LIBAVCODEC_BUILD >= 4608
case FOURCC_DIV1:
case FOURCC_div1:
case FOURCC_MPG4:
case FOURCC_mpg4:
i_codec = CODEC_ID_MSMPEG4V1;
psz_name = "MS MPEG-4 v1";
break;
case FOURCC_DIV2:
case FOURCC_div2:
case FOURCC_MP42:
case FOURCC_mp42:
i_codec = CODEC_ID_MSMPEG4V2;
psz_name = "MS MPEG-4 v2";
break;
#endif
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_3IV1:
#if LIBAVCODEC_BUILD >= 4608
i_codec = CODEC_ID_MSMPEG4V3;
#else
i_codec = CODEC_ID_MSMPEG4;
#endif
psz_name = "MS MPEG-4 v3";
break;
#if LIBAVCODEC_BUILD >= 4615
case FOURCC_SVQ1:
i_codec = CODEC_ID_SVQ1;
psz_name = "SVQ-1 (Sorenson Video v1)";
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_3IV2:
i_codec = CODEC_ID_MPEG4;
psz_name = "MPEG-4";
break;
/* FIXME FOURCC_H263P exist but what fourcc ? */
case FOURCC_H263:
case FOURCC_h263:
case FOURCC_U263:
i_codec = CODEC_ID_H263;
psz_name = "H263";
break;
case FOURCC_I263:
case FOURCC_i263:
i_codec = CODEC_ID_H263I;
psz_name = "I263.I";
break;
case FOURCC_WMV1:
i_codec = CODEC_ID_WMV1;
psz_name ="Windows Media Video 1";
break;
case FOURCC_WMV2:
i_codec = CODEC_ID_WMV2;
psz_name ="Windows Media Video 2";
break;
}
if( i_codec )
{
if( pi_ffmpeg_codec ) *pi_ffmpeg_codec = i_codec;
if( ppsz_name ) *ppsz_name = psz_name;
return VLC_TRUE;
}
return VLC_FALSE;
}
/* FIXME FIXME some of them are wrong */
static int i_ffmpeg_PixFmtToChroma[] =
{
/* PIX_FMT_ANY = -1, PIX_FMT_YUV420P,
PIX_FMT_YUV422, PIX_FMT_RGB24,
PIX_FMT_BGR24, PIX_FMT_YUV422P,
PIX_FMT_YUV444P, PIX_FMT_YUV410P
*/
0, VLC_FOURCC('I','4','2','0'),
VLC_FOURCC('I','4','2','0'), VLC_FOURCC('R','V','2','4'),
0, VLC_FOURCC('Y','4','2','2'),
VLC_FOURCC('I','4','4','4'), 0
};
static inline u32 ffmpeg_PixFmtToChroma( int i_ffmpegchroma )
{
if( ++i_ffmpegchroma > 7 )
{
return( 0 );
}
else
{
return( i_ffmpeg_PixFmtToChroma[i_ffmpegchroma] );
}
}
static inline int ffmpeg_FfAspect( int i_width, int i_height, int i_ffaspect )
{
switch( i_ffaspect )
{
case( FF_ASPECT_4_3_625 ):
case( FF_ASPECT_4_3_525 ):
return( VOUT_ASPECT_FACTOR * 4 / 3);
case( FF_ASPECT_16_9_625 ):
case( FF_ASPECT_16_9_525 ):
return( VOUT_ASPECT_FACTOR * 16 / 9 );
case( FF_ASPECT_SQUARE ):
default:
return( VOUT_ASPECT_FACTOR * i_width / i_height );
}
}
/*****************************************************************************
* 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')
......@@ -2,7 +2,7 @@
* postprocessing_mmxext.c: Post Processing plugin MMXEXT
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: postprocessing_mmxext.c,v 1.2 2002/08/08 22:28:22 sam Exp $
* $Id: postprocessing_mmxext.c,v 1.3 2002/10/28 06:26:11 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -44,6 +44,15 @@
static const unsigned long long foo __asm__ (#foo) __attribute__((unused))
/* to calculate isDC_mode for mmx */
UNUSED_LONGLONG( mmx_thr1 ) = ( PP_THR1 << 56 )|
( PP_THR1 << 48 )|
( PP_THR1 << 40 )|
( PP_THR1 << 32 )|
( PP_THR1 << 24 )|
( PP_THR1 << 16 )|
( PP_THR1 << 8 )|
( PP_THR1 );
UNUSED_LONGLONG( mmx_127_thr1 ) = ( ( 127ULL - PP_THR1 ) << 56 )|
( ( 127ULL - PP_THR1 ) << 48 )|
( ( 127ULL - PP_THR1 ) << 40 )|
......@@ -124,6 +133,7 @@ static inline int pp_deblock_isDC_mode( u8 *p_v )
we add 127-M with wrap around -> good value fit in [ 127-2*M, 127]
and if x >= 127 - 2 * M ie x > 127 -2*M - 1 value is good
*/
#if 0
__asm__ __volatile__ (" \n\
#* Do (v0-v1) to (v7-v8) \n\
movq (%1), %%mm1 # load v0->v7 \n\
......@@ -138,6 +148,20 @@ static inline int pp_deblock_isDC_mode( u8 *p_v )
andl $255, %0"
: "=r"(i_eq_cnt) : "r" (p_v) );
#endif
__asm__ __volatile__ (" \n\
#* Do (v0-v1) to (v7-v8) \n\
movq (%1), %%mm1 # load v0->v7 \n\
pxor %%mm0, %%mm0 # mm0 = 0 \n\
movq 1(%1), %%mm2 # load v1->v8 \n\
psubb %%mm2, %%mm1 # v[i]-v[i+1] \n\
paddb mmx_127_thr1, %%mm1 # + 127-THR1 with wrap \n\
pcmpgtb mmx_127_2xthr1_1, %%mm1 # > 127 -2*thr1 - 1 \n\
psadbw %%mm1, %%mm0 \n\
movd %%mm0, %0 # \n\
negl %0"
: "=r"(i_eq_cnt) : "r" (p_v) );
/* last test, hey, 9 don't fit in MMX */
if(( ( p_v[8] - p_v[9] + PP_THR1 )&0xffff )<= PP_2xTHR1 )
......
/*****************************************************************************
* video.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: video.c,v 1.1 2002/10/28 06:26:11 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* getpid() */
#endif
#include <errno.h>
#include <string.h>
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include "avcodec.h" /* ffmpeg */
#include "postprocessing/postprocessing.h"
#include "ffmpeg.h"
#include "video.h"
/*
* Local prototypes
*/
int E_( InitThread_Video ) ( vdec_thread_t * );
void E_( EndThread_Video ) ( vdec_thread_t * );
void E_( DecodeThread_Video ) ( vdec_thread_t * );
/* FIXME FIXME some of them are wrong */
static int i_ffmpeg_PixFmtToChroma[] =
{
/* PIX_FMT_ANY = -1, PIX_FMT_YUV420P,
PIX_FMT_YUV422, PIX_FMT_RGB24,
PIX_FMT_BGR24, PIX_FMT_YUV422P,
PIX_FMT_YUV444P, PIX_FMT_YUV410P
*/
0, VLC_FOURCC('I','4','2','0'),
VLC_FOURCC('I','4','2','0'), VLC_FOURCC('R','V','2','4'),
0, VLC_FOURCC('Y','4','2','2'),
VLC_FOURCC('I','4','4','4'), 0
};
static inline u32 ffmpeg_PixFmtToChroma( int i_ffmpegchroma )
{
if( ++i_ffmpegchroma > 7 )
{
return( 0 );
}
else
{
return( i_ffmpeg_PixFmtToChroma[i_ffmpegchroma] );
}
}
static inline int ffmpeg_FfAspect( int i_width, int i_height, int i_ffaspect )
{
switch( i_ffaspect )
{
case( FF_ASPECT_4_3_625 ):
case( FF_ASPECT_4_3_525 ):
return( VOUT_ASPECT_FACTOR * 4 / 3);
case( FF_ASPECT_16_9_625 ):
case( FF_ASPECT_16_9_525 ):
return( VOUT_ASPECT_FACTOR * 16 / 9 );
case( FF_ASPECT_SQUARE ):
default:
return( VOUT_ASPECT_FACTOR * i_width / i_height );
}
}
/*****************************************************************************
* locales Functions
*****************************************************************************/
static void ffmpeg_ParseBitMapInfoHeader( bitmapinfoheader_t *p_bh,
u8 *p_data )
{
p_bh->i_size = GetDWLE( p_data );
p_bh->i_width = GetDWLE( p_data + 4 );
p_bh->i_height = GetDWLE( p_data + 8 );
p_bh->i_planes = GetWLE( p_data + 12 );
p_bh->i_bitcount = GetWLE( p_data + 14 );
p_bh->i_compression = GetDWLE( p_data + 16 );
p_bh->i_sizeimage = GetDWLE( p_data + 20 );
p_bh->i_xpelspermeter = GetDWLE( p_data + 24 );
p_bh->i_ypelspermeter = GetDWLE( p_data + 28 );
p_bh->i_clrused = GetDWLE( p_data + 32 );
p_bh->i_clrimportant = GetDWLE( p_data + 36 );
if( p_bh->i_size > 40 )
{
p_bh->i_data = p_bh->i_size - 40;
if( ( p_bh->p_data = malloc( p_bh->i_data ) ) )
{
memcpy( p_bh->p_data, p_data + 40, p_bh->i_data );
}
else
{
p_bh->i_data = 0;
}
}
else
{
p_bh->i_data = 0;
p_bh->p_data = NULL;
}
}
/* Check if we have a Vout with good parameters */
static int ffmpeg_CheckVout( vout_thread_t *p_vout,
int i_width,
int i_height,
int i_aspect,
int i_chroma )
{
if( !p_vout )
{
return( 0 );
}
if( !i_chroma )
{
/* we will try to make conversion */
i_chroma = VLC_FOURCC('I','4','2','0');
}
if( ( p_vout->render.i_width != i_width )||
( p_vout->render.i_height != i_height )||
( p_vout->render.i_chroma != i_chroma )||
( p_vout->render.i_aspect !=
ffmpeg_FfAspect( i_width, i_height, i_aspect ) ) )
{
return( 0 );
}
else
{
return( 1 );
}
}
/* Return a Vout */
static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t *p_vdec,
int i_width,
int i_height,
int i_aspect,
int i_chroma )
{
vout_thread_t *p_vout;
if( (!i_width)||(!i_height) )
{
return( NULL ); /* Can't create a new vout without display size */
}
if( !i_chroma )
{
/* we make conversion if possible*/
i_chroma = VLC_FOURCC('I','4','2','0');
msg_Warn( p_vdec->p_fifo, "Internal chroma conversion (FIXME)");
/* It's mainly for I410 -> I420 conversion that I've made,
it's buggy and very slow */
}
i_aspect = ffmpeg_FfAspect( i_width, i_height, i_aspect );
/* 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 = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
FIND_CHILD );
if( !p_vout )
{
p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT,
FIND_ANYWHERE );
}
if( p_vout )
{
if( !ffmpeg_CheckVout( p_vout,
i_width, i_height, i_aspect,i_chroma ) )
{
/* We are not interested in this format, close this vout */
vlc_object_detach( p_vout );
vlc_object_release( p_vout );
vout_DestroyThread( p_vout );
p_vout = NULL;
}
else
{
/* This video output is cool! Hijack it. */
vlc_object_detach( p_vout );
vlc_object_attach( p_vout, p_vdec->p_fifo );
vlc_object_release( p_vout );
}
}
if( p_vout == NULL )
{
msg_Dbg( p_vdec->p_fifo, "no vout present, spawning one" );
p_vout = vout_CreateThread( p_vdec->p_fifo,
i_width, i_height,
i_chroma, i_aspect );
}
return( p_vout );
}
/* FIXME FIXME FIXME this is a big shit
does someone want to rewrite this function ?
or said to me how write a better thing
FIXME FIXME FIXME
*/
static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
AVPicture *p_avpicture,
vdec_thread_t *p_vdec )
{
u8 *p_src, *p_dst;
u8 *p_plane[3];
int i_plane;
int i_stride, i_lines;
int i_height, i_width;
int i_y, i_x;
i_height = p_vdec->p_context->height;
i_width = p_vdec->p_context->width;
p_dst = p_pic->p[0].p_pixels;
p_src = p_avpicture->data[0];
/* copy first plane */
for( i_y = 0; i_y < i_height; i_y++ )
{
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width);
p_dst += p_pic->p[0].i_pitch;
p_src += p_avpicture->linesize[0];
}
/* process each plane in a temporary buffer */
for( i_plane = 1; i_plane < 3; i_plane++ )
{
i_stride = p_avpicture->linesize[i_plane];
i_lines = i_height / 4;
p_dst = p_plane[i_plane] = malloc( i_lines * i_stride * 2 * 2 );
p_src = p_avpicture->data[i_plane];
/* for each source line */
for( i_y = 0; i_y < i_lines; i_y++ )
{
for( i_x = 0; i_x < i_stride - 1; i_x++ )
{
p_dst[2 * i_x ] = p_src[i_x];
p_dst[2 * i_x + 1] = ( p_src[i_x] + p_src[i_x + 1]) / 2;
}
p_dst[2 * i_stride - 2] = p_src[i_x];
p_dst[2 * i_stride - 1] = p_src[i_x];
p_dst += 4 * i_stride; /* process the next even lines */
p_src += i_stride;
}
}
for( i_plane = 1; i_plane < 3; i_plane++ )
{
i_stride = p_avpicture->linesize[i_plane];
i_lines = i_height / 4;
p_dst = p_plane[i_plane] + 2*i_stride;
p_src = p_plane[i_plane];
for( i_y = 0; i_y < i_lines - 1; i_y++ )
{
for( i_x = 0; i_x < 2 * i_stride ; i_x++ )
{
p_dst[i_x] = ( p_src[i_x] + p_src[i_x + 4*i_stride])/2;
}
p_dst += 4 * i_stride; /* process the next odd lines */
p_src += 4 * i_stride;
}
/* last line */
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, 2*i_stride );
}
/* copy to p_pic, by block
if I do pixel per pixel it segfault. It's why I use
temporaries buffers */
for( i_plane = 1; i_plane < 3; i_plane++ )
{
int i_size;
p_src = p_plane[i_plane];
p_dst = p_pic->p[i_plane].p_pixels;
i_size = __MIN( 2*i_stride, p_pic->p[i_plane].i_pitch);
for( i_y = 0; i_y < __MIN(p_pic->p[i_plane].i_lines, 2 * i_lines); i_y++ )
{
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
p_src += 2 * i_stride;
p_dst += p_pic->p[i_plane].i_pitch;
}
free( p_plane[i_plane] );
}
}
static void ffmpeg_GetPicture( picture_t *p_pic,
AVPicture *p_avpicture,
vdec_thread_t *p_vdec )
{
int i_plane;
int i_size;
int i_line;
u8 *p_dst;
u8 *p_src;
int i_src_stride;
int i_dst_stride;
if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
{
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
p_src = p_avpicture->data[i_plane];
p_dst = p_pic->p[i_plane].p_pixels;
i_src_stride = p_avpicture->linesize[i_plane];
i_dst_stride = p_pic->p[i_plane].i_pitch;
i_size = __MIN( i_src_stride, i_dst_stride );
for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
{
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
p_src += i_src_stride;
p_dst += i_dst_stride;
}
}
if( ( p_vdec->i_pp_mode )&&
( ( p_vdec->p_vout->render.i_chroma ==
VLC_FOURCC( 'I','4','2','0' ) )||
( p_vdec->p_vout->render.i_chroma ==
VLC_FOURCC( 'Y','V','1','2' ) ) ) )
{
/* Make postproc */
#if LIBAVCODEC_BUILD > 4313
p_vdec->p_pp->pf_postprocess( p_pic,
p_vdec->p_context->quant_store,
p_vdec->p_context->qstride,
p_vdec->i_pp_mode );
#endif
}
}
else
{
/* we need to convert to I420 */
switch( p_vdec->p_context->pix_fmt )
{
#if LIBAVCODEC_BUILD >= 4615
case( PIX_FMT_YUV410P ):
ffmpeg_ConvertPictureI410toI420( p_pic, p_avpicture, p_vdec );
break;
#endif
default:
p_vdec->p_fifo->b_error = 1;
break;
}
}
}
/*****************************************************************************
*
* 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
*****************************************************************************
* 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)
*****************************************************************************/
int E_( InitThread_Video )( vdec_thread_t *p_vdec )
{
int i_tmp;
if( p_vdec->p_fifo->p_demux_data )
{
ffmpeg_ParseBitMapInfoHeader( &p_vdec->format,
(u8*)p_vdec->p_fifo->p_demux_data );
}
else
{
msg_Warn( p_vdec->p_fifo, "display informations missing" );
}
/* ***** Fill p_context with init values ***** */
p_vdec->p_context->width = p_vdec->format.i_width;
p_vdec->p_context->height = p_vdec->format.i_height;
/* ***** Get configuration of ffmpeg plugin ***** */
#if LIBAVCODEC_BUILD >= 4611
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 );
#endif
#if LIBAVCODEC_BUILD >= 4614
if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
{
p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
}
#endif
p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
/* ***** Open the codec ***** */
if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0)
{
msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
p_vdec->psz_namecodec );
return( -1 );
}
else
{
msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
p_vdec->psz_namecodec );
}
/* ***** init this codec with special data ***** */
if( p_vdec->format.i_data )
{
AVPicture avpicture;
int b_gotpicture;
switch( p_vdec->i_codec_id )
{
case( CODEC_ID_MPEG4 ):
avcodec_decode_video( p_vdec->p_context, &avpicture,
&b_gotpicture,
p_vdec->format.p_data,
p_vdec->format.i_data );
break;
default:
if( p_vdec->p_fifo->i_fourcc == FOURCC_MP4S ||
p_vdec->p_fifo->i_fourcc == FOURCC_mp4s ||
p_vdec->p_fifo->i_fourcc == FOURCC_M4S2 ||
p_vdec->p_fifo->i_fourcc == FOURCC_m4s2 )
{
p_vdec->p_context->extradata_size = p_vdec->format.i_data;
p_vdec->p_context->extradata = malloc( p_vdec->format.i_data );
memcpy( p_vdec->p_context->extradata,
p_vdec->format.p_data,
p_vdec->format.i_data );
}
break;
}
}
/* ***** Load post processing ***** */
/* get overridding settings */
p_vdec->i_pp_mode = 0;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
p_vdec->i_pp_mode |= PP_DERING_Y;
if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
p_vdec->i_pp_mode |= PP_DERING_C;
if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" ) )||
( p_vdec->i_pp_mode != 0 ) )
{
/* check if the codec support postproc. */
switch( p_vdec->i_codec_id )
{
#if LIBAVCODEC_BUILD > 4608
case( CODEC_ID_MSMPEG4V1 ):
case( CODEC_ID_MSMPEG4V2 ):
case( CODEC_ID_MSMPEG4V3 ):
#else
case( CODEC_ID_MSMPEG4 ):
#endif
case( CODEC_ID_MPEG4 ):
case( CODEC_ID_H263 ):
// case( CODEC_ID_H263P ): I don't use it up to now
case( CODEC_ID_H263I ):
/* Ok we can make postprocessing :)) */
/* first try to get a postprocess module */
#if LIBAVCODEC_BUILD > 4613
p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
sizeof( postprocessing_t ) );
p_vdec->p_pp->psz_object_name = "postprocessing";
p_vdec->p_pp->p_module =
module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
if( !p_vdec->p_pp->p_module )
{
msg_Warn( p_vdec->p_fifo,
"no suitable postprocessing module" );
vlc_object_destroy( p_vdec->p_pp );
p_vdec->p_pp = NULL;
p_vdec->i_pp_mode = 0;
}
else
{
/* get mode upon quality */
p_vdec->i_pp_mode |=
p_vdec->p_pp->pf_getmode(
config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
);
/* allocate table for postprocess */
p_vdec->p_context->quant_store =
malloc( sizeof( int ) * ( MBR + 1 ) * ( MBC + 1 ) );
p_vdec->p_context->qstride = MBC + 1;
}
#else
p_vdec->i_pp_mode = 0;
msg_Warn( p_vdec->p_fifo,
"post-processing not supported, upgrade ffmpeg" );
#endif
break;
default:
p_vdec->i_pp_mode = 0;
msg_Warn( p_vdec->p_fifo,
"Post processing unsupported for this codec" );
break;
}
}
// memset( &p_vdec->statistic, 0, sizeof( statistic_t ) );
return( 0 );
}
/*****************************************************************************
* DecodeThread: Called for decode one frame
*****************************************************************************/
void E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
{
pes_packet_t *p_pes;
int i_frame_size;
int i_status;
int b_drawpicture;
int b_gotpicture;
AVPicture avpicture; /* ffmpeg picture */
picture_t *p_pic; /* videolan picture */
/* we have to get a frame stored in a pes
give it to ffmpeg decoder
and send the image to the output */
/* 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 LIBAVCODEC_BUILD > 4603
b_drawpicture = 0;
if( p_vdec->i_frame_late < 8 )
{
p_vdec->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;
}
#else
if( p_vdec->i_frame_late < 8 )
{
b_drawpicture = 0; /* not really good but .. UPGRADE FFMPEG !! */
}
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;
}
#endif
}
else
{
b_drawpicture = 1;
#if LIBAVCODEC_BUILD > 4603
p_vdec->p_context->hurry_up = 0;
#endif
}
do
{
input_ExtractPES( p_vdec->p_fifo, &p_pes );
if( !p_pes )
{
p_vdec->p_fifo->b_error = 1;
return;
}
p_vdec->pts = p_pes->i_pts;
i_frame_size = p_pes->i_pes_size;
if( i_frame_size > 0 )
{
if( p_vdec->i_buffer < i_frame_size + 16 )
{
FREE( p_vdec->p_buffer );
p_vdec->p_buffer = malloc( i_frame_size + 16 );
p_vdec->i_buffer = i_frame_size + 16;
}
E_( GetPESData )( p_vdec->p_buffer, p_vdec->i_buffer, p_pes );
}
input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
} while( i_frame_size <= 0 );
i_status = avcodec_decode_video( p_vdec->p_context,
&avpicture,
&b_gotpicture,
p_vdec->p_buffer,
i_frame_size );
if( i_status < 0 )
{
msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
i_frame_size );
p_vdec->i_frame_error++;
return;
}
/* Update frame late count*/
/* I don't make statistic on decoding time */
if( p_vdec->pts <= mdate())
{
p_vdec->i_frame_late++;
}
else
{
p_vdec->i_frame_late = 0;
}
if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture)
{
return;
}
/* Check our vout */
if( !ffmpeg_CheckVout( p_vdec->p_vout,
p_vdec->p_context->width,
p_vdec->p_context->height,
p_vdec->p_context->aspect_ratio_info,
ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) )
{
p_vdec->p_vout =
ffmpeg_CreateVout( p_vdec,
p_vdec->p_context->width,
p_vdec->p_context->height,
p_vdec->p_context->aspect_ratio_info,
ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt));
if( !p_vdec->p_vout )
{
msg_Err( p_vdec->p_fifo, "cannot create vout" );
p_vdec->p_fifo->b_error = 1; /* abort */
return;
}
}
/* Get a new picture */
while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
{
if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
{
return;
}
msleep( VOUT_OUTMEM_SLEEP );
}
/* fill p_picture_t from avpicture, do I410->I420 if needed
and do post-processing if requested */
ffmpeg_GetPicture( p_pic, &avpicture, p_vdec );
/* FIXME correct avi and use i_dts */
/* Send decoded frame to vout */
vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->pts);
vout_DisplayPicture( p_vdec->p_vout, p_pic );
return;
}
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
void E_( EndThread_Video )( vdec_thread_t *p_vdec )
{
if( p_vdec->p_pp )
{
/* release postprocessing module */
module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
vlc_object_destroy( p_vdec->p_pp );
p_vdec->p_pp = NULL;
}
if( p_vdec->p_vout != NULL )
{
/* We are about to die. Reattach video output to p_vlc. */
vlc_object_detach( p_vdec->p_vout );
vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc );
}
FREE( p_vdec->format.p_data );
}
/*****************************************************************************
* video.h: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: video.h,v 1.1 2002/10/28 06:26:11 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.
*****************************************************************************/
/* for a video stream */
typedef struct bitmapinfoheader_s
{
u32 i_size; /* size of header */
u32 i_width;
u32 i_height;
u16 i_planes;
u16 i_bitcount;
u32 i_compression;
u32 i_sizeimage;
u32 i_xpelspermeter;
u32 i_ypelspermeter;
u32 i_clrused;
u32 i_clrimportant;
int i_data;
u8 *p_data;
} bitmapinfoheader_t;
typedef struct vdec_thread_s
{
DECODER_THREAD_COMMON
bitmapinfoheader_t format;
vout_thread_t *p_vout;
/* for post processing */
u32 i_pp_mode; /* valid only with I420 and YV12 */
postprocessing_t *p_pp;
/* for frame skipping algo */
// statistic_s statistic;
int b_hurry_up;
int i_frame_error;
int i_frame_skip;
int i_frame_late; /* how may frame decoded are in late */
} vdec_thread_t;
int E_( InitThread_Video ) ( vdec_thread_t * );
void E_( EndThread_Video ) ( vdec_thread_t * );
void E_( DecodeThread_Video ) ( vdec_thread_t * );
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