Commit 4144b604 authored by Laurent Aimar's avatar Laurent Aimar

* ./plugins/ac3_adec/* use _M to avoid conflict with libavcodec.a

* ./plugins/avi a light  avi demux
* ./plugins/ffmpeg a video decoder for divx v3 and opendivx
parent 76e16cfd
......@@ -2,7 +2,7 @@
* input_ext-dec.h: structures exported to the VideoLAN decoders
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: input_ext-dec.h,v 1.54 2002/03/14 01:35:28 stef Exp $
* $Id: input_ext-dec.h,v 1.55 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Michel Kaempf <maxx@via.ecp.fr>
......@@ -31,6 +31,8 @@
/* These ones might violate the norm : */
#define DVD_SPU_ES 0x82
#define LPCM_AUDIO_ES 0x83
#define MSMPEG4_VIDEO_ES 0x90
#define MPEG4_VIDEO_ES 0x91
#define UNKNOWN_ES 0xFF
/* Structures exported to the decoders */
......
......@@ -2,7 +2,7 @@
* ac3_adec.c: ac3 decoder module main file
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ac3_adec.c,v 1.27 2002/04/23 14:16:20 sam Exp $
* $Id: ac3_adec.c,v 1.28 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Michel Lespinasse <walken@zoy.org>
*
......@@ -214,7 +214,7 @@ static int InitThread( ac3dec_thread_t * p_ac3thread )
IMDCT->w_64 = vlc_memalign( 16, 64 * sizeof(complex_t),
&IMDCT->w_64_orig );
ac3_init( p_ac3thread->ac3_decoder );
_M( ac3_init )( p_ac3thread->ac3_decoder );
/*
* Initialize the output properties
......
......@@ -2,7 +2,7 @@
* ac3_decoder.c: core ac3 decoder
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ac3_decoder.c,v 1.6 2001/12/30 07:09:54 sam Exp $
* $Id: ac3_decoder.c,v 1.7 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Michel Lespinasse <walken@zoy.org>
......@@ -45,10 +45,10 @@
static const float cmixlev_lut[4] = { 0.707, 0.595, 0.500, 0.707 };
static const float smixlev_lut[4] = { 0.707, 0.500, 0.0 , 0.500 };
int ac3_init (ac3dec_t * p_ac3dec)
int _M( ac3_init )(ac3dec_t * p_ac3dec)
{
p_ac3dec->mantissa.lfsr_state = 1; /* dither_gen initialization */
imdct_init(p_ac3dec->imdct);
_M( imdct_init )(p_ac3dec->imdct) ;
return 0;
}
......
......@@ -2,7 +2,7 @@
* ac3_decoder.h : ac3 decoder interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: ac3_decoder.h,v 1.3 2002/04/05 01:05:22 gbazin Exp $
* $Id: ac3_decoder.h,v 1.4 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Renaud Dartus <reno@videolan.org>
......@@ -35,7 +35,7 @@ typedef struct ac3_sync_info_s {
/**** ac3 decoder API - functions publically provided by the ac3 decoder ****/
int ac3_init (ac3dec_t * p_ac3dec);
int _M( ac3_init )(ac3dec_t * p_ac3dec);
int ac3_sync_frame (ac3dec_t * p_ac3dec, ac3_sync_info_t * p_sync_info);
int ac3_decode_frame (ac3dec_t * p_ac3dec, s16 * buffer);
......
......@@ -2,7 +2,7 @@
* ac3_imdct.c: ac3 DCT
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ac3_imdct.c,v 1.7 2001/12/30 07:09:54 sam Exp $
* $Id: ac3_imdct.c,v 1.8 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Aaron Holtzman <aholtzma@engr.uvic.ca>
......@@ -44,7 +44,7 @@
# define M_PI 3.14159265358979323846
#endif
void imdct_init(imdct_t * p_imdct)
void _M( imdct_init )(imdct_t * p_imdct)
{
int i;
float scale = 181.019;
......
......@@ -2,7 +2,7 @@
* ac3_internals.h: needed by the ac3 decoder
*****************************************************************************
* Copyright (C) 2000 VideoLAN
* $Id: ac3_internal.h,v 1.1 2001/11/13 12:09:17 henri Exp $
* $Id: ac3_internal.h,v 1.2 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Michel Lespinasse <walken@zoy.org>
*
......@@ -40,7 +40,7 @@ void bit_allocate (ac3dec_t *);
int exponent_unpack (ac3dec_t *);
/* ac3_imdct.c */
void imdct_init (imdct_t * p_imdct);
void _M( imdct_init )(imdct_t * p_imdct);
void imdct (ac3dec_t * p_ac3dec, s16 * buffer);
/* ac3_mantissa.c */
......
avi_SOURCES =
avi_SOURCES = avi.c
/*****************************************************************************
* avi.c : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: avi.c,v 1.1 2002/04/23 23:44:36 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 <string.h> /* strdup() */
#include <errno.h>
#include <sys/types.h>
#include <videolan/vlc.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*****************************************************************************
* Constants
*****************************************************************************/
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list );
static int AVIDemux ( struct input_thread_s * );
static int AVIInit ( struct input_thread_s * );
static void AVIEnd ( struct input_thread_s * );
/*****************************************************************************
* Build configuration tree.
*****************************************************************************/
MODULE_CONFIG_START
MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "RIFF-AVI Stream input" )
ADD_CAPABILITY( DEMUX, 150 )
ADD_SHORTCUT( "avi" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
input_getfunctions( &p_module->p_functions->demux );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Definition of structures and libraries for this plugins
*****************************************************************************/
#include "fourcc.h"
#include "libLE.c"
#include "libioRIFF.c"
#include "avi.h"
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.demux
input.pf_init = AVIInit;
input.pf_end = AVIEnd;
input.pf_demux = AVIDemux;
input.pf_rewind = NULL;
#undef input
}
/********************************************************************/
static void __AVIFreeDemuxData( input_thread_t *p_input )
{
int i;
demux_data_avi_file_t *p_avi_demux;
p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data ;
if( p_avi_demux->p_riff != NULL )
RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_riff );
if( p_avi_demux->p_hdrl != NULL )
RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_hdrl );
if( p_avi_demux->p_movi != NULL )
RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_movi );
if( p_avi_demux->p_idx1 != NULL )
RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_idx1 );
return;
if( p_avi_demux->pp_info != NULL )
{
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
if( p_avi_demux->pp_info[i] != NULL )
{
#define p_info p_avi_demux->pp_info[i]
if( p_info->p_strl != NULL )
RIFF_DeleteChunk( p_input->p_demux_data, p_info->p_strl );
if( p_info->p_strh != NULL )
RIFF_DeleteChunk( p_input->p_demux_data,p_info->p_strh );
if( p_info->p_strf != NULL )
RIFF_DeleteChunk( p_input->p_demux_data,p_info->p_strf );
if( p_info->p_strd != NULL )
RIFF_DeleteChunk( p_input->p_demux_data,p_info->p_strd );
if( p_info->p_index != NULL )
free( p_info->p_index );
free( p_info );
#undef p_info
}
}
free( p_avi_demux->pp_info );
}
}
static void __AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
{
p_avih->i_microsecperframe = __GetDoubleWordLittleEndianFromBuff( p_buff );
p_avih->i_maxbytespersec = __GetDoubleWordLittleEndianFromBuff( p_buff + 4);
p_avih->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 8);
p_avih->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
p_avih->i_totalframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
p_avih->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
p_avih->i_streams = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
p_avih->i_suggestedbuffersize =
__GetDoubleWordLittleEndianFromBuff( p_buff + 28);
p_avih->i_width = __GetDoubleWordLittleEndianFromBuff( p_buff + 32 );
p_avih->i_height = __GetDoubleWordLittleEndianFromBuff( p_buff + 36 );
p_avih->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 40 );
p_avih->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 44 );
p_avih->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 48);
p_avih->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 52);
}
static void __AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
{
p_strh->i_type = __GetDoubleWordLittleEndianFromBuff( p_buff );
p_strh->i_handler = __GetDoubleWordLittleEndianFromBuff( p_buff + 4 );
p_strh->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 8 );
p_strh->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
p_strh->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
p_strh->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
p_strh->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
p_strh->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 28);
p_strh->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 32);
p_strh->i_suggestedbuffersize =
__GetDoubleWordLittleEndianFromBuff( p_buff + 36);
p_strh->i_quality = __GetDoubleWordLittleEndianFromBuff( p_buff + 40);
p_strh->i_samplesize = __GetDoubleWordLittleEndianFromBuff( p_buff + 44);
}
int avi_ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
{
h->i_size = __GetDoubleWordLittleEndianFromBuff( p_data );
h->i_width = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
h->i_height = __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
h->i_planes = __GetWordLittleEndianFromBuff( p_data + 12 );
h->i_bitcount = __GetWordLittleEndianFromBuff( p_data + 14 );
h->i_compression = __GetDoubleWordLittleEndianFromBuff( p_data + 16 );
h->i_sizeimage = __GetDoubleWordLittleEndianFromBuff( p_data + 20 );
h->i_xpelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 24 );
h->i_ypelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 28 );
h->i_clrused = __GetDoubleWordLittleEndianFromBuff( p_data + 32 );
h->i_clrimportant = __GetDoubleWordLittleEndianFromBuff( p_data + 36 );
return( 0 );
}
int avi_ParseWaveFormatEx( waveformatex_t *h, byte_t *p_data )
{
h->i_formattag = __GetWordLittleEndianFromBuff( p_data );
h->i_channels = __GetWordLittleEndianFromBuff( p_data + 2 );
h->i_samplespersec = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
h->i_avgbytespersec= __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
h->i_blockalign = __GetWordLittleEndianFromBuff( p_data + 12 );
h->i_bitspersample = __GetWordLittleEndianFromBuff( p_data + 14 );
h->i_size = __GetWordLittleEndianFromBuff( p_data + 16 );
return( 0 );
}
static int __AVI_ParseStreamHeader( u32 i_id, int *i_number, u16 *i_type )
{
int c1,c2,c3,c4;
char str[3];
c1 = ( i_id ) & 0xFF;
c2 = ( i_id >> 8 ) & 0xFF;
c3 = ( i_id >> 16 ) & 0xFF;
c4 = ( i_id >> 24 ) & 0xFF;
if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
{
return( -1 );
}
str[0] = c1;
str[1] = c2;
str[2] = 0;
*i_number = atoi( str );
*i_type = ( c3 << 8) + c4;
return( 0 );
}
static int __AVI_HeaderMoviValid( u32 i_header )
{
switch( i_header&0xFFFF0000 )
{
case( TWOCC_wb ):
case( TWOCC_db ):
case( TWOCC_dc ):
case( TWOCC_pc ):
return( 1 );
break;
}
switch( i_header )
{
case( FOURCC_LIST ):
case( FOURCC_JUNK ):
return( 1 );
break;
}
return( 0 );
}
static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
AVIIndexEntry_t *p_index)
{
if( p_info->p_index == NULL )
{
p_info->i_idxmax = 4096;
p_info->i_idxnb = 0;
p_info->p_index = calloc( p_info->i_idxmax,
sizeof( AVIIndexEntry_t ) );
}
if( p_info->i_idxnb >= p_info->i_idxmax )
{
p_info->i_idxmax += 4096;
p_info->p_index = realloc( (void*)p_info->p_index,
p_info->i_idxmax *
sizeof( AVIIndexEntry_t ) );
}
/* calculate cumulate length */
if( p_info->i_idxnb > 0 )
{
p_index->i_lengthtotal = p_index->i_length +
p_info->p_index[p_info->i_idxnb-1].i_lengthtotal;
}
else
{
p_index->i_lengthtotal = 0;
}
p_info->p_index[p_info->i_idxnb] = *p_index;
p_info->i_idxnb++;
}
static void __AVI_GetIndex( input_thread_t *p_input )
{
demux_data_avi_file_t *p_avi_demux;
AVIIndexEntry_t index;
byte_t *p_buff;
riffchunk_t *p_idx1;
int i_read;
int i;
int i_number;
u16 i_type;
p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data ;
if( RIFF_FindAndGotoDataChunk( p_input,
p_avi_demux->p_riff,
&p_idx1,
FOURCC_idx1)!=0 )
{
intf_WarnMsg( 1, "input init: cannot find index" );
RIFF_GoToChunk( p_input, p_avi_demux->p_hdrl );
return;
}
p_avi_demux->p_idx1 = p_idx1;
intf_WarnMsg( 1, "input init: loading index" );
for(;;)
{
if( (i_read = input_Peek( p_input, &p_buff, 16*1024 )) < 16 )
{
for( i = 0, i_read = 0; i < p_avi_demux->i_streams; i++ )
{
i_read += p_avi_demux->pp_info[i]->i_idxnb;
}
intf_WarnMsg( 1,"input info: read %d idx chunk", i_read );
return;
}
i_read /= 16 ;
/* try to verify if we are beyond end of p_idx1 */
for( i = 0; i < i_read; i++ )
{
byte_t *p_peek = p_buff + i * 16;
index.i_id = __GetDoubleWordLittleEndianFromBuff( p_peek );
index.i_flags = __GetDoubleWordLittleEndianFromBuff( p_peek+4);
index.i_offset = __GetDoubleWordLittleEndianFromBuff( p_peek+8);
index.i_length = __GetDoubleWordLittleEndianFromBuff(p_peek+12);
if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) != 0)
||(i_number > p_avi_demux->i_streams))
{
continue;
}
__AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
&index );
}
__RIFF_SkipBytes( p_input, 16 * i_read );
}
}
static int __AVI_SeekToChunk( input_thread_t *p_input, AVIStreamInfo_t *p_info )
{
demux_data_avi_file_t *p_avi_demux;
p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
if( (p_info->p_index != NULL)&&(p_info->i_idxpos < p_info->i_idxnb) )
{
/* perfect */
off_t i_pos;
i_pos = (off_t)p_info->p_index[p_info->i_idxpos].i_offset +
p_info->i_idxoffset;
p_input->pf_seek( p_input, i_pos );
input_AccessReinit( p_input );
return( 0 );
}
/* index are no longer valid */
if( p_info->p_index != NULL )
{
return( -1 );
}
/* no index */
return( -1 );
}
/* XXX call after get p_movi */
static int __AVI_GetIndexOffset( input_thread_t *p_input )
{
riffchunk_t *p_chunk;
demux_data_avi_file_t *p_avi_demux;
int i;
p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
#define p_info p_avi_demux->pp_info[i]
if( p_info->p_index == NULL ) {continue;}
p_info->i_idxoffset = 0;
__AVI_SeekToChunk( p_input, p_info );
p_chunk = RIFF_ReadChunk( p_input );
if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
{
p_info->i_idxoffset = p_avi_demux->p_movi->i_pos + 8;
__AVI_SeekToChunk( p_input, p_info );
p_chunk = RIFF_ReadChunk( p_input );
if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
{
intf_WarnMsg( 1, "input demux: can't find offset for stream %d",
i);
continue; /* TODO: search manually from p_movi */
}
}
#undef p_info
}
return( 0 );
}
static int __AVI_AudioGetType( u32 i_type )
{
switch( i_type )
{
/* case( WAVE_FORMAT_PCM ):
return( WAVE_AUDIO_ES ); */
case( WAVE_FORMAT_AC3 ):
return( AC3_AUDIO_ES );
case( WAVE_FORMAT_MPEG):
case( WAVE_FORMAT_MPEGLAYER3):
return( MPEG2_AUDIO_ES ); /* 2 for mpeg-2 layer 1 2 ou 3 */
default:
return( 0 );
}
}
static int __AVI_VideoGetType( u32 i_type )
{
switch( i_type )
{
case( FOURCC_DIV3 ):
case( FOURCC_div3 ):
case( FOURCC_DIV4 ):
case( FOURCC_div4 ):
case( FOURCC_DIV5 ):
case( FOURCC_div5 ):
case( FOURCC_DIV6 ):
case( FOURCC_div6 ):
case( FOURCC_3IV1 ):
case( FOURCC_AP41 ):
case( FOURCC_MP43 ):
case( FOURCC_mp43 ):
return( MSMPEG4_VIDEO_ES );
case( FOURCC_DIVX ):
case( FOURCC_divx ):
case( FOURCC_DX50 ):
case( FOURCC_MP4S ):
case( FOURCC_MPG4 ):
case( FOURCC_mpg4 ):
case( FOURCC_mp4v ):
return( MPEG4_VIDEO_ES );
default:
return( 0 );
}
}
/**************************************************************************/
/* Tention: bcp de test ajouter mais aussi beaucoup de MEMOIRE a DESALLOUER pas fait */
static int AVIInit( input_thread_t *p_input )
{
riffchunk_t *p_riff,*p_hdrl,*p_movi;
riffchunk_t *p_avih;
riffchunk_t *p_strl,*p_strh,*p_strf/* ,*p_strd */;
demux_data_avi_file_t *p_avi_demux;
es_descriptor_t *p_es = NULL; /* for not warning */
es_descriptor_t *p_es_video = NULL;
es_descriptor_t *p_es_audio = NULL;
int i,j;
p_avi_demux = malloc( sizeof(demux_data_avi_file_t) );
memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) );
p_input->p_demux_data = p_avi_demux;
/* FIXME FIXME Je sais pas trop a quoi ca sert juste copi de ESInit */
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
{
/* Improve speed. */
p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
}
if( RIFF_TestFileHeader( p_input, &p_riff, FOURCC_AVI ) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input: RIFF-AVI plug-in discarded (avi_file)" );
return( -1 );
}
p_avi_demux->p_riff = p_riff;
if ( RIFF_DescendChunk(p_input) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
return ( -1 );
}
/* it's a riff-avi file, so search for LIST-hdrl */
if( RIFF_FindListChunk(p_input ,&p_hdrl,p_riff, FOURCC_hdrl) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot find \"LIST-hdrl\" (avi_file)" );
return( -1 );
}
p_avi_demux->p_hdrl = p_hdrl;
if( RIFF_DescendChunk(p_input) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
return ( -1 );
}
/* ds LIST-hdrl cherche avih */
if( RIFF_FindAndLoadChunk( p_input, p_hdrl,
&p_avih, FOURCC_avih ) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot find \"avih\" chunk (avi_file)" );
return( -1 );
}
__AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start );
RIFF_DeleteChunk( p_input, p_avih );
if( p_avi_demux->avih.i_streams == 0 )
/* aucun flux defini, peut etre essayer de trouver ss connaitre */
/* le nombre serait pas mal, a voir */
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: no defined stream !" );
return( -1 );
}
/* On creer les tableau pr les flux */
p_avi_demux->i_streams = p_avi_demux->avih.i_streams;
p_avi_demux->pp_info = calloc( p_avi_demux->i_streams,
sizeof( AVIStreamInfo_t* ) );
memset( p_avi_demux->pp_info, 0,
sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams );
for( i = 0 ; i < p_avi_demux->i_streams; i++ )
{
p_avi_demux->pp_info[i] = malloc( sizeof(AVIStreamInfo_t ) );
memset( p_avi_demux->pp_info[i], 0, sizeof( AVIStreamInfo_t ) );
/* pour chaque flux on cherche ses infos */
if( RIFF_FindListChunk(p_input,
&p_strl,p_hdrl, FOURCC_strl) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot find \"LIST-strl\" (avi_file)" );
return( -1 );
}
p_avi_demux->pp_info[i]->p_strl = p_strl;
if( RIFF_DescendChunk(p_input) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
return ( -1 );
}
/* ds LIST-strl cherche strh */
if( RIFF_FindAndLoadChunk( p_input, p_hdrl,
&p_strh, FOURCC_strh ) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot find \"strh\" (avi_file)" );
return( -1 );
}
p_avi_demux->pp_info[i]->p_strh = p_strh;
/* ds LIST-strl cherche strf */
if( RIFF_FindAndLoadChunk( p_input, p_hdrl,
&p_strf, FOURCC_strf ) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot find \"strf\" (avi_file)" );
return( -1 );
}
p_avi_demux->pp_info[i]->p_strf = p_strf;
/* FIXME faudrait cherche et charger strd */
/* mais a priori pas vraiment utile pr divx */
if( RIFF_AscendChunk(p_input, p_strl) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot go out (\"strl\") (avi_file)" );
return( -1 );
}
}
if( RIFF_AscendChunk(p_input, p_hdrl) != 0)
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot go out (\"hdrl\") (avi_file)" );
return( -1 );
}
intf_Msg( "input init: AVIH: %d stream, flags %s%s%s%s%s%s ",
p_avi_demux->i_streams,
p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
p_avi_demux->avih.i_flags&AVIF_WASCAPTUREFILE?" CAPTUREFILE":"",
p_avi_demux->avih.i_flags&AVIF_COPYRIGHTED?" COPYRIGHTED":"" );
/* go to movi chunk */
if( RIFF_FindListChunk(p_input ,&p_movi,p_riff, FOURCC_movi) != 0 )
{
intf_ErrMsg( "input error: cannot find \"LIST-movi\" (avi_file)" );
__AVIFreeDemuxData( p_input );
return( -1 );
}
p_avi_demux->p_movi = p_movi;
/* get index */
if( (p_input->stream.b_seekable)
&&((p_avi_demux->avih.i_flags&AVIF_HASINDEX) != 0) )
{
__AVI_GetIndex( p_input );
/* try to get i_idxoffset with first stream*/
__AVI_GetIndexOffset( p_input );
RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
}
else
{
intf_WarnMsg( 1, "input init: cannot get index" );
}
if( RIFF_DescendChunk( p_input ) != 0 )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot go in (\"movi\") (avi_file)" );
return( -1 );
}
/* TODO: check for index and read it if possible( seekable )*/
/** We have now finished with reading the file **/
/** we make the last initialisation **/
if( input_InitStream( p_input, 0 ) == -1)
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot init stream" );
return( -1 );
}
if( input_AddProgram( p_input, 0, 0) == NULL )
{
__AVIFreeDemuxData( p_input );
intf_ErrMsg( "input error: cannot add program" );
return( -1 );
}
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
p_input->stream.p_new_program = p_input->stream.pp_programs[0] ;
/* FIXME FIXME id des es doit etre unique FIXME FIXME */
vlc_mutex_lock( &p_input->stream.stream_lock );
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
#define p_info p_avi_demux->pp_info[i]
__AVI_Parse_Header( &p_info->header,
p_info->p_strh->p_data->p_payload_start);
switch( p_info->header.i_type )
{
case( FOURCC_auds ):
/* pour l'id j'ai mis 12 pr audio et 42 pour video */
/* et le numero du flux(ici i) dans i_stream_id */
avi_ParseWaveFormatEx( &p_info->audio_format,
p_info->p_strf->p_data->p_payload_start );
p_es = input_AddES( p_input,
p_input->stream.p_selected_program, 12+i,
p_info->p_strf->i_size );
p_es->i_cat = AUDIO_ES;
p_es->b_audio = 1;
p_es->i_type =
__AVI_AudioGetType( p_info->audio_format.i_formattag );
if( p_es->i_type == 0 )
{
intf_ErrMsg( "input error: stream(%d,0x%x) not supported",
i,
p_info->audio_format.i_formattag );
p_es->i_cat = UNKNOWN_ES;
}
else
{
if( p_es_audio == NULL ) p_es_audio = p_es;
}
p_es->i_stream_id =i; /* FIXME */
break;
case( FOURCC_vids ):
avi_ParseBitMapInfoHeader( &p_info->video_format,
p_info->p_strf->p_data->p_payload_start );
p_es = input_AddES( p_input,
p_input->stream.p_selected_program, 42+i,
p_info->p_strf->i_size );
p_es->i_cat = VIDEO_ES;
p_es->b_audio = 0;
p_es->i_type =
__AVI_VideoGetType( p_info->video_format.i_compression );
if( p_es->i_type == 0 )
{
intf_ErrMsg( "input error: stream(%d,%4.4s) not supported",
i,
(char*)&p_info->video_format.i_compression);
}
else
{
if( p_es_video == NULL ) p_es_video = p_es;
}
p_es->i_stream_id =i; /* FIXME */
break;
default:
p_es = input_AddES( p_input,
p_input->stream.p_selected_program, 12,
p_info->p_strf->i_size );
intf_ErrMsg( "input error: unknown stream(%d) type",
i );
p_es->i_cat = UNKNOWN_ES;
break;
}
p_info->p_es = p_es;
p_info->i_cat = p_es->i_cat;
/* We copy strf for decoder in p_es->p_demux_data */
for( j = 0; j < p_info->p_strf->i_size; j++ )
{
*((byte_t*)p_es->p_demux_data + j) =
*(p_info->p_strf->p_data->p_payload_start + j);
}
/* print informations on stream */
switch( p_es->i_cat )
{
case( VIDEO_ES ):
intf_Msg("input init: video(%4.4s) %dx%d %dbpp %ffps (size %d)",
(char*)&p_info->video_format.i_compression,
p_info->video_format.i_width,
p_info->video_format.i_height,
p_info->video_format.i_bitcount,
(float)p_info->header.i_rate /
(float)p_info->header.i_scale,
p_info->header.i_samplesize );
break;
case( AUDIO_ES ):
intf_Msg( "input init: audio(0x%x) %d channels %dHz %dbits %ffps (size %d)",
p_info->audio_format.i_formattag,
p_info->audio_format.i_channels,
p_info->audio_format.i_samplespersec,
p_info->audio_format.i_bitspersample,
(float)p_info->header.i_rate /
(float)p_info->header.i_scale,
p_info->header.i_samplesize );
break;
}
#undef p_info
}
/* we select the first audio and video ES */
if( p_es_audio != NULL )
{
input_SelectES( p_input, p_es_audio );
}
else
{
intf_Msg( "input init: no audio stream found !" );
}
if( p_es_video != NULL )
{
input_SelectES( p_input, p_es_video );
}
else
{
intf_ErrMsg( "input error: no video stream found !" );
return( -1 );
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/* p_input->stream.p_selected_area->i_tell = 0; */
p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50;
p_input->stream.p_selected_program->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* stoker les donnes p_demux_data dans p_input */
return( 0 );
}
static void AVIEnd( input_thread_t *p_input )
{
__AVIFreeDemuxData( p_input );
return;
}
static mtime_t __AVI_GetPTSAudio( AVIStreamInfo_t *p_info )
{
/* XXX you need to had p_info->i_date to have correct pts */
/* p_info->p_index[p_info->i_idxpos] need to be valid !! */
mtime_t i_pts;
/* be careful to *1000000 before round ! */
if( p_info->header.i_samplesize != 0 )
{
i_pts = (mtime_t)( (double)1000000.0 *
(double)p_info->p_index[p_info->i_idxpos].i_lengthtotal *
(double)p_info->header.i_scale /
(double)p_info->header.i_rate);
}
else
{
i_pts = (mtime_t)( (double)1000000.0 *
(double)p_info->i_idxpos *
(double)p_info->header.i_scale /
(double)p_info->header.i_rate);
}
return( i_pts );
}
static mtime_t __AVI_GetPTSVideo( AVIStreamInfo_t *p_info )
{
/* XXX you need to had p_info->i_date to have correct pts */
mtime_t i_pts;
i_pts = (mtime_t)( (double)1000000.0 *
(double)p_info->i_idxpos *
(double)p_info->header.i_scale /
(double)p_info->header.i_rate);
return( i_pts );
}
static mtime_t __AVI_GetPTS( AVIStreamInfo_t *p_info )
{
switch( p_info->i_cat )
{
case( AUDIO_ES ):
return( __AVI_GetPTSAudio( p_info ) );
case( VIDEO_ES ):
return( __AVI_GetPTSVideo( p_info ) );
default:
return( mdate() + DEFAULT_PTS_DELAY );
}
}
static void __AVI_ControleUnPause()
{
}
static void __AVI_NextIndexEntry( input_thread_t *p_input,
AVIStreamInfo_t *p_info )
{
p_info->i_idxpos++;
if( p_info->i_idxpos >= p_info->i_idxnb )
{
/* we need to verify if we reach end of file
or if index is broken and search manually */
}
}
static void __AVI_ReInitDate( demux_data_avi_file_t *p_avi_demux )
{
mtime_t i_ptsmin = 0;
int i;
int b_first = 1;
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
#define p_info p_avi_demux->pp_info[i]
if( (p_info->p_es->p_decoder_fifo != NULL)
&&( !p_info->b_unselected ) )
{
i_ptsmin = __MIN( i_ptsmin,
__AVI_GetPTS( p_info ) );
if( b_first )
{
i_ptsmin = __AVI_GetPTS( p_info );
b_first = 0;
}
}
#undef p_info
}
p_avi_demux->i_date = mdate() + DEFAULT_PTS_DELAY - i_ptsmin;
}
static int __AVI_ReAlign( input_thread_t *p_input,
AVIStreamInfo_t *p_info )
{
u32 i_pos;
int i_idxpos;
__RIFF_TellPos( p_input, &i_pos );
/* TODO verifier si on est dans p_movi */
if( p_info->p_index[p_info->i_idxnb-1].i_offset +
p_info->i_idxoffset < i_pos )
{
return( -1 );
}
i_idxpos = p_info->i_idxpos;
i_pos -= p_info->i_idxoffset;
if( i_pos < 0 )
{
p_info->i_idxpos = 0;
return( 0 );
}
while( p_info->p_index[i_idxpos].i_offset > i_pos )
{
i_idxpos--;
if( i_idxpos <= 0 ) { return( -1 );}
}
while( p_info->p_index[i_idxpos].i_offset +
p_info->p_index[i_idxpos].i_length < i_pos )
{
i_idxpos++;
if( i_idxpos >= p_info->i_idxnb ) { return( -1 );}
}
p_info->i_idxpos = i_idxpos;
return( 0 );
}
/** -1 in case of error, 0 of EOF, 1 otherwise **/
static int AVIDemux( input_thread_t *p_input )
{
/* on cherche un block
plusieurs cas :
* encapsuler dans un chunk "rec "
* juste une succesion de 00dc 01wb ...
* pire tout audio puis tout video ou vice versa
*/
/*
From xine-lib :
static uint32_t get_audio_pts (demux_avi_t *this, long posc, long posb)
{
if (this->avi->dwSampleSize==0)
return posc * (double) this->avi->dwScale_audio / this->avi->dwRate_audio * 90000.0;
else
return (this->avi->audio_index[posc].tot+posb)/this->avi->dwSampleSize * (double) this->avi->dwScale_audio / this->avi->dwRate_audio * 90000.0;
}
static uint32_t get_video_pts (demux_avi_t *this, long pos)
{
return pos * (double) this->avi->dwScale / this->avi->dwRate * 90000.0;
}
*/
/* TODO : * a better method to realign
* verify that we are reading in p_movi
* XXX be sure to send audio before video to avoid click
*
*/
riffchunk_t *p_chunk;
int i;
pes_packet_t *p_pes;
demux_data_avi_file_t *p_avi_demux;
AVIStreamInfo_t *p_info_video;
AVIStreamInfo_t *p_info_audio;
AVIStreamInfo_t *p_info;
/* XXX arrive pas a avoir acces a cette fct
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
(mtime_t)0 ); */
p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
/* search video and audio stream selected */
p_info_video = NULL;
p_info_audio = NULL;
for( i = 0; i < p_avi_demux->i_streams; i++ )
{
if( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo != NULL )
{
switch( p_avi_demux->pp_info[i]->p_es->i_cat )
{
case( VIDEO_ES ):
p_info_video = p_avi_demux->pp_info[i];
break;
case( AUDIO_ES ):
p_info_audio = p_avi_demux->pp_info[i];
break;
}
}
else
{
p_avi_demux->pp_info[i]->b_unselected = 1;
}
}
if( p_info_video == NULL )
{
intf_ErrMsg( "input error: no video ouput selected" );
return( -1 );
}
if( input_ClockManageControl( p_input, p_input->stream.p_selected_program,
(mtime_t)0) == PAUSE_S )
{
__AVI_ControleUnPause();
p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_REINIT;
}
/* after updated p_avi_demux->pp_info[i]->b_unselected !! */
if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
{
/* TODO check if we have seek */
__AVI_ReAlign( p_input, p_info_video ); /*on se realigne pr la video */
p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
p_avi_demux->i_date = mdate() + DEFAULT_PTS_DELAY
- __AVI_GetPTSVideo( p_info_video );
/* TODO: a optimiser */
p_info_audio->i_idxpos = 0;
p_info_audio->b_unselected = 1; /* to correct audio */
p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
}
/* update i_date if previously unselected ES (ex: 2 channels audio ) */
if( (p_info_audio != NULL)&&(p_info_audio->b_unselected ))
{
intf_WarnMsg( 1, "input demux: reinit synchro for unselected es" );
/* we have to go to the good pts */
/* we will reach p_info_ok pts */
while( __AVI_GetPTS( p_info_audio) < __AVI_GetPTS( p_info_video) )
{
__AVI_NextIndexEntry( p_input, p_info_audio );
}
p_info_audio->b_unselected = 0 ;
}
/* what stream we should read in first */
if( p_info_audio == NULL )
{
p_info = p_info_video;
}
else
{
if( __AVI_GetPTSAudio( p_info_audio ) <=
__AVI_GetPTSVideo( p_info_video ) )
{
p_info = p_info_audio;
}
else
{
p_info = p_info_video;
}
}
/* go the good chunk to read */
__AVI_SeekToChunk( p_input, p_info );
/* now we just need to read a chunk */
if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
{
intf_ErrMsg( "input demux: cannot read chunk" );
return( -1 );
}
if( (p_chunk->i_id&0xFFFF0000) !=
(p_info->p_index[p_info->i_idxpos].i_id&0xFFFF0000) )
{
intf_WarnMsg( 2, "input demux: bad index entry" );
__AVI_NextIndexEntry( p_input, p_info );
return( 1 );
}
/*
intf_WarnMsg( 6, "input demux: read %4.4s chunk",
(char*)&p_chunk->i_id);
*/
if( RIFF_LoadChunkDataInPES(p_input, p_chunk, &p_pes) != 0 )
{
intf_ErrMsg( "input error: cannot read data" );
return( -1 );
}
p_pes->i_rate = p_input->stream.control.i_rate;
p_pes->i_pts = p_avi_demux->i_date + __AVI_GetPTS( p_info );
p_pes->i_dts = 0;
/* on update les donnes */
__AVI_NextIndexEntry( p_input, p_info );
/* send to decoder */
vlc_mutex_lock( &p_info->p_es->p_decoder_fifo->data_lock );
if( p_info->p_es->p_decoder_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
{
/* Wait for the decoder. */
vlc_cond_wait( &p_info->p_es->p_decoder_fifo->data_wait,
&p_info->p_es->p_decoder_fifo->data_lock );
}
vlc_mutex_unlock( &p_info->p_es->p_decoder_fifo->data_lock );
input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
return( 1 );
}
/*****************************************************************************
* avi.h : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: avi.h,v 1.1 2002/04/23 23:44:36 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.
*****************************************************************************/
#define MAX_PACKETS_IN_FIFO 10
/* flags for use in <dwFlags> in AVIFileHdr */
#define AVIF_HASINDEX 0x00000010 /* Index at end of file? */
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames? */
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
/* Flags for index */
#define AVIIF_LIST 0x00000001L /* chunk is a 'LIST' */
#define AVIIF_KEYFRAME 0x00000010L /* this frame is a key frame.*/
#define AVIIF_NOTIME 0x00000100L /* this frame doesn't take any time */
#define AVIIF_COMPUSE 0x0FFF0000L /* these bits are for compressor use */
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;
} bitmapinfoheader_t;
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 */
} waveformatex_t;
typedef struct MainAVIHeader_s
{
u32 i_microsecperframe;
u32 i_maxbytespersec;
u32 i_reserved1; /* dwPaddingGranularity; pad to multiples of this
size; normally 2K */
u32 i_flags;
u32 i_totalframes;
u32 i_initialframes;
u32 i_streams;
u32 i_suggestedbuffersize;
u32 i_width;
u32 i_height;
u32 i_scale;
u32 i_rate;
u32 i_start;
u32 i_length;
} MainAVIHeader_t;
typedef struct AVIStreamHeader_s
{
u32 i_type;
u32 i_handler;
u32 i_flags;
u32 i_reserved1; /* wPriority wLanguage */
u32 i_initialframes;
u32 i_scale;
u32 i_rate;
u32 i_start;
u32 i_length; /* In units above... */
u32 i_suggestedbuffersize;
u32 i_quality;
u32 i_samplesize;
} AVIStreamHeader_t;
typedef struct AVIIndexEntry_s
{
u32 i_id;
u32 i_flags;
u32 i_offset;
u32 i_length;
u32 i_lengthtotal;
} AVIIndexEntry_t;
typedef struct AVIStreamInfo_s
{
riffchunk_t *p_strl;
riffchunk_t *p_strh;
riffchunk_t *p_strf;
riffchunk_t *p_strd; /* not used */
AVIStreamHeader_t header;
u8 i_cat; /* AUDIO_ES, VIDEO_ES */
bitmapinfoheader_t video_format;
waveformatex_t audio_format;
es_descriptor_t *p_es;
int b_unselected; /* previously unselected */
AVIIndexEntry_t *p_index;
int i_idxnb;
int i_idxmax;
int i_idxpos;
off_t i_idxoffset; /* how many to add to index.i_pos */
} AVIStreamInfo_t;
typedef struct demux_data_avi_file_s
{
mtime_t i_date; /* date correspondant i_chunkread = 0 */
riffchunk_t *p_riff;
riffchunk_t *p_hdrl;
riffchunk_t *p_movi;
riffchunk_t *p_idx1;
/* Info extraites de avih */
MainAVIHeader_t avih;
/* les differents stream */
int i_streams;
AVIStreamInfo_t **pp_info;
/* absolument pas definitif */
} demux_data_avi_file_t;
/*****************************************************************************
* fourcc.h : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: fourcc.h,v 1.1 2002/04/23 23:44:36 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.
*****************************************************************************/
#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
( ((u32)ch0) | ( ((u32)ch1) << 8 ) | \
( ((u32)ch2) << 16 ) | ( ((u32)ch3) << 24 ) )
#define mmioTWOCC( ch0, ch1 ) \
( (u32)(ch0) | ( (u32)(ch1) << 8 ) )
#define WAVE_FORMAT_UNKNOWN 0x0000
#define WAVE_FORMAT_PCM 0x0001
#define WAVE_FORMAT_MPEG 0x0050
#define WAVE_FORMAT_MPEGLAYER3 0x0055
#define WAVE_FORMAT_AC3 0x2000
#define FOURCC_RIFF mmioFOURCC( 'R', 'I', 'F', 'F' )
#define FOURCC_LIST mmioFOURCC( 'L', 'I', 'S', 'T' )
#define FOURCC_JUNK mmioFOURCC( 'J', 'U', 'N', 'K' )
#define FOURCC_AVI mmioFOURCC( 'A', 'V', 'I', ' ' )
#define FOURCC_WAVE mmioFOURCC( 'W', 'A', 'V', 'E' )
#define FOURCC_avih mmioFOURCC( 'a', 'v', 'i', 'h' )
#define FOURCC_hdrl mmioFOURCC( 'h', 'd', 'r', 'l' )
#define FOURCC_movi mmioFOURCC( 'm', 'o', 'v', 'i' )
#define FOURCC_idx1 mmioFOURCC( 'i', 'd', 'x', '1' )
#define FOURCC_strl mmioFOURCC( 's', 't', 'r', 'l' )
#define FOURCC_strh mmioFOURCC( 's', 't', 'r', 'h' )
#define FOURCC_strf mmioFOURCC( 's', 't', 'r', 'f' )
#define FOURCC_strd mmioFOURCC( 's', 't', 'r', 'd' )
#define FOURCC_rec mmioFOURCC( 'r', 'e', 'c', ' ' )
#define FOURCC_auds mmioFOURCC( 'a', 'u', 'd', 's' )
#define FOURCC_vids mmioFOURCC( 'v', 'i', 'd', 's' )
#define TWOCC_wb mmioTWOCC( 'w', 'b' )
#define TWOCC_db mmioTWOCC( 'd', 'b' )
#define TWOCC_dc mmioTWOCC( 'd', 'c' )
#define TWOCC_pc mmioTWOCC( 'p', 'c' )
/* definition of mpeg4 (opendivx) codec */
#define FOURCC_DIVX mmioFOURCC( 'D', 'I', 'V', 'X' )
#define FOURCC_divx mmioFOURCC( 'd', 'i', 'v', 'x' )
#define FOURCC_DX50 mmioFOURCC( 'D', 'X', '5', '0' )
#define FOURCC_MP4S mmioFOURCC( 'M', 'P', '4', 'S' )
#define FOURCC_MPG4 mmioFOURCC( 'M', 'P', 'G', '4' )
#define FOURCC_mpg4 mmioFOURCC( 'm', 'p', 'g', '4' )
#define FOURCC_mp4v mmioFOURCC( 'm', 'p', '4', 'v' )
/* definition of msmepg (divx v3) codec */
#define FOURCC_DIV3 mmioFOURCC( 'D', 'I', 'V', '3' )
#define FOURCC_div3 mmioFOURCC( 'd', 'i', 'v', '3' )
#define FOURCC_DIV4 mmioFOURCC( 'D', 'I', 'V', '4' )
#define FOURCC_div4 mmioFOURCC( 'd', 'i', 'v', '4' )
#define FOURCC_DIV5 mmioFOURCC( 'D', 'I', 'V', '5' )
#define FOURCC_div5 mmioFOURCC( 'd', 'i', 'v', '5' )
#define FOURCC_DIV6 mmioFOURCC( 'D', 'I', 'V', '6' )
#define FOURCC_div6 mmioFOURCC( 'd', 'i', 'v', '6' )
#define FOURCC_3IV1 mmioFOURCC( '3', 'I', 'V', '1' )
#define FOURCC_AP41 mmioFOURCC( 'A', 'P', '4', '1' )
#define FOURCC_MP43 mmioFOURCC( 'M', 'P', '4', '3' )
#define FOURCC_mp43 mmioFOURCC( 'm', 'p', '4', '3' )
/*****************************************************************************
* avi_file.c : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: libLE.c,v 1.1 2002/04/23 23:44:36 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.
*****************************************************************************/
/*
* Data reading functions
*/
static u16 __GetWordLittleEndianFromBuff( byte_t *p_buff )
{
u16 i;
i = (*p_buff) + ( *(p_buff + 1) <<8 );
return ( i );
}
static u32 __GetDoubleWordLittleEndianFromBuff( byte_t *p_buff )
{
u32 i;
i = (*p_buff) + ( *(p_buff + 1) <<8 ) + ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 );
return ( i );
}
static void __SetWordLittleEndianToBuff( byte_t *p_buff, u16 i)
{
*(p_buff) = (i & 0xFF);
*(p_buff + 1) = ( ( i >>8 ) & 0xFF);
return;
}
static void __SetDoubleWordLittleEndianToBuff( byte_t *p_buff, u32 i)
{
*(p_buff) = ( i & 0xFF );
*(p_buff + 1) = (( i >>8 ) & 0xFF);
*(p_buff + 2) = (( i >>16 ) & 0xFF);
*(p_buff + 3) = (( i >>24 ) & 0xFF);
return;
}
/*****************************************************************************
* libioRIFF.c : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: libioRIFF.c,v 1.1 2002/04/23 23:44:36 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 riffchunk_s
{
u32 i_id;
u32 i_size;
u32 i_type;
u32 i_pos; /* peut etre a changer */
data_packet_t *p_data; /* pas forcement utilise */
struct riffchunk_s *p_next;
struct riffchunk_s *p_subchunk;
} riffchunk_t;
/* ttes ces fonctions permettent un acces lineaire sans avoir besoin de revenrir en arriere */
static riffchunk_t * RIFF_ReadChunk(input_thread_t * p_input);
static int RIFF_NextChunk(input_thread_t * p_input,riffchunk_t *p_rifffather);
static int RIFF_DescendChunk(input_thread_t * p_input);
static int RIFF_AscendChunk(input_thread_t * p_input,riffchunk_t *p_rifffather);
static int RIFF_FindChunk(input_thread_t * p_input,u32 i_id,riffchunk_t *p_rifffather);
static int RIFF_GoToChunkData(input_thread_t * p_input);
static int RIFF_LoadChunkData(input_thread_t * p_input,riffchunk_t *p_riff);
static int RIFF_TestFileHeader(input_thread_t * p_input, riffchunk_t **pp_riff, u32 i_type);
static int RIFF_FindAndLoadChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_fmt, u32 i_type );
static int RIFF_FindAndGotoDataChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_data, u32 i_type );
static int RIFF_FindListChunk( input_thread_t *p_input, riffchunk_t **pp_riff, riffchunk_t *p_rifffather, u32 i_type );
static void RIFF_DeleteChunk( input_thread_t * p_input, riffchunk_t *p_chunk );
/*
ces fonctions on besoin de pouvoir faire des seek
static int RIFF_GoToChunk(input_thread_t * p_input,riffchunk_t *p_riff);
*/
static u32 RIFF_4cToI(char c1,char c2,char c3,char c4);
static char * RIFF_IToStr(u32 i);
/*************************************************************************/
/********************************************
* Fonction locale maintenant *
********************************************/
static int __RIFF_TellPos( input_thread_t *p_input, u32 *pos )
{ /* pas sur que ca marche */
u32 i;
vlc_mutex_lock( &p_input->stream.stream_lock );
i = p_input->stream.p_selected_area->i_tell - ( p_input->p_last_data - p_input->p_current_data );
vlc_mutex_unlock( &p_input->stream.stream_lock );
*pos = i;
return 0;
}
static int __RIFF_SkipBytes(input_thread_t * p_input,int nb)
{
data_packet_t *p_pack;
int i;
int i_rest;
if( p_input->stream.b_seekable )
{
u32 i_pos;
__RIFF_TellPos( p_input, &i_pos);
p_input->pf_seek( p_input, (off_t)(i_pos + nb) );
input_AccessReinit( p_input );
}
else
{
intf_WarnMsg( 1, "input demux: cannot seek, it will take times" );
if( nb < 0 ) { return( -1 ); }
i_rest = nb;
while (i_rest != 0 )
{
if ( i_rest >= 4096 )
{
i = input_SplitBuffer( p_input, &p_pack, 4096);
}
else
{
i = input_SplitBuffer( p_input, &p_pack, i_rest);
}
if ( i < 0 ) { return ( -1 ); }
i_rest-=i;
input_DeletePacket( p_input->p_method_data, p_pack);
}
}
return ( 0 );
}
static void RIFF_DeleteChunk( input_thread_t *p_input, riffchunk_t *p_chunk )
{
if( p_chunk != NULL)
{
if( p_chunk->p_data != NULL )
{
input_DeletePacket( p_input->p_method_data, p_chunk->p_data );
}
free( p_chunk );
}
}
/* ******************************************
* lit une structure riffchunk sans avancer *
********************************************/
static riffchunk_t * RIFF_ReadChunk(input_thread_t * p_input)
{
riffchunk_t * p_riff;
int count;
byte_t * p_peek;
if((p_riff = malloc( sizeof(riffchunk_t))) == NULL)
{
intf_ErrMsg("input error: not enough memory (ioriff)" );
return NULL;
}
p_riff->p_data = NULL; /* Par defaut */
p_riff->p_next = NULL;
p_riff->p_subchunk = NULL;
/* peek to have the begining, 8+4 where 4 are to get type */
count=input_Peek( p_input, &p_peek, 12 );
if( count < 8 )
{
intf_ErrMsg( "input error: cannot peek() (ioriff)" );
free(p_riff);
return NULL;
}
p_riff->i_id = __GetDoubleWordLittleEndianFromBuff( p_peek );
p_riff->i_size =__GetDoubleWordLittleEndianFromBuff( p_peek + 4 );
if( count == 12 )
{
p_riff->i_type = __GetDoubleWordLittleEndianFromBuff( p_peek + 8 );
}
else
{
p_riff->i_type = 0;
}
__RIFF_TellPos(p_input, &(p_riff->i_pos) );
return( p_riff );
}
/**************************************************
* Va au chunk juste d'apres si il en a encore *
* -1 si erreur , 1 si y'en a plus *
**************************************************/
static int RIFF_NextChunk( input_thread_t * p_input,riffchunk_t *p_rifffather)
{
int i_len;
int i_lenfather;
riffchunk_t *p_riff;
if( ( p_riff = RIFF_ReadChunk( p_input ) ) == NULL )
{
intf_ErrMsg( "ioriff: cannot read chunk." );
return( -1 );
}
i_len = p_riff->i_size;
if( i_len%2 != 0 ) {i_len++;} /* align sur un mot */
if ( p_rifffather != NULL )
{
i_lenfather=p_rifffather->i_size;
if ( i_lenfather%2 !=0 ) {i_lenfather++;}
if ( p_rifffather->i_pos + i_lenfather <= p_riff->i_pos + i_len )
{
intf_ErrMsg( "ioriff: next chunk out of bound" );
free( p_riff );
return( 1 ); /* pas dans nos frontiere */
}
}
if ( __RIFF_SkipBytes( p_input,i_len + 8 ) != 0 )
{
free( p_riff );
intf_ErrMsg( "input error: cannot go to the next chunk (ioriff)." );
return( -1 );
}
free( p_riff );
return( 0 );
}
/****************************************************************
* Permet de rentrer dans un ck RIFF ou LIST *
****************************************************************/
static int RIFF_DescendChunk(input_thread_t * p_input)
{
if ( __RIFF_SkipBytes(p_input,12) != 0)
{
intf_ErrMsg( "input error: cannot go into chunk." );
return ( -1 );
}
return( 0 );
}
/***************************************************************
* Permet de sortir d'un sous chunk et d'aller sur le suivant *
* chunk *
***************************************************************/
static int RIFF_AscendChunk(input_thread_t * p_input ,riffchunk_t *p_rifffather)
{
int i_skip;
u32 i_posactu;
i_skip = p_rifffather->i_pos + p_rifffather->i_size + 8;
if ( i_skip%2 != 0) {i_skip++;}
__RIFF_TellPos(p_input, &i_posactu);
i_skip-=i_posactu;
if (( __RIFF_SkipBytes(p_input,i_skip)) != 0)
{
intf_ErrMsg( "ioriff: cannot exit from subchunk.");
return( -1 );
}
return( 0 );
}
/***************************************************************
* Permet de se deplacer jusqu'au premier chunk avec le bon id *
* *************************************************************/
static int RIFF_FindChunk(input_thread_t * p_input ,u32 i_id,riffchunk_t *p_rifffather)
{
riffchunk_t *p_riff=NULL;
do
{
if (p_riff!=NULL)
{
free(p_riff);
if ( RIFF_NextChunk(p_input ,p_rifffather) != 0 )
{
return( -1 );
}
}
p_riff=RIFF_ReadChunk(p_input);
} while ( ( p_riff != NULL )&&( p_riff->i_id != i_id ) );
if ( ( p_riff == NULL )||( p_riff->i_id != i_id ) )
{
return( -1 );
}
free( p_riff );
return( 0 );
}
/*****************************************************************
* Permet de pointer sur la zone de donn du chunk courant *
*****************************************************************/
static int RIFF_GoToChunkData(input_thread_t * p_input)
{
if ( __RIFF_SkipBytes(p_input,8) != 0 )
{
return( -1 );
}
return( 0 );
}
static int RIFF_LoadChunkData(input_thread_t * p_input,riffchunk_t *p_riff )
{
RIFF_GoToChunkData(p_input);
if ( input_SplitBuffer( p_input, &p_riff->p_data, p_riff->i_size ) != p_riff->i_size )
{
intf_ErrMsg( "ioriff: cannot read enough data " );
return ( -1 );
}
if ( p_riff->i_size%2 != 0)
{
__RIFF_SkipBytes(p_input,1);
} /* aligne sur un mot */
return( 0 );
}
static int RIFF_LoadChunkDataInPES(input_thread_t * p_input,riffchunk_t *p_riff,pes_packet_t **pp_pes)
{
u32 i_read;
data_packet_t *p_data;
RIFF_GoToChunkData(p_input);
*pp_pes = input_NewPES( p_input->p_method_data );
if( *pp_pes == NULL )
{
return( -1 );
}
if( p_riff->i_size == 0 )
{
p_data = input_NewPacket( p_input->p_method_data, 0 );
(*pp_pes)->p_first = p_data;
(*pp_pes)->p_last = p_data;
(*pp_pes)->i_nb_data = 1;
(*pp_pes)->i_pes_size = 0;
return( 0 );
}
do
{
i_read = input_SplitBuffer(p_input, &p_data, p_riff->i_size -
(*pp_pes)->i_pes_size );
if( i_read < 0 )
{
/* FIXME free sur tout les packets */
return( -1 );
}
if( (*pp_pes)->p_first == NULL )
{
(*pp_pes)->p_first = p_data;
(*pp_pes)->p_last = p_data;
(*pp_pes)->i_nb_data = 1;
(*pp_pes)->i_pes_size = ( p_data->p_payload_end -
p_data->p_payload_start );
}
else
{
(*pp_pes)->p_last->p_next = p_data;
(*pp_pes)->p_last = p_data;
(*pp_pes)->i_nb_data++;
(*pp_pes)->i_pes_size += ( p_data->p_payload_end -
p_data->p_payload_start );
}
} while( ((*pp_pes)->i_pes_size < p_riff->i_size)&&(i_read != 0) );
/* i_read = 0 si fin du stream sinon block */
if ( p_riff->i_size%2 != 0)
{
__RIFF_SkipBytes(p_input,1);
} /* aligne sur un mot */
return( 0 );
}
static int RIFF_GoToChunk(input_thread_t * p_input, riffchunk_t *p_riff)
{
/* TODO rajouter les test */
if( p_input->stream.b_seekable )
{
p_input->pf_seek( p_input, (off_t)p_riff->i_pos );
input_AccessReinit( p_input );
return 0;
}
return( -1 );
}
static u32 RIFF_4cToI(char c1,char c2,char c3,char c4)
{
u32 i;
i = ( ((u32)c1) << 24 ) + ( ((u32)c2) << 16 ) + ( ((u32)c3) << 8 ) + (u32)c4;
return i;
}
static char * RIFF_IToStr(u32 l)
{
char *str;
int i;
str=calloc(5,sizeof(char));
for( i = 0; i < 4; i++)
{
str[i] = ( l >> ( (3-i) * 8) )&0xFF;
}
str[5] = 0;
return( str );
}
static int RIFF_TestFileHeader( input_thread_t * p_input, riffchunk_t ** pp_riff, u32 i_type )
{
*pp_riff = RIFF_ReadChunk( p_input );
if( *pp_riff == NULL )
{
intf_ErrMsg( "input error: cannot retrieve header" );
return( -1 );
}
if( (*pp_riff)->i_id != FOURCC_RIFF )
{
free( *pp_riff );
return( -1 );
}
if( (*pp_riff)->i_type != i_type )
{
free( *pp_riff );
return( -1 );
}
return( 0 );
}
static int RIFF_FindAndLoadChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_fmt, u32 i_type )
{
*pp_fmt = NULL;
if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
{
return( -1 );
}
if ( ( (*pp_fmt = RIFF_ReadChunk( p_input )) == NULL) || ( RIFF_LoadChunkData( p_input, *pp_fmt ) != 0 ) )
{
if( *pp_fmt != NULL ) { RIFF_DeleteChunk( p_input, *pp_fmt ); }
return( -1 );
}
return( 0 );
}
static int RIFF_FindAndGotoDataChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_data, u32 i_type )
{
*pp_data = NULL;
if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
{
return( -1 );
}
if ( ( *pp_data = RIFF_ReadChunk( p_input ) ) == NULL )
{
return( -1 );
}
if ( RIFF_GoToChunkData( p_input ) != 0 )
{
RIFF_DeleteChunk( p_input, *pp_data );
return( -1 );
}
return( 0 );
}
static int RIFF_FindListChunk( input_thread_t *p_input, riffchunk_t **pp_riff, riffchunk_t *p_rifffather, u32 i_type )
{
int i_ok;
*pp_riff = NULL;
i_ok = 0;
while( i_ok == 0 )
{
if( *pp_riff != NULL )
{
free( *pp_riff );
}
if( RIFF_FindChunk( p_input, FOURCC_LIST, p_rifffather) != 0 )
{
return( -1 );
}
*pp_riff = RIFF_ReadChunk( p_input );
if( *pp_riff == NULL )
{
return( -1 );
}
if( (*pp_riff)->i_type != i_type )
{
if( RIFF_NextChunk( p_input, p_rifffather ) != 0 )
{
return( -1 );
}
}
else
{
i_ok = 1;
}
}
return( 0 );
}
ffmpeg_SOURCES =
ffmpeg_SOURCES = ffmpeg.c
/*****************************************************************************
* ffmpeg.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ffmpeg.c,v 1.1 2002/04/23 23:44:36 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 <videolan/vlc.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 "video.h"
#include "video_output.h"
#include "stream_control.h"
#include "input_ext-dec.h"
#include "input_ext-intf.h"
#include "input_ext-plugins.h"
#include "vdec_ext-plugins.h"
#include "avcodec.h" /* ffmpeg */
#include "ffmpeg.h"
/*
* Local prototypes
*/
static int decoder_Probe ( u8 * );
static int decoder_Run ( decoder_config_t * );
static int InitThread ( videodec_thread_t * );
static void EndThread ( videodec_thread_t * );
static void DecodeThread ( videodec_thread_t * );
/* FIXME make this variable global */
static int b_ffmpeginit = 0;
/*****************************************************************************
* Capabilities
*****************************************************************************/
void _M( vdec_getfunctions )( function_list_t * p_function_list )
{
p_function_list->functions.dec.pf_probe = decoder_Probe;
p_function_list->functions.dec.pf_run = decoder_Run;
}
/*****************************************************************************
* Build configuration tree.
*****************************************************************************/
MODULE_CONFIG_START
MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "ffmpeg video decoder module (MSMPEG4,MPEG4)" )
ADD_CAPABILITY( DECODER, 50 )
ADD_SHORTCUT( "ffmpeg_vdec" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
_M( vdec_getfunctions )( &p_module->p_functions->dec );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
static u16 __GetWordLittleEndianFromBuff( byte_t *p_buff )
{
u16 i;
i = (*p_buff) + ( *(p_buff + 1) <<8 );
return ( i );
}
static u32 __GetDoubleWordLittleEndianFromBuff( byte_t *p_buff )
{
u32 i;
i = (*p_buff) + ( *(p_buff + 1) <<8 ) + ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 );
return ( i );
}
/*****************************************************************************
* decoder_Probe: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to chose.
*****************************************************************************/
static int decoder_Probe( u8 *pi_type )
{
switch( *pi_type )
{
/* case( MPEG1_VIDEO_ES ): marche pas pr le moment
case( MPEG2_VIDEO_ES ): */
case( MSMPEG4_VIDEO_ES ):
case( MPEG4_VIDEO_ES ):
return( 0 );
default:
return( -1 );
}
}
/*****************************************************************************
* Functions locales
*****************************************************************************/
static int __ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
{
h->i_size = __GetDoubleWordLittleEndianFromBuff( p_data );
h->i_width = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
h->i_height = __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
h->i_planes = __GetWordLittleEndianFromBuff( p_data + 12 );
h->i_bitcount = __GetWordLittleEndianFromBuff( p_data + 14 );
h->i_compression = __GetDoubleWordLittleEndianFromBuff( p_data + 16 );
h->i_sizeimage = __GetDoubleWordLittleEndianFromBuff( p_data + 20 );
h->i_xpelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 24 );
h->i_ypelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 28 );
h->i_clrused = __GetDoubleWordLittleEndianFromBuff( p_data + 32 );
h->i_clrimportant = __GetDoubleWordLittleEndianFromBuff( p_data + 36 );
return( 0 );
}
/* get the first pes from fifo */
static pes_packet_t *__PES_GET( decoder_fifo_t *p_fifo )
{
pes_packet_t *p_pes;
/* get a p_pes ie data for a frame ! */
vlc_mutex_lock( &p_fifo->data_lock );
/* if fifo is emty wait */
while( p_fifo->p_first == NULL )
{
if( p_fifo->b_die )
{
vlc_mutex_unlock( &p_fifo->data_lock );
return( NULL );
}
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
p_pes = p_fifo->p_first;
vlc_mutex_unlock( &p_fifo->data_lock );
return( p_pes );
}
/* free the first pes and go to next */
static void __PES_NEXT( decoder_fifo_t *p_fifo )
{
pes_packet_t *p_next;
vlc_mutex_lock( &p_fifo->data_lock );
p_next = p_fifo->p_first->p_next;
p_fifo->p_first->p_next = NULL;
input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
p_fifo->p_first = p_next;
p_fifo->i_depth--;
if( p_fifo->p_first == NULL )
{
/* No PES in the fifo */
/* pp_last no longer valid */
p_fifo->pp_last = &p_fifo->p_first;
while( p_fifo->p_first == NULL )
{
vlc_cond_signal( &p_fifo->data_wait );
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
}
vlc_mutex_unlock( &p_fifo->data_lock );
}
static void __PACKET_REINIT( videodec_thread_t *p_vdec )
{
pes_packet_t *p_pes;
p_pes = __PES_GET( p_vdec->p_fifo );
if( p_vdec->p_fifo->b_die )
{
return;
}
p_vdec->p_data = p_pes->p_first;
p_vdec->p_buff = p_vdec->p_data->p_payload_start;
p_vdec->i_data_size = p_vdec->p_data->p_payload_end -
p_vdec->p_data->p_payload_start;
}
static void __PACKET_NEXT( videodec_thread_t *p_vdec )
{
do
{
p_vdec->p_data = p_vdec->p_data->p_next;
if( p_vdec->p_data == NULL )
{
__PES_NEXT( p_vdec->p_fifo );
if( p_vdec->p_fifo->b_die )
{
return;
}
__PACKET_REINIT( p_vdec );
}
else
{
p_vdec->p_buff = p_vdec->p_data->p_payload_start;
p_vdec->i_data_size = p_vdec->p_data->p_payload_end -
p_vdec->p_data->p_payload_start;
}
if( p_vdec->i_data_size == 0 )
{
p_vdec->p_data = NULL;
}
} while( p_vdec->i_data_size <= 0 );
}
static void __PACKET_FILL( videodec_thread_t *p_vdec )
{
if( p_vdec->i_data_size <= 0 )
{
__PACKET_NEXT( p_vdec );
}
}
/* call only two times so inline for faster */
static __inline__ void __ConvertAVPictureToPicture( AVPicture *p_avpicture,
picture_t *p_picture )
{
int i_plane, i_line;
u8 *p_dest,*p_src;
for( i_plane = 0; i_plane < p_picture->i_planes; i_plane++ )
{
p_dest = p_picture->p[i_plane].p_pixels;
p_src = p_avpicture->data[i_plane];
if( (p_dest == NULL)||( p_src == NULL)||(i_plane >= 3) ) { return; }
for( i_line = 0; i_line < p_picture->p[i_plane].i_lines; i_line++ )
{
FAST_MEMCPY( p_dest,
p_src,
__MIN( p_picture->p[i_plane].i_pitch,
p_avpicture->linesize[i_plane] ) );
p_dest += p_picture->p[i_plane].i_pitch;
p_src += p_avpicture->linesize[i_plane];
}
}
}
static __inline__ u32 __FfmpegChromaToFourCC( int i_ffmpegchroma )
{
switch( i_ffmpegchroma )
{
case( PIX_FMT_YUV420P ):
return FOURCC_I420;
case( PIX_FMT_YUV422 ):
return FOURCC_I420;
case( PIX_FMT_RGB24 ):
return FOURCC_RV24;
case( PIX_FMT_BGR24 ):
return 0; /* FIXME pas trouv ds video.h */
case( PIX_FMT_YUV422P ):
return FOURCC_Y422;
case( PIX_FMT_YUV444P ):
return 0; /* FIXME pas trouv FOURCC_IYU2; */
default:
return 0;
}
}
/*****************************************************************************
* decoder_Run: this function is called just after the thread is created
*****************************************************************************/
static int decoder_Run ( decoder_config_t * p_config )
{
videodec_thread_t *p_vdec;
int b_error;
if ( (p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t)))
== NULL )
{
intf_ErrMsg( "vdec error: not enough memory "
"for vdec_CreateThread() to create the new thread");
DecoderError( p_config->p_decoder_fifo );
return( -1 );
}
memset( p_vdec, 0, sizeof( videodec_thread_t ) );
p_vdec->p_fifo = p_config->p_decoder_fifo;
p_vdec->p_config = p_config;
p_vdec->p_vout = NULL;
if( InitThread( p_vdec ) != 0 )
{
DecoderError( p_config->p_decoder_fifo );
return( -1 );
}
while( (!p_vdec->p_fifo->b_die) && (!p_vdec->p_fifo->b_error) )
{
/* decode a picture */
DecodeThread( p_vdec );
}
if( ( b_error = p_vdec->p_fifo->b_error ) )
{
DecoderError( p_vdec->p_fifo );
}
EndThread( p_vdec );
if( b_error )
{
return( -1 );
}
return( 0 );
}
/*****************************************************************************
* 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.
*****************************************************************************/
static int InitThread( videodec_thread_t *p_vdec )
{
if( p_vdec->p_config->p_demux_data != NULL )
{
__ParseBitMapInfoHeader( &p_vdec->format,
(byte_t*)p_vdec->p_config->p_demux_data );
}
else
{
memset( &p_vdec->format, 0, sizeof( bitmapinfoheader_t ) );
}
/* some codec need to have height and width initialized (msmepg4,mpeg4) */
/* we cannot create vout because we don't know what chroma */
/*init ffmpeg */
/* XXX maybe it's not multi thread capable */
/* TODO: add a global variable to know if init was already done */
if( b_ffmpeginit == 0 )
{
avcodec_init();
avcodec_register_all();
b_ffmpeginit = 1;
intf_WarnMsg( 1, "vdec init: library ffmpeg initialised" );
}
else
{
intf_WarnMsg( 1, "vdec init: library ffmpeg already initialised" );
}
switch( p_vdec->p_config->i_type)
{
case( MPEG1_VIDEO_ES ): /* marche pas pr le moment */
case( MPEG2_VIDEO_ES ):
p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MPEG1VIDEO );
p_vdec->psz_namecodec = "MPEG-1";
break;
case( MSMPEG4_VIDEO_ES):
p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MSMPEG4 );
p_vdec->psz_namecodec = "MS MPEG-4";
break;
case( MPEG4_VIDEO_ES):
p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MPEG4 );
p_vdec->psz_namecodec = "MPEG-4";
break;
default:
p_vdec->p_codec = NULL;
p_vdec->psz_namecodec = "Unknown";
}
if( p_vdec->p_codec == NULL )
{
intf_ErrMsg( "vdec error: codec not found (%s)",
p_vdec->psz_namecodec );
return( -1 );
}
p_vdec->p_context = &p_vdec->context;
memset( p_vdec->p_context, 0, sizeof( AVCodecContext ) );
p_vdec->p_context->width = p_vdec->format.i_width;
p_vdec->p_context->height = p_vdec->format.i_height;
p_vdec->p_context->pix_fmt = PIX_FMT_YUV420P;
if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0)
{
intf_ErrMsg( "vdec error: cannot open codec (%s)",
p_vdec->psz_namecodec );
return( -1 );
}
else
{
intf_WarnMsg( 1, "vdec info: ffmpeg codec (%s) started",
p_vdec->psz_namecodec );
}
__PACKET_REINIT( p_vdec );
return( 0 );
}
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static void EndThread( videodec_thread_t *p_vdec )
{
if( p_vdec == NULL )
{
intf_ErrMsg( "vdec error: cannot free structures" );
return;
}
if( p_vdec->p_context != NULL)
{
avcodec_close( p_vdec->p_context );
intf_WarnMsg(1, "vdec info: ffmpeg codec (%s) stopped",
p_vdec->psz_namecodec);
}
if( p_vdec->p_vout != NULL )
{
vout_DestroyThread( p_vdec->p_vout, NULL );
}
free( p_vdec );
}
static void DecodeThread( videodec_thread_t *p_vdec )
{
int i_len;
int b_gotpicture;
int b_convert;
int i_aspect;
pes_packet_t *p_pes;
AVPicture avpicture; /* ffmpeg picture */
u32 i_chroma;
picture_t *p_picture; /* videolan picture */
/* we have to get a frame stored in a pes
give it to ffmpeg decoder
and send the image to the output */
/* when we have the first image we create the video output */
/* int avcodec_decode_video(AVCodecContext *avctx, AVPicture *picture,
int *got_picture_ptr,
UINT8 *buf, int buf_size);
typedef struct AVPicture
{
UINT8 *data[3];
int linesize[3];
} AVPicture;
*/
p_pes = NULL;
do
{
__PACKET_FILL( p_vdec );
if( p_vdec->p_fifo->b_die )
{
return;
}
/* save p_pes for pts */
if( p_pes == NULL ) {p_pes = __PES_GET( p_vdec->p_fifo );}
i_len = avcodec_decode_video( p_vdec->p_context,
&avpicture,
&b_gotpicture,
p_vdec->p_buff,
p_vdec->i_data_size);
if( i_len < 0 )
{
intf_WarnMsg( 1, "vdec error: cannot decode one frame (%d bytes)",
p_vdec->i_data_size );
__PES_NEXT( p_vdec->p_fifo );
__PACKET_REINIT( p_vdec );
return;
}
p_vdec->i_data_size -= i_len;
p_vdec->p_buff += i_len;
} while( !b_gotpicture );
i_chroma =__FfmpegChromaToFourCC( p_vdec->p_context->pix_fmt );
if( i_chroma == 0 )
{
b_convert = 1;
i_chroma = FOURCC_I420;
}
else
{
b_convert = 0;
}
/* Send decoded frame to vout */
if( p_vdec->p_vout == NULL )
{
/* FIXME FIXME faire ca comme il faut avec :
* pp_vout_bank
* bon aspect, ds avi pas definie mais pour le reste a voir ...
*/
/* create vout */
/* FIXME */
/*
p_vdec->i_aspect = VOUT_ASPECT_FACTOR * 4 / 3; AR_3_4_PICTURE
*/
/* ffmpeg set it for our with some codec */
if( (p_vdec->format.i_width == 0)||(p_vdec->format.i_height == 0) )
{
p_vdec->format.i_width = p_vdec->p_context->width;
p_vdec->format.i_height = p_vdec->p_context->height;
}
/* calculate i_aspect */
i_aspect = VOUT_ASPECT_FACTOR * p_vdec->format.i_width /
p_vdec->format.i_height;
/* FIXME comment faire ca proprement */
/*
if( i_aspect == VOUT_ASPECT_FACTOR * 4 /3 )
{
i_aspect = 1;
}
else
{
if( i_aspect == VOUT_ASPECT_FACTOR * 16 /9 )
{
i_aspect = 2;
}
}
*/
p_vdec->i_aspect = i_aspect;
p_vdec->i_chroma = i_chroma;
intf_WarnMsg( 1, "vdec info: creating vout %dx%d chroma %4.4s %s %s",
p_vdec->format.i_width,
p_vdec->format.i_height,
(char*)&i_chroma,
b_convert ? "(with convertion)" : "",
/*i_aspect ==1 ? "aspect 4:3" : "aspect 16:9"*/
"free aspect" );
p_vdec->p_vout = vout_CreateThread(
NULL,
p_vdec->format.i_width,
p_vdec->format.i_height,
p_vdec->i_chroma,
p_vdec->i_aspect );
if( p_vdec->p_vout == NULL )
{
intf_ErrMsg( "vdec error: can't open vout, aborting" );
p_vdec->p_fifo->b_error = 1;
return;
}
}
while( (p_picture = vout_CreatePicture( p_vdec->p_vout,
0, /* ??? */
0, /* ??? */
0) ) /* ??? */
== NULL )
{
if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
{
return;
}
msleep( VOUT_OUTMEM_SLEEP );
}
if( b_convert == 1 )
{
/* we convert in a supported format */
int i_status;
u8 *p_buff;
AVPicture avpicture_tmp;
p_buff = malloc( avpicture_get_size( PIX_FMT_YUV420P,
p_vdec->p_context->width,
p_vdec->p_context->height) );
avpicture_fill( &avpicture_tmp,
p_buff,
PIX_FMT_YUV420P,
p_vdec->p_context->width,
p_vdec->p_context->height );
i_status = img_convert( &avpicture_tmp,
PIX_FMT_YUV420P,
&avpicture,
p_vdec->p_context->pix_fmt,
p_vdec->p_context->width,
p_vdec->p_context->height );
if( i_status < 0 )
{
intf_ErrMsg( "vdec error: cannot convert picture in known chroma" );
return;
}
__ConvertAVPictureToPicture( &avpicture_tmp, p_picture );
free( p_buff ); /* FIXME try to alloc only one time */
}
else
{
__ConvertAVPictureToPicture( &avpicture, p_picture );
}
vout_DatePicture( p_vdec->p_vout, p_picture, p_pes->i_pts );
vout_DisplayPicture( p_vdec->p_vout, p_picture );
return;
}
/*****************************************************************************
* ffmpeg_vdec.h: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ffmpeg.h,v 1.1 2002/04/23 23:44:36 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.
*****************************************************************************/
/* 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;
} bitmapinfoheader_t;
typedef struct videodec_thread_s
{
decoder_config_t *p_config;
decoder_fifo_t *p_fifo;
bitmapinfoheader_t format;
AVCodecContext context, *p_context;
AVCodec *p_codec;
vout_thread_t *p_vout;
int i_aspect;
u32 i_chroma;
char *psz_namecodec;
/* private */
data_packet_t *p_data;
byte_t *p_buff;
int i_data_size;
} videodec_thread_t;
......@@ -67,7 +67,7 @@ MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( _("libmad MPEG 1/2/3 audio decoder library") )
ADD_CAPABILITY( DECODER, 50 )
ADD_CAPABILITY( DECODER, 100 )
ADD_SHORTCUT( "mad" )
MODULE_INIT_STOP
......
......@@ -2,7 +2,7 @@
* mpeg_adec.c: MPEG audio decoder thread
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: mpeg_adec.c,v 1.22 2002/04/19 13:56:11 sam Exp $
* $Id: mpeg_adec.c,v 1.23 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Michel Lespinasse <walken@via.ecp.fr>
......@@ -67,7 +67,7 @@ MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( _("MPEG I/II layer 1/2 audio decoder") )
ADD_CAPABILITY( DECODER, 100 )
ADD_CAPABILITY( DECODER, 50 )
ADD_REQUIREMENT( FPU )
ADD_SHORTCUT( "builtin" )
MODULE_INIT_STOP
......
......@@ -2,7 +2,7 @@
* input_programs.c: es_descriptor_t, pgrm_descriptor_t management
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: input_programs.c,v 1.81 2002/04/23 14:16:20 sam Exp $
* $Id: input_programs.c,v 1.82 2002/04/23 23:44:36 fenrir Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -617,6 +617,8 @@ int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
case AC3_AUDIO_ES:
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
case MPEG4_VIDEO_ES:
case MSMPEG4_VIDEO_ES:
case LPCM_AUDIO_ES:
if( p_main->b_audio )
{
......
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