From 5ad2a46fa61f3a095147ed1185ceced8d5fa7839 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Feb 2008 16:46:07 +0000 Subject: [PATCH] Supports vorbis audio in avi container (refs #224) Note that the format supported is the one created by FFmpeg, and not one of those described in the ticket. --- include/vlc_codecs.h | 17 +++++- modules/demux/avi/avi.c | 112 +++++++++++++++++++++++++++++++++------- 2 files changed, 108 insertions(+), 21 deletions(-) diff --git a/include/vlc_codecs.h b/include/vlc_codecs.h index 1f8c7015ea..3063ddf889 100644 --- a/include/vlc_codecs.h +++ b/include/vlc_codecs.h @@ -242,12 +242,24 @@ typedef struct #define WAVE_FORMAT_DK3 0x0061 #define WAVE_FORMAT_DK4 0x0062 +/* At least FFmpeg use that ID: from libavformat/riff.c ('Vo' == 0x566f) + * { CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id? + */ +#define WAVE_FORMAT_VORBIS 0x566f + +/* It seems that these IDs are used by braindead & obsolete VorbisACM encoder + * (Windows only) + * A few info is available except VorbisACM source (remember, Windows only) + * (available on http://svn.xiph.org), but it seems that vo3+ at least is + * made of Vorbis data encapsulated in Ogg container... + */ #define WAVE_FORMAT_VORB_1 0x674f -#define WAVE_FORMAT_VORB_1PLUS 0x676f #define WAVE_FORMAT_VORB_2 0x6750 -#define WAVE_FORMAT_VORB_2PLUS 0x6770 #define WAVE_FORMAT_VORB_3 0x6751 +#define WAVE_FORMAT_VORB_1PLUS 0x676f +#define WAVE_FORMAT_VORB_2PLUS 0x6770 #define WAVE_FORMAT_VORB_3PLUS 0x6771 + #define WAVE_FORMAT_SPEEX 0xa109 /* Speex audio */ @@ -323,6 +335,7 @@ wave_format_tag_to_fourcc[] = { WAVE_FORMAT_DIVIO_AAC, VLC_FOURCC( 'm', 'p', '4', 'a' ), "MPEG-4 Audio (Divio)" }, { WAVE_FORMAT_AAC, VLC_FOURCC( 'm', 'p', '4', 'a' ), "MPEG-4 Audio" }, { WAVE_FORMAT_FFMPEG_AAC, VLC_FOURCC( 'm', 'p', '4', 'a' ), "MPEG-4 Audio" }, + { WAVE_FORMAT_VORBIS, VLC_FOURCC( 'v', 'o', 'r', 'b' ), "Vorbis Audio" }, { WAVE_FORMAT_VORB_1, VLC_FOURCC( 'v', 'o', 'r', '1' ), "Vorbis 1 Audio" }, { WAVE_FORMAT_VORB_1PLUS, VLC_FOURCC( 'v', 'o', '1', '+' ), "Vorbis 1+ Audio" }, { WAVE_FORMAT_VORB_2, VLC_FOURCC( 'v', 'o', 'r', '2' ), "Vorbis 2 Audio" }, diff --git a/modules/demux/avi/avi.c b/modules/demux/avi/avi.c index 927ddc2af1..33c5552872 100644 --- a/modules/demux/avi/avi.c +++ b/modules/demux/avi/avi.c @@ -130,6 +130,9 @@ typedef struct unsigned int i_idxposc; /* numero of chunk */ unsigned int i_idxposb; /* byte in the current chunk */ + /* extra information given to the decoder */ + void *p_extra; + /* For VBR audio only */ unsigned int i_blockno; unsigned int i_blocksize; @@ -351,6 +354,12 @@ static int Open( vlc_object_t * p_this ) for( i = 0 ; i < i_track; i++ ) { avi_track_t *tk = malloc( sizeof( avi_track_t ) ); + if( !tk ) + { + msg_Err( p_demux, "Out of memory" ); + goto error; + } + avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i ); avi_chunk_strh_t *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 ); avi_chunk_STRING_t *p_strn = AVI_ChunkFind( p_strl, AVIFOURCC_strn, 0 ); @@ -358,18 +367,7 @@ static int Open( vlc_object_t * p_this ) avi_chunk_strf_vids_t *p_vids = NULL; es_format_t fmt; - tk->b_activated = VLC_FALSE; - tk->p_index = 0; - tk->i_idxnb = 0; - tk->i_idxmax = 0; - tk->i_idxposc = 0; - tk->i_idxposb = 0; - - tk->i_blockno = 0; - tk->i_blocksize = 0; - - tk->p_es = NULL; - tk->p_out_muxed = NULL; + memset( tk, 0, sizeof( avi_track_t ) ); p_vids = (avi_chunk_strf_vids_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 ); p_auds = (avi_chunk_strf_auds_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 ); @@ -392,7 +390,9 @@ static int Open( vlc_object_t * p_this ) tk->i_cat = AUDIO_ES; tk->i_codec = AVI_FourccGetCodec( AUDIO_ES, p_auds->p_wf->wFormatTag ); - if( ( tk->i_blocksize = p_auds->p_wf->nBlockAlign ) == 0 ) + if( tk->i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ) + tk->i_blocksize = 0; /* fix vorbis VBR decoding */ + else if( ( tk->i_blocksize = p_auds->p_wf->nBlockAlign ) == 0 ) { if( p_auds->p_wf->wFormatTag == 1 ) { @@ -411,12 +411,85 @@ static int Open( vlc_object_t * p_this ) fmt.audio.i_blockalign = p_auds->p_wf->nBlockAlign; fmt.audio.i_bitspersample = p_auds->p_wf->wBitsPerSample; fmt.b_packetized = !tk->i_blocksize; + + msg_Dbg( p_demux, + "stream[%d] audio(0x%x) %d channels %dHz %dbits", + i, p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels, + p_auds->p_wf->nSamplesPerSec, + p_auds->p_wf->wBitsPerSample ); + fmt.i_extra = __MIN( p_auds->p_wf->cbSize, p_auds->i_chunk_size - sizeof(WAVEFORMATEX) ); - fmt.p_extra = &p_auds->p_wf[1]; - msg_Dbg( p_demux, "stream[%d] audio(0x%x) %d channels %dHz %dbits", - i, p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels, - p_auds->p_wf->nSamplesPerSec, p_auds->p_wf->wBitsPerSample); + fmt.p_extra = tk->p_extra = malloc( fmt.i_extra ); + if( !fmt.p_extra ) goto error; + memcpy( fmt.p_extra, &p_auds->p_wf[1], fmt.i_extra ); + + /* Rewrite the vorbis headers from Xiph-like format + * to VLC internal format + * + * Xiph format: + * - 1st byte == N, is the number of packets - 1 + * - Following bytes are the size of the N first packets: + * while( *p == 0xFF ) { size += 0xFF; p++ } size += *p; + * (the size of the last packet is the size of remaining + * data in the buffer) + * - Finally, all the packets concatenated + * + * VLC format: + * - Size of the packet on 16 bits (big endian) FIXME: should be 32 bits to be safe + * - The packet itself + * - Size of the next packet, and so on ... + */ + + if( tk->i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ) + { + uint8_t *p_extra = fmt.p_extra; + size_t i_extra = fmt.i_extra; + + if( i_extra <= 1 ) break; + if( *p_extra++ != 2 ) break; /* 3 packets - 1 = 2 */ + i_extra--; + + size_t i_identifier_len = 0; + while( *p_extra == 0xFF ) + { + i_identifier_len += 0xFF; + p_extra++; + if( --i_extra <= 1 ) break; + } + i_identifier_len += *p_extra++; + if( i_identifier_len > --i_extra ) break; + + size_t i_comment_len = 0; + while( *p_extra == 0xFF ) + { + i_comment_len += 0xFF; + p_extra++; + if( --i_extra <= 1 ) break; + } + i_comment_len += *p_extra++; + if( i_comment_len > --i_extra ) break; + size_t i_cookbook_len = i_extra; + + size_t i_headers_size = 3 * 2 + i_identifier_len + + i_comment_len + i_cookbook_len; + uint8_t *p_out = malloc( i_headers_size ); + if( !p_out ) goto error; + free( fmt.p_extra ); + fmt.p_extra = tk->p_extra = p_out; + fmt.i_extra = i_headers_size; + #define copy_packet( len ) \ + *p_out++ = len >> 8; \ + *p_out++ = len & 0xFF; \ + memcpy( p_out, p_extra, len ); \ + p_out += len; \ + p_extra += len; + copy_packet( i_identifier_len ); + copy_packet( i_comment_len ); + copy_packet( i_cookbook_len ); + #undef copy_packet + break; + } break; case( AVIFOURCC_vids ): @@ -689,11 +762,12 @@ static void Close ( vlc_object_t * p_this ) { if( p_sys->track[i]->p_out_muxed ) stream_DemuxDelete( p_sys->track[i]->p_out_muxed ); - FREENULL( p_sys->track[i]->p_index ); + free( p_sys->track[i]->p_index ); + free( p_sys->track[i]->p_extra ); free( p_sys->track[i] ); } } - FREENULL( p_sys->track ); + free( p_sys->track ); AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root ); vlc_meta_Delete( p_sys->meta ); -- 2.39.2