Added Opus support. 2nd part
This commit is contained in:
		
							parent
							
								
									ef5ba44013
								
							
						
					
					
						commit
						9cecd3f493
					
				| 
						 | 
				
			
			@ -0,0 +1,551 @@
 | 
			
		|||
/*------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
   Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
 | 
			
		||||
 | 
			
		||||
   Tyrell DarkIce
 | 
			
		||||
 | 
			
		||||
   File     : OpusLibEncoder.cpp
 | 
			
		||||
   Version  : $Revision$
 | 
			
		||||
   Author   : $Author$
 | 
			
		||||
   Location : $HeadURL$
 | 
			
		||||
 | 
			
		||||
   Copyright notice:
 | 
			
		||||
 | 
			
		||||
    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 3
 | 
			
		||||
    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.
 | 
			
		||||
 | 
			
		||||
------------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/* ============================================================ include files */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// compile only if configured for Ogg / Opus
 | 
			
		||||
#ifdef HAVE_OPUS_LIB
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "Exception.h"
 | 
			
		||||
#include "Util.h"
 | 
			
		||||
#include "OpusLibEncoder.h"
 | 
			
		||||
#include "CastSink.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ===================================================  local data structures */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ================================================  local constants & macros */
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------------------
 | 
			
		||||
 *  File identity
 | 
			
		||||
 *----------------------------------------------------------------------------*/
 | 
			
		||||
static const char fileid[] = "$Id$";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ===============================================  local function prototypes */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* =============================================================  module code */
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------------------
 | 
			
		||||
 *  Initialize the encoder
 | 
			
		||||
 *----------------------------------------------------------------------------*/
 | 
			
		||||
void
 | 
			
		||||
OpusLibEncoder :: init ( unsigned int     outMaxBitrate )
 | 
			
		||||
                                                            throw ( Exception )
 | 
			
		||||
{
 | 
			
		||||
    this->outMaxBitrate = outMaxBitrate;
 | 
			
		||||
 | 
			
		||||
    if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__,
 | 
			
		||||
                         "specified bits per sample not supported",
 | 
			
		||||
                         getInBitsPerSample() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( getInChannel() != 1 && getInChannel() != 2 ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__,
 | 
			
		||||
                         "unsupported number of channels for the encoder",
 | 
			
		||||
                         getInChannel() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( getOutSampleRate() != 48000 ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__,
 | 
			
		||||
                         "unsupported sample rate for this encoder",
 | 
			
		||||
                         getOutSampleRate() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( getOutSampleRate() == getInSampleRate() ) {
 | 
			
		||||
        resampleRatio = 1;
 | 
			
		||||
        converter     = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        resampleRatio = ( (double) getOutSampleRate() /
 | 
			
		||||
                          (double) getInSampleRate() );
 | 
			
		||||
 | 
			
		||||
        // Determine if we can use linear interpolation.
 | 
			
		||||
        // The inverse of the ratio must be a power of two for linear mode to
 | 
			
		||||
        // be of sufficient quality.
 | 
			
		||||
 | 
			
		||||
        bool    useLinear = true;
 | 
			
		||||
        double  inverse   = 1 / resampleRatio;
 | 
			
		||||
        int     integer   = (int) inverse;
 | 
			
		||||
 | 
			
		||||
        // Check that the inverse of the ratio is an integer
 | 
			
		||||
        if( integer == inverse ) {
 | 
			
		||||
            while( useLinear && integer ) { // Loop through the bits
 | 
			
		||||
                // If the lowest order bit is not the only one set
 | 
			
		||||
                if( integer & 1 && integer != 1 ) {
 | 
			
		||||
                    // Not a power of two; cannot use linear
 | 
			
		||||
                    useLinear = false;
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Shift all the bits over and try again
 | 
			
		||||
                    integer >>= 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
           useLinear = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If we get here and useLinear is still true, then we have
 | 
			
		||||
        // a power of two.
 | 
			
		||||
 | 
			
		||||
        // open the aflibConverter in
 | 
			
		||||
        // - high quality
 | 
			
		||||
        // - linear or quadratic (non-linear) based on algorithm
 | 
			
		||||
        // - not filter interpolation
 | 
			
		||||
#ifdef HAVE_SRC_LIB
 | 
			
		||||
        int srcError = 0;
 | 
			
		||||
        converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
 | 
			
		||||
                            getInChannel(), &srcError);
 | 
			
		||||
        if(srcError)
 | 
			
		||||
            throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
 | 
			
		||||
#else
 | 
			
		||||
        converter = new aflibConverter( true, useLinear, false);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int bufferSize = (getInBitsPerSample()/8) * getInChannel() * 480;
 | 
			
		||||
    internalBuffer = new unsigned char[bufferSize];
 | 
			
		||||
    internalBufferLength = 0;
 | 
			
		||||
    memset( internalBuffer, 0, bufferSize);
 | 
			
		||||
 | 
			
		||||
    encoderOpen = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------------------
 | 
			
		||||
 *  Open an encoding session
 | 
			
		||||
 *----------------------------------------------------------------------------*/
 | 
			
		||||
bool
 | 
			
		||||
OpusLibEncoder :: open ( void )
 | 
			
		||||
                                                            throw ( Exception )
 | 
			
		||||
{
 | 
			
		||||
    int     ret;
 | 
			
		||||
 | 
			
		||||
    if ( isOpen() ) {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // open the underlying sink
 | 
			
		||||
    if ( !getSink()->open() ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__,
 | 
			
		||||
                         "opus lib opening underlying sink error");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int err;
 | 
			
		||||
    opusEncoder = opus_encoder_create( getOutSampleRate(),
 | 
			
		||||
                                       getInChannel(),
 | 
			
		||||
                                       OPUS_APPLICATION_AUDIO,
 | 
			
		||||
                                       &err);
 | 
			
		||||
    if( err != OPUS_OK ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__,
 | 
			
		||||
                         "opus encoder creation error",
 | 
			
		||||
                         err);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    opus_encoder_ctl(opusEncoder, OPUS_SET_COMPLEXITY(10));
 | 
			
		||||
    opus_encoder_ctl(opusEncoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
 | 
			
		||||
 | 
			
		||||
    switch ( getOutBitrateMode() ) {
 | 
			
		||||
 | 
			
		||||
        case cbr: {
 | 
			
		||||
                int     maxBitrate = getOutMaxBitrate() * 1000;
 | 
			
		||||
                if ( !maxBitrate ) {
 | 
			
		||||
                    maxBitrate = 96000;
 | 
			
		||||
                }
 | 
			
		||||
                opus_encoder_ctl(opusEncoder, OPUS_SET_BITRATE(maxBitrate));
 | 
			
		||||
                opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(0));
 | 
			
		||||
            } break;
 | 
			
		||||
 | 
			
		||||
        case abr: {
 | 
			
		||||
                int     maxBitrate = getOutMaxBitrate() * 1000;
 | 
			
		||||
                if ( !maxBitrate ) {
 | 
			
		||||
                    maxBitrate = 96000;
 | 
			
		||||
                }
 | 
			
		||||
                /* set non-managed VBR around the average bitrate */
 | 
			
		||||
                opus_encoder_ctl(opusEncoder, OPUS_SET_BITRATE(maxBitrate));
 | 
			
		||||
                opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(1));
 | 
			
		||||
                opus_encoder_ctl(opusEncoder, OPUS_SET_VBR_CONSTRAINT(0));
 | 
			
		||||
            } break;
 | 
			
		||||
        case vbr:
 | 
			
		||||
            throw Exception( __FILE__, __LINE__, "vbr is not supported; use cbr/abr");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( (ret = ogg_stream_init( &oggStreamState, 0)) ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__, "ogg stream init error", ret);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // First, we need to assemble and send a OggOpus header.
 | 
			
		||||
    OpusIdHeader header;
 | 
			
		||||
    strncpy(header.magic, "OpusHead", 8);
 | 
			
		||||
    header.version = 1;
 | 
			
		||||
    header.channels = getOutChannel();
 | 
			
		||||
    header.preskip = 0;
 | 
			
		||||
    header.samplerate = getInSampleRate();
 | 
			
		||||
    header.gain = 0; // technically a fixed-point decimal.
 | 
			
		||||
    header.chanmap = 0;
 | 
			
		||||
 | 
			
		||||
    // And, now we need to send a Opus comment header.
 | 
			
		||||
    // Anything after this can be audio.
 | 
			
		||||
 | 
			
		||||
    char vendor[8] = "darkice";
 | 
			
		||||
    char titlestr[7] = "TITLE=";
 | 
			
		||||
    OpusCommentHeader::Tags tags[1];
 | 
			
		||||
    char name[40];
 | 
			
		||||
    CastSink* sink = dynamic_cast<CastSink*>(getSink().get());
 | 
			
		||||
    if( sink && sink->getName() ) {
 | 
			
		||||
        strncpy(name, (char*)sink->getName(), 39);
 | 
			
		||||
        name[39] = 0;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        strncpy(name, "Darkice Stream", 39);
 | 
			
		||||
    }
 | 
			
		||||
    tags[0].tag_len = strlen(titlestr) + strlen(name);
 | 
			
		||||
    tags[0].tag_str = (char*) malloc( tags[0].tag_len );
 | 
			
		||||
    if( tags[0].tag_str == NULL ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__, "malloc failed");
 | 
			
		||||
    }
 | 
			
		||||
    strncpy( tags[0].tag_str, titlestr, tags[0].tag_len);
 | 
			
		||||
    strncat( tags[0].tag_str, name, tags[0].tag_len);
 | 
			
		||||
 | 
			
		||||
    OpusCommentHeader commentHeader;
 | 
			
		||||
    strncpy(commentHeader.magic, "OpusTags", 8);
 | 
			
		||||
    commentHeader.vendor_length = strlen(vendor);
 | 
			
		||||
    commentHeader.vendor_string = vendor;
 | 
			
		||||
    commentHeader.num_tags = 1;
 | 
			
		||||
    commentHeader.tags = tags;
 | 
			
		||||
 | 
			
		||||
    ogg_packet      oggHeader;
 | 
			
		||||
    ogg_packet      oggCommentHeader;
 | 
			
		||||
    memset(&oggHeader, 0, sizeof(oggHeader));
 | 
			
		||||
    memset(&oggCommentHeader, 0, sizeof(oggCommentHeader));
 | 
			
		||||
    unsigned char* headerData = NULL;
 | 
			
		||||
    unsigned char* commentData = NULL;
 | 
			
		||||
    int headerLen = 0;
 | 
			
		||||
    int commentLen = 0;
 | 
			
		||||
 | 
			
		||||
    headerLen = header.buildPacket( &headerData);
 | 
			
		||||
    commentLen = commentHeader.buildPacket( &commentData);
 | 
			
		||||
 | 
			
		||||
    oggHeader.packet = headerData;
 | 
			
		||||
    oggHeader.bytes = headerLen;
 | 
			
		||||
    oggHeader.b_o_s = 1;
 | 
			
		||||
    oggHeader.e_o_s = 0;
 | 
			
		||||
    oggHeader.granulepos = 0;
 | 
			
		||||
    oggHeader.packetno = 0;
 | 
			
		||||
 | 
			
		||||
    oggCommentHeader.packet = commentData;
 | 
			
		||||
    oggCommentHeader.bytes = commentLen;
 | 
			
		||||
    oggCommentHeader.b_o_s = 0;
 | 
			
		||||
    oggCommentHeader.e_o_s = 0;
 | 
			
		||||
    oggCommentHeader.granulepos = 0;
 | 
			
		||||
    oggCommentHeader.packetno = 1;
 | 
			
		||||
 | 
			
		||||
    oggPacketNumber = 2;
 | 
			
		||||
    oggGranulePosition = 0;
 | 
			
		||||
 | 
			
		||||
    ogg_stream_packetin( &oggStreamState, &oggHeader);
 | 
			
		||||
    ogg_stream_packetin( &oggStreamState, &oggCommentHeader);
 | 
			
		||||
 | 
			
		||||
    ogg_page oggPage;
 | 
			
		||||
    while ( ogg_stream_flush( &oggStreamState, &oggPage) ) {
 | 
			
		||||
        getSink()->write( oggPage.header, oggPage.header_len);
 | 
			
		||||
        getSink()->write( oggPage.body, oggPage.body_len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free(tags[0].tag_str);
 | 
			
		||||
    free(headerData);
 | 
			
		||||
    free(commentData);
 | 
			
		||||
 | 
			
		||||
    // initialize the resampling coverter if needed
 | 
			
		||||
    if ( converter ) {
 | 
			
		||||
#ifdef HAVE_SRC_LIB
 | 
			
		||||
        converterData.input_frames   = 4096/((getInBitsPerSample() / 8) * getInChannel());
 | 
			
		||||
        converterData.data_in        = new float[converterData.input_frames*getInChannel()];
 | 
			
		||||
        converterData.output_frames  = (int) (converterData.input_frames * resampleRatio + 1);
 | 
			
		||||
        converterData.data_out       = new float[getInChannel() * converterData.output_frames];
 | 
			
		||||
        converterData.src_ratio      = resampleRatio;
 | 
			
		||||
        converterData.end_of_input   = 0;
 | 
			
		||||
#else
 | 
			
		||||
        converter->initialize( resampleRatio, getInChannel());
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    encoderOpen = true;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------------------
 | 
			
		||||
 *  Write data to the encoder
 | 
			
		||||
 *----------------------------------------------------------------------------*/
 | 
			
		||||
unsigned int
 | 
			
		||||
OpusLibEncoder :: write ( const void    * buf,
 | 
			
		||||
                          unsigned int    len )             throw ( Exception )
 | 
			
		||||
{
 | 
			
		||||
    if ( !isOpen() || len == 0 ) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned int    channels      = getInChannel();
 | 
			
		||||
    unsigned int    bitsPerSample = getInBitsPerSample();
 | 
			
		||||
    unsigned int    sampleSize = (bitsPerSample / 8) * channels;
 | 
			
		||||
 | 
			
		||||
    unsigned int i;
 | 
			
		||||
 | 
			
		||||
    if ( getInChannel() == 2 && getOutChannel() == 1 ) {
 | 
			
		||||
        for ( i = 0; i < len/sampleSize; i++) {
 | 
			
		||||
            if ( bitsPerSample == 8 ) {
 | 
			
		||||
                char          * buf8 = (char *) buf;
 | 
			
		||||
                unsigned int    ix   = sampleSize * i;
 | 
			
		||||
                unsigned int    iix  = ix;
 | 
			
		||||
                buf8[i] = (buf8[ix] + buf8[++iix]) / 2;
 | 
			
		||||
            }
 | 
			
		||||
            if ( bitsPerSample == 16 ) {
 | 
			
		||||
                short         * buf16 = (short *) buf;
 | 
			
		||||
                unsigned int    ix    = (bitsPerSample >> 3) * i;
 | 
			
		||||
                unsigned int    iix   = ix;
 | 
			
		||||
                buf16[i] = (buf16[ix] + buf16[++iix]) / 2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        len      >>= 1;
 | 
			
		||||
        channels   = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sampleSize = (bitsPerSample / 8) * channels;
 | 
			
		||||
    unsigned int    processed = 0;
 | 
			
		||||
    unsigned int    bytesToProcess = len - (len % sampleSize);
 | 
			
		||||
    unsigned int    totalProcessed = 0;
 | 
			
		||||
    unsigned char * b = (unsigned char*) buf;
 | 
			
		||||
    unsigned char * tempBuffer = NULL;
 | 
			
		||||
 | 
			
		||||
    if( internalBufferLength > 0 ) {
 | 
			
		||||
        tempBuffer = new unsigned char[len + internalBufferLength];
 | 
			
		||||
        memset( tempBuffer, 0, len + internalBufferLength);
 | 
			
		||||
        if( !tempBuffer ) {
 | 
			
		||||
            throw Exception( __FILE__, __LINE__, "could not allocate temp buffer");
 | 
			
		||||
        }
 | 
			
		||||
        memcpy( tempBuffer, internalBuffer, internalBufferLength);
 | 
			
		||||
        memcpy( tempBuffer+internalBufferLength, buf, len);
 | 
			
		||||
        b = tempBuffer;
 | 
			
		||||
        bytesToProcess += internalBufferLength;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    while ( bytesToProcess / resampleRatio >= 480 * sampleSize ) {
 | 
			
		||||
        unsigned int toProcess = bytesToProcess / (resampleRatio * sampleSize);
 | 
			
		||||
        if( toProcess >= 480 / resampleRatio) {
 | 
			
		||||
            processed = 480 / resampleRatio;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int opusBufferSize = (1275*3+7)*channels;
 | 
			
		||||
        unsigned char*   opusBuffer = new unsigned char[opusBufferSize];
 | 
			
		||||
 | 
			
		||||
        // convert the byte-based raw input into a short buffer
 | 
			
		||||
        // with channels still interleaved
 | 
			
		||||
        unsigned int    totalSamples = processed * channels;
 | 
			
		||||
        short int     * shortBuffer  = new short int[totalSamples];
 | 
			
		||||
 | 
			
		||||
        Util::conv( bitsPerSample, b, processed*sampleSize, shortBuffer, isInBigEndian());
 | 
			
		||||
 | 
			
		||||
        if ( converter && processed > 0 ) {
 | 
			
		||||
            // resample if needed
 | 
			
		||||
            int         inCount  = processed;
 | 
			
		||||
            int         outCount = 480; //(int) (inCount * resampleRatio);
 | 
			
		||||
            short int * resampledBuffer = new short int[(outCount+1)* channels];
 | 
			
		||||
            int         converted;
 | 
			
		||||
#ifdef HAVE_SRC_LIB
 | 
			
		||||
            (void)inCount;
 | 
			
		||||
            converterData.input_frames   = processed;
 | 
			
		||||
            src_short_to_float_array (shortBuffer, converterData.data_in, totalSamples);
 | 
			
		||||
            int srcError = src_process (converter, &converterData);
 | 
			
		||||
            if (srcError)
 | 
			
		||||
                 throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
 | 
			
		||||
            converted = converterData.output_frames_gen;
 | 
			
		||||
 | 
			
		||||
            src_float_to_short_array(converterData.data_out, resampledBuffer, converted*channels);
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
            converted = converter->resample( inCount,
 | 
			
		||||
                                             outCount,
 | 
			
		||||
                                             shortBuffer,
 | 
			
		||||
                                             resampledBuffer );
 | 
			
		||||
#endif
 | 
			
		||||
            if( converted != 480) {
 | 
			
		||||
                throw Exception( __FILE__, __LINE__, "resampler error: expected 480 samples", converted);
 | 
			
		||||
            }
 | 
			
		||||
            int encBytes = opus_encode( opusEncoder, resampledBuffer, 480, opusBuffer, opusBufferSize);
 | 
			
		||||
            if( encBytes == -1 ) {
 | 
			
		||||
                throw Exception( __FILE__, __LINE__, "opus encoder error");
 | 
			
		||||
            }
 | 
			
		||||
            oggGranulePosition += converted;
 | 
			
		||||
            opusBlocksOut( encBytes, opusBuffer);
 | 
			
		||||
 | 
			
		||||
            delete[] resampledBuffer;
 | 
			
		||||
 | 
			
		||||
        } else if( processed > 0) {
 | 
			
		||||
            memset( opusBuffer, 0, opusBufferSize);
 | 
			
		||||
            int encBytes = opus_encode( opusEncoder, shortBuffer, processed, opusBuffer, opusBufferSize);
 | 
			
		||||
            if( encBytes == -1 ) {
 | 
			
		||||
                throw Exception( __FILE__, __LINE__, "opus encoder error");
 | 
			
		||||
            }
 | 
			
		||||
            oggGranulePosition += processed;
 | 
			
		||||
            opusBlocksOut( encBytes, opusBuffer);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        delete[] shortBuffer;
 | 
			
		||||
        delete[] opusBuffer;
 | 
			
		||||
        bytesToProcess -= processed * sampleSize;
 | 
			
		||||
        totalProcessed += processed * sampleSize;
 | 
			
		||||
        b = ((unsigned char*)b) + (processed * sampleSize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int newLen = len - (len % sampleSize) + internalBufferLength - totalProcessed;
 | 
			
		||||
    newLen -= newLen % sampleSize;
 | 
			
		||||
 | 
			
		||||
    if( newLen > 0 ) {
 | 
			
		||||
        memcpy( internalBuffer, b, newLen);
 | 
			
		||||
        totalProcessed += newLen;
 | 
			
		||||
        internalBufferLength = newLen;
 | 
			
		||||
    } else {
 | 
			
		||||
        internalBufferLength = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if( tempBuffer ) {
 | 
			
		||||
        delete[] tempBuffer;
 | 
			
		||||
        tempBuffer = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return totalProcessed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------------------
 | 
			
		||||
 *  Flush the data from the encoder
 | 
			
		||||
 *----------------------------------------------------------------------------*/
 | 
			
		||||
void
 | 
			
		||||
OpusLibEncoder :: flush ( void )
 | 
			
		||||
                                                            throw ( Exception )
 | 
			
		||||
{
 | 
			
		||||
    if ( !isOpen() ) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int opusBufferSize = (1275*3+7)*getOutChannel();
 | 
			
		||||
    unsigned char * opusBuffer = new unsigned char[opusBufferSize];
 | 
			
		||||
    short int * shortBuffer = new short int[480];
 | 
			
		||||
 | 
			
		||||
    // Send an empty audio packet along to flush out the stream.
 | 
			
		||||
    memset( shortBuffer, 0, 480);
 | 
			
		||||
    memset( opusBuffer, 0, opusBufferSize);
 | 
			
		||||
    int encBytes = opus_encode( opusEncoder, shortBuffer, 480, opusBuffer, opusBufferSize);
 | 
			
		||||
    if( encBytes == -1 ) {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__, "opus encoder error");
 | 
			
		||||
    }
 | 
			
		||||
    oggGranulePosition += 480;
 | 
			
		||||
 | 
			
		||||
    // Send the empty block to the Ogg layer, and mark the
 | 
			
		||||
    // EOS flag.  This will trigger any remaining packets to be
 | 
			
		||||
    // sent.
 | 
			
		||||
    opusBlocksOut( encBytes, opusBuffer, true);
 | 
			
		||||
    delete[] opusBuffer;
 | 
			
		||||
    delete[] shortBuffer;
 | 
			
		||||
    getSink()->flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------------------
 | 
			
		||||
 *  Send pending Opus blocks to the underlying stream
 | 
			
		||||
 *----------------------------------------------------------------------------*/
 | 
			
		||||
void
 | 
			
		||||
OpusLibEncoder :: opusBlocksOut ( int bytes,
 | 
			
		||||
                                  unsigned char* data,
 | 
			
		||||
                                  bool eos )               throw ( Exception )
 | 
			
		||||
{
 | 
			
		||||
    ogg_packet      oggPacket;
 | 
			
		||||
    ogg_page        oggPage;
 | 
			
		||||
 | 
			
		||||
    oggPacket.packet = data;
 | 
			
		||||
    oggPacket.bytes = bytes;
 | 
			
		||||
    oggPacket.b_o_s = 0;
 | 
			
		||||
    oggPacket.e_o_s = ( eos ) ? 1 : 0;
 | 
			
		||||
    oggPacket.granulepos = oggGranulePosition;
 | 
			
		||||
    oggPacket.packetno = oggPacketNumber;
 | 
			
		||||
    oggPacketNumber++;
 | 
			
		||||
 | 
			
		||||
    if( ogg_stream_packetin( &oggStreamState, &oggPacket) == 0) {
 | 
			
		||||
        while( ogg_stream_pageout( &oggStreamState, &oggPage) ||
 | 
			
		||||
            ( eos && ogg_stream_flush( &oggStreamState, &oggPage) ) ) {
 | 
			
		||||
            int    written;
 | 
			
		||||
 | 
			
		||||
            written  = getSink()->write(oggPage.header, oggPage.header_len);
 | 
			
		||||
            written += getSink()->write( oggPage.body, oggPage.body_len);
 | 
			
		||||
 | 
			
		||||
            if ( written < oggPage.header_len + oggPage.body_len ) {
 | 
			
		||||
                // just let go data that could not be written
 | 
			
		||||
                reportEvent( 2,
 | 
			
		||||
                       "couldn't write full opus data to underlying sink",
 | 
			
		||||
                       oggPage.header_len + oggPage.body_len - written);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        throw Exception( __FILE__, __LINE__, "internal ogg error");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------------------
 | 
			
		||||
 *  Close the encoding session
 | 
			
		||||
 *----------------------------------------------------------------------------*/
 | 
			
		||||
void
 | 
			
		||||
OpusLibEncoder :: close ( void )                    throw ( Exception )
 | 
			
		||||
{
 | 
			
		||||
    if ( isOpen() ) {
 | 
			
		||||
        flush();
 | 
			
		||||
 | 
			
		||||
        ogg_stream_clear( &oggStreamState);
 | 
			
		||||
        opus_encoder_destroy( opusEncoder);
 | 
			
		||||
        opusEncoder = NULL;
 | 
			
		||||
 | 
			
		||||
        encoderOpen = false;
 | 
			
		||||
        delete[] internalBuffer;
 | 
			
		||||
 | 
			
		||||
        getSink()->close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // HAVE_OPUS_LIB
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,561 @@
 | 
			
		|||
/*------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
   Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
 | 
			
		||||
 | 
			
		||||
   Tyrell DarkIce
 | 
			
		||||
 | 
			
		||||
   File     : OpusLibEncoder.h
 | 
			
		||||
   Version  : $Revision$
 | 
			
		||||
   Author   : $Author$
 | 
			
		||||
   Location : $HeadURL$
 | 
			
		||||
 | 
			
		||||
   Copyright notice:
 | 
			
		||||
 | 
			
		||||
    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 3
 | 
			
		||||
    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.
 | 
			
		||||
 | 
			
		||||
------------------------------------------------------------------------------*/
 | 
			
		||||
#ifndef OPUS_LIB_ENCODER_H
 | 
			
		||||
#define OPUS_LIB_ENCODER_H
 | 
			
		||||
 | 
			
		||||
#ifndef __cplusplus
 | 
			
		||||
#error This is a C++ include file
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ============================================================ include files */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPUS_LIB
 | 
			
		||||
#include <opus/opus.h>
 | 
			
		||||
#include <ogg/ogg.h>
 | 
			
		||||
#else
 | 
			
		||||
#error configure for Ogg Opus
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "Ref.h"
 | 
			
		||||
#include "Exception.h"
 | 
			
		||||
#include "Reporter.h"
 | 
			
		||||
#include "AudioEncoder.h"
 | 
			
		||||
#include "CastSink.h"
 | 
			
		||||
#ifdef HAVE_SRC_LIB
 | 
			
		||||
#include <samplerate.h>
 | 
			
		||||
#else
 | 
			
		||||
#include "aflibConverter.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ================================================================ constants */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* =================================================================== macros */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* =============================================================== data types */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  A struct for containing the ogg opus header format, sent at the stream
 | 
			
		||||
 *  beginning.
 | 
			
		||||
 *
 | 
			
		||||
 *  @author $Author$
 | 
			
		||||
 *  @version $Revision$
 | 
			
		||||
 */
 | 
			
		||||
struct OpusIdHeader {
 | 
			
		||||
    char magic[8];              /* "OpusHead" */
 | 
			
		||||
    unsigned char version;      /* Version (currently 1) */
 | 
			
		||||
    unsigned char channels;     /* Number of channels */
 | 
			
		||||
    unsigned short preskip;     /* Pre-skip */
 | 
			
		||||
    unsigned int samplerate;    /* Original samplerate; informational only */
 | 
			
		||||
    unsigned short gain;        /* Output gain, stored in Q7.8 in dB */
 | 
			
		||||
    unsigned char chanmap;      /* 0 = mono or stereo L/R, 1=vorbis spec order, 2..254=reserved, 255=undef */
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Build an Ogg packet from the header.
 | 
			
		||||
     * @param packet output pointer, must be freed by caller
 | 
			
		||||
     *
 | 
			
		||||
     * @return number of bytes in packet.
 | 
			
		||||
     */
 | 
			
		||||
    inline int buildPacket( unsigned char** packet) throw ( Exception ) {
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        // FIXME - doesn't support multistream
 | 
			
		||||
        unsigned char* out = (unsigned char*)malloc(15);
 | 
			
		||||
        if( out == NULL ) {
 | 
			
		||||
             throw Exception( __FILE__, __LINE__, "cannot alloc buffer");
 | 
			
		||||
        }
 | 
			
		||||
        for( ; i < 8; i++) {
 | 
			
		||||
            out[i] = magic[i];
 | 
			
		||||
        }
 | 
			
		||||
        out[i++] = version;
 | 
			
		||||
        out[i++] = channels;
 | 
			
		||||
        out[i++] = preskip & 0xff;
 | 
			
		||||
        out[i++] = (preskip >> 8) & 0xff;
 | 
			
		||||
        out[i++] = samplerate & 0xff;
 | 
			
		||||
        out[i++] = (samplerate >> 8) & 0xff;
 | 
			
		||||
        out[i++] = (samplerate >> 16) & 0xff;
 | 
			
		||||
        out[i++] = (samplerate >> 24) & 0xff;
 | 
			
		||||
        out[i++] = gain & 0xff;
 | 
			
		||||
        out[i++] = (gain >> 8) & 0xff;
 | 
			
		||||
        out[i++] = chanmap;
 | 
			
		||||
        *packet = out;
 | 
			
		||||
        return i;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  A struct for containing the ogg opus comment header format
 | 
			
		||||
 *
 | 
			
		||||
 *  @author $Author$
 | 
			
		||||
 *  @version $Revision$
 | 
			
		||||
 */
 | 
			
		||||
struct OpusCommentHeader {
 | 
			
		||||
    /**
 | 
			
		||||
     * Struct for each tag pair, in the form of a UTF-8
 | 
			
		||||
     * string, "TAG=value"
 | 
			
		||||
     *
 | 
			
		||||
     * @author $Author$
 | 
			
		||||
     * @version $Revision$
 | 
			
		||||
     */
 | 
			
		||||
    struct Tags {
 | 
			
		||||
        unsigned int tag_len;   /* For each tag, how long the following tag is */
 | 
			
		||||
        char* tag_str;          /* For each tag, UTF-8 encoded string, in tag=value */
 | 
			
		||||
    };
 | 
			
		||||
    char magic[8];              /* "OpusTags" */
 | 
			
		||||
    unsigned int vendor_length; /* Length of the vendor string */
 | 
			
		||||
    char* vendor_string;        /* Vendor string -- parsed as utf-8 */
 | 
			
		||||
    unsigned int num_tags;      /* Number of tags following */
 | 
			
		||||
    Tags* tags;                 /* Pointer to allocated tag array */
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Build an Ogg packet from the header.
 | 
			
		||||
     * @param packet output pointer, must be freed by caller
 | 
			
		||||
     *
 | 
			
		||||
     * @return number of bytes in packet.
 | 
			
		||||
     */
 | 
			
		||||
    inline int buildPacket( unsigned char** packet) throw ( Exception ) {
 | 
			
		||||
        int len = 8 + sizeof(unsigned int) * 2 + vendor_length;
 | 
			
		||||
        int pos = 0;
 | 
			
		||||
        for( unsigned int i = 0; i < num_tags; i++ )
 | 
			
		||||
        {
 | 
			
		||||
            len += sizeof(unsigned int) + tags[i].tag_len;
 | 
			
		||||
        }
 | 
			
		||||
        unsigned char* out = (unsigned char*)malloc(len);
 | 
			
		||||
        if( out == NULL ) {
 | 
			
		||||
             throw Exception( __FILE__, __LINE__, "cannot alloc buffer");
 | 
			
		||||
        }
 | 
			
		||||
        for( ; pos < 8; pos++) {
 | 
			
		||||
            out[pos] = magic[pos];
 | 
			
		||||
        }
 | 
			
		||||
        out[pos++] = vendor_length & 0xff;
 | 
			
		||||
        out[pos++] = (vendor_length >> 8) & 0xff;
 | 
			
		||||
        out[pos++] = (vendor_length >> 16) & 0xff;
 | 
			
		||||
        out[pos++] = (vendor_length >> 24) & 0xff;
 | 
			
		||||
        for( unsigned int i = 0; i < vendor_length; i++ ) {
 | 
			
		||||
            out[pos++] = vendor_string[i];
 | 
			
		||||
        }
 | 
			
		||||
        out[pos++] = num_tags & 0xff;
 | 
			
		||||
        out[pos++] = (num_tags >> 8) & 0xff;
 | 
			
		||||
        out[pos++] = (num_tags >> 16) & 0xff;
 | 
			
		||||
        out[pos++] = (num_tags >> 24) & 0xff;
 | 
			
		||||
        for( unsigned int i = 0; i < num_tags; i++ ) {
 | 
			
		||||
            out[pos++] = tags[i].tag_len & 0xff;
 | 
			
		||||
            out[pos++] = (tags[i].tag_len >> 8) & 0xff;
 | 
			
		||||
            out[pos++] = (tags[i].tag_len >> 16) & 0xff;
 | 
			
		||||
            out[pos++] = (tags[i].tag_len >> 24) & 0xff;
 | 
			
		||||
            for( unsigned int j = 0; j < tags[i].tag_len; j++ ) {
 | 
			
		||||
                out[pos++] = tags[i].tag_str[j];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        *packet = out;
 | 
			
		||||
        return len;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  A class representing the ogg opus encoder linked as a shared object or
 | 
			
		||||
 *  as a static library.
 | 
			
		||||
 *
 | 
			
		||||
 *  @author  $Author$
 | 
			
		||||
 *  @version $Revision$
 | 
			
		||||
 */
 | 
			
		||||
class OpusLibEncoder : public AudioEncoder, public virtual Reporter
 | 
			
		||||
{
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Value indicating if the encoding process is going on
 | 
			
		||||
         */
 | 
			
		||||
        bool                            encoderOpen;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Ogg Opus library global info
 | 
			
		||||
         */
 | 
			
		||||
        OpusEncoder*                    opusEncoder;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Ogg library global stream state
 | 
			
		||||
         */
 | 
			
		||||
        ogg_stream_state                oggStreamState;
 | 
			
		||||
 | 
			
		||||
        ogg_int64_t                     oggGranulePosition;
 | 
			
		||||
        ogg_int64_t                     oggPacketNumber;
 | 
			
		||||
 | 
			
		||||
        unsigned char*                  internalBuffer;
 | 
			
		||||
        int                             internalBufferLength;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Maximum bitrate of the output in kbits/sec. If 0, don't care.
 | 
			
		||||
         */
 | 
			
		||||
        unsigned int                    outMaxBitrate;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Resample ratio
 | 
			
		||||
         */
 | 
			
		||||
        double                          resampleRatio;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  sample rate converter object for possible resampling
 | 
			
		||||
         */
 | 
			
		||||
#ifdef HAVE_SRC_LIB
 | 
			
		||||
        SRC_STATE                     * converter;
 | 
			
		||||
        SRC_DATA                      converterData;
 | 
			
		||||
#else
 | 
			
		||||
        aflibConverter                * converter;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Initialize the object.
 | 
			
		||||
         *
 | 
			
		||||
         *  @param the maximum bit rate
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        void
 | 
			
		||||
        init ( unsigned int     outMaxBitrate )         throw ( Exception );
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  De-initialize the object.
 | 
			
		||||
         *
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline void
 | 
			
		||||
        strip ( void )                                  throw ( Exception )
 | 
			
		||||
        {
 | 
			
		||||
            if ( converter ) {
 | 
			
		||||
#ifdef HAVE_SRC_LIB
 | 
			
		||||
                delete [] converterData.data_in;
 | 
			
		||||
                delete [] converterData.data_out;
 | 
			
		||||
                src_delete (converter);
 | 
			
		||||
#else
 | 
			
		||||
                delete converter;
 | 
			
		||||
#endif
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Send pending Opus blocks to the underlying stream
 | 
			
		||||
         */
 | 
			
		||||
        void
 | 
			
		||||
        opusBlocksOut( int bytes,
 | 
			
		||||
                       unsigned char* data,
 | 
			
		||||
                       bool eos = false )               throw ( Exception );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Default constructor. Always throws an Exception.
 | 
			
		||||
         *
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline
 | 
			
		||||
        OpusLibEncoder ( void )                         throw ( Exception )
 | 
			
		||||
        {
 | 
			
		||||
            throw Exception( __FILE__, __LINE__);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Constructor.
 | 
			
		||||
         *
 | 
			
		||||
         *  @param sink the sink to send encoded output to
 | 
			
		||||
         *  @param inSampleRate sample rate of the input.
 | 
			
		||||
         *  @param inBitsPerSample number of bits per sample of the input.
 | 
			
		||||
         *  @param inChannel number of channels  of the input.
 | 
			
		||||
         *  @param inBigEndian shows if the input is big or little endian
 | 
			
		||||
         *  @param outBitrateMode the bit rate mode of the output.
 | 
			
		||||
         *  @param outBitrate bit rate of the output (kbits/sec).
 | 
			
		||||
         *  @param outQuality the quality of the stream.
 | 
			
		||||
         *  @param outSampleRate sample rate of the output.
 | 
			
		||||
         *                       If 0, inSampleRate is used.
 | 
			
		||||
         *  @param outMaxBitrate maximum output bitrate.
 | 
			
		||||
         *                       0 if not used.
 | 
			
		||||
         *  @param outChannel number of channels of the output.
 | 
			
		||||
         *                    If 0, inChannel is used.
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline
 | 
			
		||||
        OpusLibEncoder (  CastSink      * sink,
 | 
			
		||||
                            unsigned int    inSampleRate,
 | 
			
		||||
                            unsigned int    inBitsPerSample,
 | 
			
		||||
                            unsigned int    inChannel,
 | 
			
		||||
                            bool            inBigEndian,
 | 
			
		||||
                            BitrateMode     outBitrateMode,
 | 
			
		||||
                            unsigned int    outBitrate,
 | 
			
		||||
                            double          outQuality,
 | 
			
		||||
                            unsigned int    outSampleRate = 0,
 | 
			
		||||
                            unsigned int    outChannel    = 0,
 | 
			
		||||
                            unsigned int    outMaxBitrate = 0 )
 | 
			
		||||
                                                        throw ( Exception )
 | 
			
		||||
 | 
			
		||||
                    : AudioEncoder ( sink,
 | 
			
		||||
                                     inSampleRate,
 | 
			
		||||
                                     inBitsPerSample,
 | 
			
		||||
                                     inChannel,
 | 
			
		||||
                                     inBigEndian,
 | 
			
		||||
                                     outBitrateMode,
 | 
			
		||||
                                     outBitrate,
 | 
			
		||||
                                     outQuality,
 | 
			
		||||
                                     outSampleRate,
 | 
			
		||||
                                     outChannel )
 | 
			
		||||
        {
 | 
			
		||||
            init( outMaxBitrate);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Constructor.
 | 
			
		||||
         *
 | 
			
		||||
         *  @param sink the sink to send encoded output to
 | 
			
		||||
         *  @param as get input sample rate, bits per sample and channels
 | 
			
		||||
         *            from this AudioSource.
 | 
			
		||||
         *  @param outBitrateMode the bit rate mode of the output.
 | 
			
		||||
         *  @param outBitrate bit rate of the output (kbits/sec).
 | 
			
		||||
         *  @param outQuality the quality of the stream.
 | 
			
		||||
         *  @param outSampleRate sample rate of the output.
 | 
			
		||||
         *                       If 0, input sample rate is used.
 | 
			
		||||
         *  @param outMaxBitrate maximum output bitrate.
 | 
			
		||||
         *                       0 if not used.
 | 
			
		||||
         *  @param outChannel number of channels of the output.
 | 
			
		||||
         *                    If 0, input channel is used.
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline
 | 
			
		||||
        OpusLibEncoder (  CastSink              * sink,
 | 
			
		||||
                            const AudioSource     * as,
 | 
			
		||||
                            BitrateMode             outBitrateMode,
 | 
			
		||||
                            unsigned int            outBitrate,
 | 
			
		||||
                            double                  outQuality,
 | 
			
		||||
                            unsigned int            outSampleRate = 0,
 | 
			
		||||
                            unsigned int            outChannel    = 0,
 | 
			
		||||
                            unsigned int            outMaxBitrate = 0 )
 | 
			
		||||
                                                            throw ( Exception )
 | 
			
		||||
 | 
			
		||||
                    : AudioEncoder ( sink,
 | 
			
		||||
                                     as,
 | 
			
		||||
                                     outBitrateMode,
 | 
			
		||||
                                     outBitrate,
 | 
			
		||||
                                     outQuality,
 | 
			
		||||
                                     outSampleRate,
 | 
			
		||||
                                     outChannel )
 | 
			
		||||
        {
 | 
			
		||||
            init( outMaxBitrate);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Copy constructor.
 | 
			
		||||
         *
 | 
			
		||||
         *  @param encoder the OpusLibEncoder to copy.
 | 
			
		||||
         */
 | 
			
		||||
        inline
 | 
			
		||||
        OpusLibEncoder (  const OpusLibEncoder &    encoder )
 | 
			
		||||
                                                            throw ( Exception )
 | 
			
		||||
                    : AudioEncoder( encoder )
 | 
			
		||||
        {
 | 
			
		||||
            if( encoder.isOpen() ) {
 | 
			
		||||
                throw Exception(__FILE__, __LINE__, "don't copy open encoders");
 | 
			
		||||
            }
 | 
			
		||||
            init( encoder.getOutMaxBitrate() );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Destructor.
 | 
			
		||||
         *
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline virtual
 | 
			
		||||
        ~OpusLibEncoder ( void )                         throw ( Exception )
 | 
			
		||||
        {
 | 
			
		||||
            if ( isOpen() ) {
 | 
			
		||||
                close();
 | 
			
		||||
            }
 | 
			
		||||
            strip();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Assignment operator.
 | 
			
		||||
         *
 | 
			
		||||
         *  @param encoder the OpusLibEncoder to assign this to.
 | 
			
		||||
         *  @return a reference to this OpusLibEncoder.
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline virtual OpusLibEncoder &
 | 
			
		||||
        operator= ( const OpusLibEncoder &   encoder )   throw ( Exception )
 | 
			
		||||
        {
 | 
			
		||||
            if( encoder.isOpen() ) {
 | 
			
		||||
                throw Exception(__FILE__, __LINE__, "don't copy open encoders");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ( this != &encoder ) {
 | 
			
		||||
                strip();
 | 
			
		||||
                AudioEncoder::operator=( encoder);
 | 
			
		||||
                init( encoder.getOutMaxBitrate() );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Get the maximum bit rate of the output in kbits/sec,
 | 
			
		||||
         *  for fixed / average bitrate encodings.
 | 
			
		||||
         *
 | 
			
		||||
         *  @return the maximum bit rate of the output, or 0 if not set.
 | 
			
		||||
         */
 | 
			
		||||
        inline unsigned int
 | 
			
		||||
        getOutMaxBitrate ( void ) const        throw ()
 | 
			
		||||
        {
 | 
			
		||||
            return outMaxBitrate;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Check wether encoding is in progress.
 | 
			
		||||
         *
 | 
			
		||||
         *  @return true if encoding is in progress, false otherwise.
 | 
			
		||||
         */
 | 
			
		||||
        inline virtual bool
 | 
			
		||||
        isRunning ( void ) const           throw ()
 | 
			
		||||
        {
 | 
			
		||||
            return isOpen();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Start encoding. This function returns as soon as possible,
 | 
			
		||||
         *  with encoding started in the background.
 | 
			
		||||
         *
 | 
			
		||||
         *  @return true if encoding has started, false otherwise.
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline virtual bool
 | 
			
		||||
        start ( void )                      throw ( Exception )
 | 
			
		||||
        {
 | 
			
		||||
            return open();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Stop encoding. Stops the encoding running in the background.
 | 
			
		||||
         *
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline virtual void
 | 
			
		||||
        stop ( void )                       throw ( Exception )
 | 
			
		||||
        {
 | 
			
		||||
            return close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Open an encoding session.
 | 
			
		||||
         *
 | 
			
		||||
         *  @return true if opening was successfull, false otherwise.
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        virtual bool
 | 
			
		||||
        open ( void )                               throw ( Exception );
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Check if the encoding session is open.
 | 
			
		||||
         *
 | 
			
		||||
         *  @return true if the encoding session is open, false otherwise.
 | 
			
		||||
         */
 | 
			
		||||
        inline virtual bool
 | 
			
		||||
        isOpen ( void ) const                       throw ()
 | 
			
		||||
        {
 | 
			
		||||
            return encoderOpen;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Check if the encoder is ready to accept data.
 | 
			
		||||
         *
 | 
			
		||||
         *  @param sec the maximum seconds to block.
 | 
			
		||||
         *  @param usec micro seconds to block after the full seconds.
 | 
			
		||||
         *  @return true if the encoder is ready to accept data,
 | 
			
		||||
         *          false otherwise.
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        inline virtual bool
 | 
			
		||||
        canWrite (     unsigned int    sec,
 | 
			
		||||
                       unsigned int    usec )       throw ( Exception )
 | 
			
		||||
        {
 | 
			
		||||
            if ( !isOpen() ) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return getSink()->canWrite(sec, usec);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Write data to the encoder.
 | 
			
		||||
         *  Buf is expected to be a sequence of big-endian 16 bit values,
 | 
			
		||||
         *  with left and right channels interleaved. Len is the number of
 | 
			
		||||
         *  bytes, must be a multiple of 4.
 | 
			
		||||
         *
 | 
			
		||||
         *  @param buf the data to write.
 | 
			
		||||
         *  @param len number of bytes to write from buf.
 | 
			
		||||
         *  @return the number of bytes written (may be less than len).
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        virtual unsigned int
 | 
			
		||||
        write (        const void    * buf,
 | 
			
		||||
                       unsigned int    len )        throw ( Exception );
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Flush all data that was written to the encoder to the underlying
 | 
			
		||||
         *  connection.
 | 
			
		||||
         *
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        virtual void
 | 
			
		||||
        flush ( void )                              throw ( Exception );
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *  Close the encoding session.
 | 
			
		||||
         *
 | 
			
		||||
         *  @exception Exception
 | 
			
		||||
         */
 | 
			
		||||
        virtual void
 | 
			
		||||
        close ( void )                              throw ( Exception );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ================================================= external data structures */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ====================================================== function prototypes */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif  /* OPUS_LIB_ENCODER_H */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue