Browse Source
* ./plugins/avi a light avi demux * ./plugins/ffmpeg a video decoder for divx v3 and opendivxpull/2/head
18 changed files with 2574 additions and 18 deletions
@ -1 +1,2 @@ |
|||
avi_SOURCES = |
|||
avi_SOURCES = avi.c |
|||
|
|||
|
|||
File diff suppressed because it is too large
@ -0,0 +1,153 @@ |
|||
/*****************************************************************************
|
|||
* 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; |
|||
|
|||
@ -0,0 +1,86 @@ |
|||
/*****************************************************************************
|
|||
* 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' ) |
|||
|
|||
@ -0,0 +1,57 @@ |
|||
/*****************************************************************************
|
|||
* 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; |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,483 @@ |
|||
/*****************************************************************************
|
|||
* 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 ); |
|||
} |
|||
@ -1 +1,2 @@ |
|||
ffmpeg_SOURCES = |
|||
ffmpeg_SOURCES = ffmpeg.c |
|||
|
|||
|
|||
@ -0,0 +1,638 @@ |
|||
/*****************************************************************************
|
|||
* 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; |
|||
} |
|||
|
|||
@ -0,0 +1,57 @@ |
|||
/*****************************************************************************
|
|||
* 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; |
|||
Loading…
Reference in new issue