|
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 |
}
|