wolf3d-ios/wolf3d/wolfextractor/vorbisenc_inter.c

303 lines
6.4 KiB
C

/*
Copyright (C) 2005 Michael Liebscher
Copyright 2000-2002, Michael Smith <msmith@xiph.org>
(c) Kenneth Arnold <kcarnold@yahoo.com>
(c) Monty <monty@xiph.org>
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-1307, USA.
*/
/*
* vorbisenc_inter.c: Simple Ogg Vorbis interface.
*
* Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
* Date: 2005
*
* Acknowledgement:
* Portions from oggenc, Copyright 2000-2002, Michael Smith <msmith@xiph.org>
* Vorbize, (c) Kenneth Arnold <kcarnold@yahoo.com>
* and libvorbis examples, (c) Monty <monty@xiph.org>
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vorbis/vorbisenc.h>
#include "../../common/arch.h"
#include "../../common/common_utils.h"
#define READSIZE 1024
PRIVATE W32 channels;
PRIVATE W32 samplesize;
PRIVATE W8 *ptrCurrent;
PRIVATE W8 *ptrEnd;
long read_samples( float **buffer, int samples )
{
int sampbyte = samplesize / 8;
SW8 *buf;
long bytes_read;
int i,j;
long realsamples;
buf = ptrCurrent;
if( (samples * sampbyte * channels) > (ptrEnd - ptrCurrent) )
{
bytes_read = ptrEnd - ptrCurrent;
ptrCurrent = ptrEnd;
if( bytes_read == 0 )
{
return 0;
}
}
else
{
bytes_read = samples * sampbyte * channels;
ptrCurrent += samples * sampbyte * channels;
}
realsamples = bytes_read / (sampbyte * channels);
for( i = 0 ; i < realsamples ; ++i )
{
for( j = 0 ; j < channels ; ++j )
{
buffer[j][i] = ((buf[ i * 2 * channels + 2 * j + 1 ] << 8) |
(buf[ i * 2 * channels + 2 * j ] & 0xFF)) / 32768.0f;
}
}
return realsamples;
}
int vorbis_encode( const char *filename, void *data, W32 size, W32 in_channels, W32 in_samplesize,
W32 rate, W32 quality, W32 max_bitrate, W32 min_bitrate )
{
FILE *fp;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
vorbis_dsp_state vd;
vorbis_block vb;
vorbis_info vi;
ogg_packet header_main;
ogg_packet header_comments;
ogg_packet header_codebooks;
int result;
unsigned int serialno = 0;
vorbis_comment comments;
int ret = 0;
int eos;
W32 samplesdone = 0;
W32 packetsdone = 0;
W32 bytes_written = 0;
fp = fopen( filename, "wb" );
if( fp == NULL )
{
return 0;
}
memset( &comments, 0, sizeof( comments ) );
channels = in_channels;
samplesize = in_samplesize;
ptrCurrent = (PW8)data;
ptrEnd = (PW8)data + size;
vorbis_info_init( &vi );
if( vorbis_encode_setup_vbr( &vi, channels, rate, quality ) )
{
fprintf( stderr, "Mode initialisation failed: invalid parameters for quality\n" );
vorbis_info_clear( &vi );
return 1;
}
/* do we have optional hard quality restrictions? */
if( max_bitrate > 0 || min_bitrate > 0 )
{
struct ovectl_ratemanage_arg ai;
vorbis_encode_ctl( &vi, OV_ECTL_RATEMANAGE_GET, &ai );
ai.bitrate_hard_min = min_bitrate;
ai.bitrate_hard_max = max_bitrate;
ai.management_active = 1;
vorbis_encode_ctl( &vi, OV_ECTL_RATEMANAGE_SET, &ai );
}
/* Turn off management entirely (if it was turned on). */
vorbis_encode_ctl( &vi, OV_ECTL_RATEMANAGE_SET, NULL );
vorbis_encode_setup_init( &vi );
vorbis_analysis_init( &vd, &vi );
vorbis_block_init( &vd, &vb );
ogg_stream_init( &os, serialno );
/* Now, build the three header packets and send through to the stream
output stage (but defer actual file output until the main encode loop) */
/* Build the packets */
ret = vorbis_analysis_headerout( &vd, &comments,
&header_main, &header_comments, &header_codebooks );
/* And stream them out */
ogg_stream_packetin( &os, &header_main );
ogg_stream_packetin( &os, &header_comments );
ogg_stream_packetin( &os, &header_codebooks );
while( (result = ogg_stream_flush( &os, &og )) )
{
if( ! result )
{
break;
}
ret = fwrite( og.header, 1, og.header_len, fp );
ret += fwrite( og.body, 1, og.body_len, fp );
if(ret != og.header_len + og.body_len)
{
printf( "Failed writing header to output stream\n") ;
ret = 1;
goto cleanup; /* Bail and try to clean up stuff */
}
}
eos = 0;
/* Main encode loop - continue until end of file */
while( ! eos )
{
float **buffer = vorbis_analysis_buffer( &vd, READSIZE );
long samples_read = read_samples( buffer, READSIZE );
if( samples_read == 0 )
{
/* Tell the library that we wrote 0 bytes - signalling the end */
vorbis_analysis_wrote( &vd, 0 );
}
else
{
samplesdone += samples_read;
/* Call progress update every 40 pages */
if( packetsdone >= 40 )
{
packetsdone = 0;
// progress bar here
}
/* Tell the library how many samples (per channel) we wrote
into the supplied buffer */
vorbis_analysis_wrote( &vd, samples_read );
}
/* While we can get enough data from the library to analyse, one
block at a time... */
while( vorbis_analysis_blockout( &vd, &vb ) == 1 )
{
/* Do the main analysis, creating a packet */
vorbis_analysis( &vb, NULL );
vorbis_bitrate_addblock( &vb );
while( vorbis_bitrate_flushpacket( &vd, &op ) )
{
/* Add packet to bitstream */
ogg_stream_packetin( &os, &op );
packetsdone++;
/* If we've gone over a page boundary, we can do actual output,
so do so (for however many pages are available) */
while( ! eos )
{
int result = ogg_stream_pageout( &os, &og );
if( ! result )
{
break;
}
ret = fwrite( og.header, 1, og.header_len, fp );
ret += fwrite( og.body, 1, og.body_len, fp );
if(ret != og.header_len + og.body_len)
{
printf( "Failed writing data to output stream\n" );
ret = 1;
goto cleanup; /* Bail */
}
else
{
bytes_written += ret;
}
if( ogg_page_eos( &og ) )
{
eos = 1;
}
}
}
}
}
cleanup:
fclose( fp );
ogg_stream_clear( &os );
vorbis_block_clear( &vb );
vorbis_dsp_clear( &vd );
vorbis_info_clear( &vi );
return 0;
}