Blame dshow/Encoder.cpp

Packit 47f805
/*
Packit 47f805
 *  LAME MP3 encoder for DirectShow
Packit 47f805
 *  LAME encoder wrapper
Packit 47f805
 *
Packit 47f805
 *  Copyright (c) 2000-2005 Marie Orlova, Peter Gubanov, Vitaly Ivanov, Elecard Ltd.
Packit 47f805
 *
Packit 47f805
 * This library is free software; you can redistribute it and/or
Packit 47f805
 * modify it under the terms of the GNU Library General Public
Packit 47f805
 * License as published by the Free Software Foundation; either
Packit 47f805
 * version 2 of the License, or (at your option) any later version.
Packit 47f805
 *
Packit 47f805
 * This library is distributed in the hope that it will be useful,
Packit 47f805
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 47f805
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit 47f805
 * Library General Public License for more details.
Packit 47f805
 *
Packit 47f805
 * You should have received a copy of the GNU Library General Public
Packit 47f805
 * License along with this library; if not, write to the
Packit 47f805
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 47f805
 * Boston, MA 02111-1307, USA.
Packit 47f805
 */
Packit 47f805
Packit 47f805
#include <streams.h>
Packit 47f805
#include "Encoder.h"
Packit 47f805
Packit 47f805
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
// Construction/Destruction
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
CEncoder::CEncoder() :
Packit 47f805
    m_bInpuTypeSet(FALSE),
Packit 47f805
    m_bOutpuTypeSet(FALSE),
Packit 47f805
    m_bFinished(FALSE),
Packit 47f805
    m_outOffset(0),
Packit 47f805
    m_outReadOffset(0),
Packit 47f805
    m_frameCount(0),
Packit 47f805
    pgf(NULL)
Packit 47f805
{
Packit 47f805
    m_outFrameBuf = new unsigned char[OUT_BUFFER_SIZE];
Packit 47f805
}
Packit 47f805
Packit 47f805
CEncoder::~CEncoder()
Packit 47f805
{
Packit 47f805
    Close(NULL);
Packit 47f805
Packit 47f805
    if (m_outFrameBuf)
Packit 47f805
        delete [] m_outFrameBuf;
Packit 47f805
}
Packit 47f805
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
// SetInputType - check if given input type is supported
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
HRESULT CEncoder::SetInputType(LPWAVEFORMATEX lpwfex, bool bJustCheck)
Packit 47f805
{
Packit 47f805
    CAutoLock l(&m_lock);
Packit 47f805
Packit 47f805
    if (lpwfex->wFormatTag == WAVE_FORMAT_PCM)
Packit 47f805
    {
Packit 47f805
        if (lpwfex->nChannels == 1 || lpwfex->nChannels == 2)
Packit 47f805
        {
Packit 47f805
            if (lpwfex->nSamplesPerSec  == 48000 ||
Packit 47f805
                lpwfex->nSamplesPerSec  == 44100 ||
Packit 47f805
                lpwfex->nSamplesPerSec  == 32000 ||
Packit 47f805
                lpwfex->nSamplesPerSec  == 24000 ||
Packit 47f805
                lpwfex->nSamplesPerSec  == 22050 ||
Packit 47f805
                lpwfex->nSamplesPerSec  == 16000 ||
Packit 47f805
                lpwfex->nSamplesPerSec  == 12000 ||
Packit 47f805
                lpwfex->nSamplesPerSec  == 11025 ||
Packit 47f805
                lpwfex->nSamplesPerSec  ==  8000)
Packit 47f805
            {
Packit 47f805
                if (lpwfex->wBitsPerSample == 16)
Packit 47f805
                {
Packit 47f805
                    if (!bJustCheck)
Packit 47f805
                    {
Packit 47f805
                        memcpy(&m_wfex, lpwfex, sizeof(WAVEFORMATEX));
Packit 47f805
                        m_bInpuTypeSet = true;
Packit 47f805
                    }
Packit 47f805
Packit 47f805
                    return S_OK;
Packit 47f805
                }
Packit 47f805
            }
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
Packit 47f805
    if (!bJustCheck)
Packit 47f805
        m_bInpuTypeSet = false;
Packit 47f805
Packit 47f805
    return E_INVALIDARG;
Packit 47f805
}
Packit 47f805
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
// SetOutputType - try to initialize encoder with given output type
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
HRESULT CEncoder::SetOutputType(MPEG_ENCODER_CONFIG &mabsi)
Packit 47f805
{
Packit 47f805
    CAutoLock l(&m_lock);
Packit 47f805
Packit 47f805
    m_mabsi = mabsi;
Packit 47f805
    m_bOutpuTypeSet = true;
Packit 47f805
Packit 47f805
    return S_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
// SetDefaultOutputType - sets default MPEG audio properties according
Packit 47f805
// to input type
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
HRESULT CEncoder::SetDefaultOutputType(LPWAVEFORMATEX lpwfex)
Packit 47f805
{
Packit 47f805
    CAutoLock l(&m_lock);
Packit 47f805
Packit 47f805
    if(lpwfex->nChannels == 1 || m_mabsi.bForceMono)
Packit 47f805
        m_mabsi.ChMode = MONO;
Packit 47f805
Packit 47f805
    if((lpwfex->nSamplesPerSec < m_mabsi.dwSampleRate) || (lpwfex->nSamplesPerSec % m_mabsi.dwSampleRate != 0))
Packit 47f805
        m_mabsi.dwSampleRate = lpwfex->nSamplesPerSec;
Packit 47f805
Packit 47f805
    return S_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
// Init - initialized or reiniyialized encoder SDK with given input 
Packit 47f805
// and output settings
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
HRESULT CEncoder::Init()
Packit 47f805
{
Packit 47f805
    CAutoLock l(&m_lock);
Packit 47f805
Packit 47f805
    m_outOffset     = 0;
Packit 47f805
    m_outReadOffset = 0;
Packit 47f805
Packit 47f805
    m_bFinished     = FALSE;
Packit 47f805
Packit 47f805
    m_frameCount    = 0;
Packit 47f805
Packit 47f805
    if (!pgf)
Packit 47f805
    {
Packit 47f805
        if (!m_bInpuTypeSet || !m_bOutpuTypeSet)
Packit 47f805
            return E_UNEXPECTED;
Packit 47f805
Packit 47f805
        // Init Lame library
Packit 47f805
        // note: newer, safer interface which doesn't 
Packit 47f805
        // allow or require direct access to 'gf' struct is being written
Packit 47f805
        // see the file 'API' included with LAME.
Packit 47f805
        if (pgf = lame_init())
Packit 47f805
        {
Packit 47f805
            lame_set_num_channels(pgf, m_wfex.nChannels);
Packit 47f805
            lame_set_in_samplerate(pgf, m_wfex.nSamplesPerSec);
Packit 47f805
            lame_set_out_samplerate(pgf, m_mabsi.dwSampleRate);
Packit 47f805
            if ((lame_get_out_samplerate(pgf) >= 32000) && (m_mabsi.dwBitrate < 32))
Packit 47f805
                lame_set_brate(pgf, 32);
Packit 47f805
            else
Packit 47f805
                lame_set_brate(pgf, m_mabsi.dwBitrate);
Packit 47f805
            lame_set_VBR(pgf, m_mabsi.vmVariable);
Packit 47f805
            lame_set_VBR_min_bitrate_kbps(pgf, m_mabsi.dwVariableMin);
Packit 47f805
            lame_set_VBR_max_bitrate_kbps(pgf, m_mabsi.dwVariableMax);
Packit 47f805
Packit 47f805
            lame_set_copyright(pgf, m_mabsi.bCopyright);
Packit 47f805
            lame_set_original(pgf, m_mabsi.bOriginal);
Packit 47f805
            lame_set_error_protection(pgf, m_mabsi.bCRCProtect);
Packit 47f805
Packit 47f805
            lame_set_bWriteVbrTag(pgf, m_mabsi.dwXingTag);
Packit 47f805
            lame_set_strict_ISO(pgf, m_mabsi.dwStrictISO);
Packit 47f805
            lame_set_VBR_hard_min(pgf, m_mabsi.dwEnforceVBRmin);
Packit 47f805
Packit 47f805
            if (lame_get_num_channels(pgf) == 2 && !m_mabsi.bForceMono)
Packit 47f805
            {
Packit 47f805
                //int act_br = pgf->VBR ? pgf->VBR_min_bitrate_kbps + pgf->VBR_max_bitrate_kbps / 2 : pgf->brate;
Packit 47f805
Packit 47f805
                // Disabled. It's for user's consideration now
Packit 47f805
                //int rel = pgf->out_samplerate / (act_br + 1);
Packit 47f805
                //pgf->mode = rel < 200 ? m_mabsi.ChMode : JOINT_STEREO;
Packit 47f805
Packit 47f805
                lame_set_mode(pgf, m_mabsi.ChMode);
Packit 47f805
            }
Packit 47f805
            else
Packit 47f805
                lame_set_mode(pgf, MONO);
Packit 47f805
Packit 47f805
            if (lame_get_mode(pgf) == JOINT_STEREO)
Packit 47f805
                lame_set_force_ms(pgf, m_mabsi.dwForceMS);
Packit 47f805
            else
Packit 47f805
                lame_set_force_ms(pgf, 0);
Packit 47f805
Packit 47f805
//            pgf->mode_fixed = m_mabsi.dwModeFixed;
Packit 47f805
Packit 47f805
            if (m_mabsi.dwVoiceMode != 0)
Packit 47f805
            {
Packit 47f805
                lame_set_lowpassfreq(pgf,12000);
Packit 47f805
                ///pgf->VBR_max_bitrate_kbps = 160;
Packit 47f805
            }
Packit 47f805
Packit 47f805
            if (m_mabsi.dwKeepAllFreq != 0)
Packit 47f805
            {
Packit 47f805
                ///pgf->lowpassfreq = -1;
Packit 47f805
                ///pgf->highpassfreq = -1;
Packit 47f805
                /// not available anymore
Packit 47f805
            }
Packit 47f805
Packit 47f805
            lame_set_quality(pgf, m_mabsi.dwQuality);
Packit 47f805
            lame_set_VBR_q(pgf, m_mabsi.dwVBRq);
Packit 47f805
Packit 47f805
            lame_init_params(pgf);
Packit 47f805
Packit 47f805
            // encoder delay compensation
Packit 47f805
            {
Packit 47f805
                int const nch = lame_get_num_channels(pgf);
Packit 47f805
                short * start_padd = (short *)calloc(48, nch * sizeof(short));
Packit 47f805
Packit 47f805
				int out_bytes = 0;
Packit 47f805
Packit 47f805
                if (nch == 2)
Packit 47f805
                    out_bytes = lame_encode_buffer_interleaved(pgf, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE);
Packit 47f805
                else
Packit 47f805
                    out_bytes = lame_encode_buffer(pgf, start_padd, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE);
Packit 47f805
Packit 47f805
				if (out_bytes > 0)
Packit 47f805
					m_outOffset += out_bytes;
Packit 47f805
Packit 47f805
                free(start_padd);
Packit 47f805
            }
Packit 47f805
Packit 47f805
            return S_OK;
Packit 47f805
        }
Packit 47f805
Packit 47f805
        return E_FAIL;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    return S_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
// Close - closes encoder
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
HRESULT CEncoder::Close(IStream* pStream)
Packit 47f805
{
Packit 47f805
	CAutoLock l(&m_lock);
Packit 47f805
    if (pgf)
Packit 47f805
    {
Packit 47f805
		if(lame_get_bWriteVbrTag(pgf) && pStream)
Packit 47f805
		{
Packit 47f805
			updateLameTagFrame(pStream);
Packit 47f805
		}
Packit 47f805
Packit 47f805
        lame_close(pgf);
Packit 47f805
        pgf = NULL;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    return S_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
// Encode - encodes data placed on pdata and returns
Packit 47f805
// the number of processed bytes
Packit 47f805
//////////////////////////////////////////////////////////////////////
Packit 47f805
int CEncoder::Encode(const short * pdata, int data_size)
Packit 47f805
{
Packit 47f805
    CAutoLock l(&m_lock);
Packit 47f805
Packit 47f805
    if (!pgf || !m_outFrameBuf || !pdata || data_size < 0 || (data_size & (sizeof(short) - 1)))
Packit 47f805
        return -1;
Packit 47f805
Packit 47f805
    // some data left in the buffer, shift to start
Packit 47f805
    if (m_outReadOffset > 0)
Packit 47f805
    {
Packit 47f805
        if (m_outOffset > m_outReadOffset)
Packit 47f805
            memmove(m_outFrameBuf, m_outFrameBuf + m_outReadOffset, m_outOffset - m_outReadOffset);
Packit 47f805
Packit 47f805
        m_outOffset -= m_outReadOffset;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    m_outReadOffset = 0;
Packit 47f805
Packit 47f805
Packit 47f805
Packit 47f805
    m_bFinished = FALSE;
Packit 47f805
Packit 47f805
    int bytes_processed = 0;
Packit 47f805
    int const nch = lame_get_num_channels(pgf);
Packit 47f805
Packit 47f805
    while (1)
Packit 47f805
    {
Packit 47f805
        int nsamples = (data_size - bytes_processed) / (sizeof(short) * nch);
Packit 47f805
Packit 47f805
        if (nsamples <= 0)
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        if (nsamples > 1152)
Packit 47f805
            nsamples = 1152;
Packit 47f805
Packit 47f805
        if (m_outOffset >= OUT_BUFFER_MAX)
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        int out_bytes = 0;
Packit 47f805
Packit 47f805
        if (nch == 2)
Packit 47f805
            out_bytes = lame_encode_buffer_interleaved(
Packit 47f805
                                            pgf,
Packit 47f805
                                            (short *)(pdata + (bytes_processed / sizeof(short))),
Packit 47f805
                                            nsamples,
Packit 47f805
                                            m_outFrameBuf + m_outOffset,
Packit 47f805
                                            OUT_BUFFER_SIZE - m_outOffset);
Packit 47f805
        else
Packit 47f805
            out_bytes = lame_encode_buffer(
Packit 47f805
                                            pgf,
Packit 47f805
                                            pdata + (bytes_processed / sizeof(short)),
Packit 47f805
                                            pdata + (bytes_processed / sizeof(short)),
Packit 47f805
                                            nsamples,
Packit 47f805
                                            m_outFrameBuf + m_outOffset,
Packit 47f805
                                            OUT_BUFFER_SIZE - m_outOffset);
Packit 47f805
Packit 47f805
        if (out_bytes < 0)
Packit 47f805
            return -1;
Packit 47f805
Packit 47f805
        m_outOffset     += out_bytes;
Packit 47f805
        bytes_processed += nsamples * nch * sizeof(short);
Packit 47f805
    }
Packit 47f805
Packit 47f805
    return bytes_processed;
Packit 47f805
}
Packit 47f805
Packit 47f805
//
Packit 47f805
// Finsh - flush the buffered samples
Packit 47f805
//
Packit 47f805
HRESULT CEncoder::Finish()
Packit 47f805
{
Packit 47f805
    CAutoLock l(&m_lock);
Packit 47f805
Packit 47f805
    if (!pgf || !m_outFrameBuf || (m_outOffset >= OUT_BUFFER_MAX))
Packit 47f805
        return E_FAIL;
Packit 47f805
Packit 47f805
    m_outOffset += lame_encode_flush(pgf, m_outFrameBuf + m_outOffset, OUT_BUFFER_SIZE - m_outOffset);
Packit 47f805
Packit 47f805
    m_bFinished = TRUE;
Packit 47f805
Packit 47f805
    return S_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int getFrameLength(const unsigned char * pdata)
Packit 47f805
{
Packit 47f805
    if (!pdata || pdata[0] != 0xff || (pdata[1] & 0xe0) != 0xe0)
Packit 47f805
        return -1;
Packit 47f805
Packit 47f805
    const int sample_rate_tab[4][4] =
Packit 47f805
    {
Packit 47f805
        {11025,12000,8000,1},
Packit 47f805
        {1,1,1,1},
Packit 47f805
        {22050,24000,16000,1},
Packit 47f805
        {44100,48000,32000,1}
Packit 47f805
    };
Packit 47f805
Packit 47f805
#define MPEG_VERSION_RESERVED   1
Packit 47f805
#define MPEG_VERSION_1          3
Packit 47f805
Packit 47f805
#define LAYER_III               1
Packit 47f805
Packit 47f805
#define BITRATE_FREE            0
Packit 47f805
#define BITRATE_RESERVED        15
Packit 47f805
Packit 47f805
#define SRATE_RESERVED          3
Packit 47f805
Packit 47f805
#define EMPHASIS_RESERVED       2
Packit 47f805
Packit 47f805
    int version_id      = (pdata[1] & 0x18) >> 3;
Packit 47f805
    int layer           = (pdata[1] & 0x06) >> 1;
Packit 47f805
    int bitrate_id      = (pdata[2] & 0xF0) >> 4;
Packit 47f805
    int sample_rate_id  = (pdata[2] & 0x0C) >> 2;
Packit 47f805
    int padding         = (pdata[2] & 0x02) >> 1;
Packit 47f805
    int emphasis        =  pdata[3] & 0x03;
Packit 47f805
Packit 47f805
    if (version_id      != MPEG_VERSION_RESERVED &&
Packit 47f805
        layer           == LAYER_III &&
Packit 47f805
        bitrate_id      != BITRATE_FREE &&
Packit 47f805
        bitrate_id      != BITRATE_RESERVED &&
Packit 47f805
        sample_rate_id  != SRATE_RESERVED &&
Packit 47f805
        emphasis        != EMPHASIS_RESERVED)
Packit 47f805
    {
Packit 47f805
        int spf         = (version_id == MPEG_VERSION_1) ? 1152 : 576;
Packit 47f805
        int sample_rate = sample_rate_tab[version_id][sample_rate_id];
Packit 47f805
        int bitrate     = dwBitRateValue[version_id != MPEG_VERSION_1][bitrate_id - 1] * 1000;
Packit 47f805
Packit 47f805
        return (bitrate * spf) / (8 * sample_rate) + padding;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    return -1;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int CEncoder::GetFrame(const unsigned char ** pframe)
Packit 47f805
{
Packit 47f805
    if (!pgf || !m_outFrameBuf || !pframe)
Packit 47f805
        return -1;
Packit 47f805
Packit 47f805
	while ((m_outOffset - m_outReadOffset) > 4)
Packit 47f805
    {
Packit 47f805
        int frame_length = getFrameLength(m_outFrameBuf + m_outReadOffset);
Packit 47f805
Packit 47f805
        if (frame_length < 0)
Packit 47f805
        {
Packit 47f805
            m_outReadOffset++;
Packit 47f805
        }
Packit 47f805
        else if (frame_length <= (m_outOffset - m_outReadOffset))
Packit 47f805
        {
Packit 47f805
            *pframe = m_outFrameBuf + m_outReadOffset;
Packit 47f805
            m_outReadOffset += frame_length;
Packit 47f805
Packit 47f805
            m_frameCount++;
Packit 47f805
Packit 47f805
            // don't deliver the first and the last frames
Packit 47f805
            if (m_frameCount != 1 && !(m_bFinished && (m_outOffset - m_outReadOffset) < 5))
Packit 47f805
                return frame_length;
Packit 47f805
        }
Packit 47f805
        else
Packit 47f805
            break;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
////////////////////////////////////////////////////////////////////////////////
Packit 47f805
// Returns block of a mp3 file, witch size integer multiples of cbAlign
Packit 47f805
// or not aligned if finished
Packit 47f805
////////////////////////////////////////////////////////////////////////////////
Packit 47f805
int CEncoder::GetBlockAligned(const unsigned char ** pblock, int* piBufferSize, const long& cbAlign)
Packit 47f805
{
Packit 47f805
	ASSERT(piBufferSize);
Packit 47f805
    if (!pgf || !m_outFrameBuf || !pblock)
Packit 47f805
        return -1;
Packit 47f805
Packit 47f805
	int iBlockLen = m_outOffset - m_outReadOffset;
Packit 47f805
	ASSERT(iBlockLen >= 0);
Packit 47f805
	
Packit 47f805
	if(!m_bFinished)
Packit 47f805
	{
Packit 47f805
		if(cbAlign > 0)
Packit 47f805
			iBlockLen-=iBlockLen%cbAlign;
Packit 47f805
		*piBufferSize = iBlockLen;
Packit 47f805
	}
Packit 47f805
	else
Packit 47f805
	{
Packit 47f805
		if(cbAlign && iBlockLen%cbAlign)
Packit 47f805
		{
Packit 47f805
			*piBufferSize = iBlockLen + cbAlign - iBlockLen%cbAlign;
Packit 47f805
		}
Packit 47f805
		else
Packit 47f805
		{
Packit 47f805
			*piBufferSize = iBlockLen;
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
Packit 47f805
	if(iBlockLen) {
Packit 47f805
		*pblock = m_outFrameBuf + m_outReadOffset;
Packit 47f805
		m_outReadOffset+=iBlockLen;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	return iBlockLen;
Packit 47f805
}
Packit 47f805
Packit 47f805
HRESULT CEncoder::maybeSyncWord(IStream *pStream)
Packit 47f805
{
Packit 47f805
	HRESULT hr = S_OK;
Packit 47f805
    unsigned char mp3_frame_header[4];
Packit 47f805
	ULONG nbytes;
Packit 47f805
	if(FAILED(hr = pStream->Read(mp3_frame_header, sizeof(mp3_frame_header), &nbytes)))
Packit 47f805
		return hr;
Packit 47f805
	
Packit 47f805
    if ( nbytes != sizeof(mp3_frame_header) ) {
Packit 47f805
        return E_FAIL;
Packit 47f805
    }
Packit 47f805
    if ( mp3_frame_header[0] != 0xffu ) {
Packit 47f805
        return S_FALSE; /* doesn't look like a sync word */
Packit 47f805
    }
Packit 47f805
    if ( (mp3_frame_header[1] & 0xE0u) != 0xE0u ) {
Packit 47f805
		return S_FALSE; /* doesn't look like a sync word */
Packit 47f805
    }
Packit 47f805
    return S_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
HRESULT CEncoder::skipId3v2(IStream *pStream, size_t lametag_frame_size)
Packit 47f805
{
Packit 47f805
	HRESULT hr = S_OK;
Packit 47f805
    ULONG  nbytes;
Packit 47f805
    size_t  id3v2TagSize = 0;
Packit 47f805
    unsigned char id3v2Header[10];
Packit 47f805
	LARGE_INTEGER seekTo;
Packit 47f805
Packit 47f805
    /* seek to the beginning of the stream */
Packit 47f805
	seekTo.QuadPart = 0;
Packit 47f805
	if (FAILED(hr = pStream->Seek(seekTo,  STREAM_SEEK_SET, NULL))) {
Packit 47f805
        return hr;  /* not seekable, abort */
Packit 47f805
    }
Packit 47f805
    /* read 10 bytes in case there's an ID3 version 2 header here */
Packit 47f805
	hr = pStream->Read(id3v2Header, sizeof(id3v2Header), &nbytes);
Packit 47f805
    if (FAILED(hr))
Packit 47f805
		return hr;
Packit 47f805
	if(nbytes != sizeof(id3v2Header)) {
Packit 47f805
        return E_FAIL;  /* not readable, maybe opened Write-Only */
Packit 47f805
    }
Packit 47f805
    /* does the stream begin with the ID3 version 2 file identifier? */
Packit 47f805
    if (!strncmp((char *) id3v2Header, "ID3", 3)) {
Packit 47f805
        /* the tag size (minus the 10-byte header) is encoded into four
Packit 47f805
        * bytes where the most significant bit is clear in each byte
Packit 47f805
        */
Packit 47f805
        id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21)
Packit 47f805
            | ((id3v2Header[7] & 0x7f) << 14)
Packit 47f805
            | ((id3v2Header[8] & 0x7f) << 7)
Packit 47f805
            | (id3v2Header[9] & 0x7f))
Packit 47f805
            + sizeof id3v2Header;
Packit 47f805
    }
Packit 47f805
    /* Seek to the beginning of the audio stream */
Packit 47f805
	seekTo.QuadPart = id3v2TagSize;
Packit 47f805
	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
Packit 47f805
        return hr;
Packit 47f805
    }
Packit 47f805
    if (S_OK != (hr = maybeSyncWord(pStream))) {
Packit 47f805
		return SUCCEEDED(hr)?E_FAIL:hr;
Packit 47f805
    }
Packit 47f805
	seekTo.QuadPart = id3v2TagSize+lametag_frame_size;
Packit 47f805
	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
Packit 47f805
        return hr;
Packit 47f805
    }
Packit 47f805
    if (S_OK != (hr = maybeSyncWord(pStream))) {
Packit 47f805
        return SUCCEEDED(hr)?E_FAIL:hr;
Packit 47f805
    }
Packit 47f805
    /* OK, it seems we found our LAME-Tag/Xing frame again */
Packit 47f805
    /* Seek to the beginning of the audio stream */
Packit 47f805
	seekTo.QuadPart = id3v2TagSize;
Packit 47f805
	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
Packit 47f805
        return hr;
Packit 47f805
    }
Packit 47f805
    return S_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
// Updates VBR tag
Packit 47f805
HRESULT CEncoder::updateLameTagFrame(IStream* pStream)
Packit 47f805
{
Packit 47f805
	HRESULT hr = S_OK;
Packit 47f805
	size_t n = lame_get_lametag_frame( pgf, 0, 0 ); /* ask for bufer size */
Packit 47f805
Packit 47f805
    if ( n > 0 )
Packit 47f805
    {
Packit 47f805
        unsigned char* buffer = 0;
Packit 47f805
        ULONG m = n;
Packit 47f805
Packit 47f805
        if ( FAILED(hr = skipId3v2(pStream, n) )) 
Packit 47f805
        {
Packit 47f805
            /*DispErr( "Error updating LAME-tag frame:\n\n"
Packit 47f805
                     "can't locate old frame\n" );*/
Packit 47f805
            return hr;
Packit 47f805
        }
Packit 47f805
Packit 47f805
        buffer = (unsigned char*)malloc( n );
Packit 47f805
Packit 47f805
        if ( buffer == 0 ) 
Packit 47f805
        {
Packit 47f805
            /*DispErr( "Error updating LAME-tag frame:\n\n"
Packit 47f805
                     "can't allocate frame buffer\n" );*/
Packit 47f805
            return E_OUTOFMEMORY;
Packit 47f805
        }
Packit 47f805
Packit 47f805
        /* Put it all to disk again */
Packit 47f805
        n = lame_get_lametag_frame( pgf, buffer, n );
Packit 47f805
        if ( n > 0 ) 
Packit 47f805
        {
Packit 47f805
			hr = pStream->Write(buffer, n, &m);        
Packit 47f805
        }
Packit 47f805
        free( buffer );
Packit 47f805
Packit 47f805
        if ( m != n ) 
Packit 47f805
        {
Packit 47f805
            /*DispErr( "Error updating LAME-tag frame:\n\n"
Packit 47f805
                     "couldn't write frame into file\n" );*/
Packit 47f805
			return E_FAIL;
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
    return hr;
Packit 47f805
}