1159b3361Sopenharmony_ci/*
2159b3361Sopenharmony_ci *  LAME MP3 encoder for DirectShow
3159b3361Sopenharmony_ci *  LAME encoder wrapper
4159b3361Sopenharmony_ci *
5159b3361Sopenharmony_ci *  Copyright (c) 2000-2005 Marie Orlova, Peter Gubanov, Vitaly Ivanov, Elecard Ltd.
6159b3361Sopenharmony_ci *
7159b3361Sopenharmony_ci * This library is free software; you can redistribute it and/or
8159b3361Sopenharmony_ci * modify it under the terms of the GNU Library General Public
9159b3361Sopenharmony_ci * License as published by the Free Software Foundation; either
10159b3361Sopenharmony_ci * version 2 of the License, or (at your option) any later version.
11159b3361Sopenharmony_ci *
12159b3361Sopenharmony_ci * This library is distributed in the hope that it will be useful,
13159b3361Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14159b3361Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15159b3361Sopenharmony_ci * Library General Public License for more details.
16159b3361Sopenharmony_ci *
17159b3361Sopenharmony_ci * You should have received a copy of the GNU Library General Public
18159b3361Sopenharmony_ci * License along with this library; if not, write to the
19159b3361Sopenharmony_ci * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20159b3361Sopenharmony_ci * Boston, MA 02111-1307, USA.
21159b3361Sopenharmony_ci */
22159b3361Sopenharmony_ci
23159b3361Sopenharmony_ci#include <streams.h>
24159b3361Sopenharmony_ci#include "Encoder.h"
25159b3361Sopenharmony_ci
26159b3361Sopenharmony_ci
27159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
28159b3361Sopenharmony_ci// Construction/Destruction
29159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
30159b3361Sopenharmony_ciCEncoder::CEncoder() :
31159b3361Sopenharmony_ci    pgf(NULL),
32159b3361Sopenharmony_ci    m_bInpuTypeSet(FALSE),
33159b3361Sopenharmony_ci    m_bOutpuTypeSet(FALSE),
34159b3361Sopenharmony_ci    m_bFinished(FALSE),
35159b3361Sopenharmony_ci    m_frameCount(0),
36159b3361Sopenharmony_ci    m_outOffset(0),
37159b3361Sopenharmony_ci    m_outReadOffset(0)
38159b3361Sopenharmony_ci{
39159b3361Sopenharmony_ci    m_outFrameBuf = new unsigned char[OUT_BUFFER_SIZE];
40159b3361Sopenharmony_ci}
41159b3361Sopenharmony_ci
42159b3361Sopenharmony_ciCEncoder::~CEncoder()
43159b3361Sopenharmony_ci{
44159b3361Sopenharmony_ci    Close(NULL);
45159b3361Sopenharmony_ci
46159b3361Sopenharmony_ci    if (m_outFrameBuf)
47159b3361Sopenharmony_ci        delete [] m_outFrameBuf;
48159b3361Sopenharmony_ci}
49159b3361Sopenharmony_ci
50159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
51159b3361Sopenharmony_ci// SetInputType - check if given input type is supported
52159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
53159b3361Sopenharmony_ciHRESULT CEncoder::SetInputType(LPWAVEFORMATEX lpwfex, bool bJustCheck)
54159b3361Sopenharmony_ci{
55159b3361Sopenharmony_ci    CAutoLock l(&m_lock);
56159b3361Sopenharmony_ci
57159b3361Sopenharmony_ci    if (lpwfex->wFormatTag == WAVE_FORMAT_PCM)
58159b3361Sopenharmony_ci    {
59159b3361Sopenharmony_ci        if (lpwfex->nChannels == 1 || lpwfex->nChannels == 2)
60159b3361Sopenharmony_ci        {
61159b3361Sopenharmony_ci            if (lpwfex->nSamplesPerSec  == 48000 ||
62159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  == 44100 ||
63159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  == 32000 ||
64159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  == 24000 ||
65159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  == 22050 ||
66159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  == 16000 ||
67159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  == 12000 ||
68159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  == 11025 ||
69159b3361Sopenharmony_ci                lpwfex->nSamplesPerSec  ==  8000)
70159b3361Sopenharmony_ci            {
71159b3361Sopenharmony_ci                if (lpwfex->wBitsPerSample == 16)
72159b3361Sopenharmony_ci                {
73159b3361Sopenharmony_ci                    if (!bJustCheck)
74159b3361Sopenharmony_ci                    {
75159b3361Sopenharmony_ci                        memcpy(&m_wfex, lpwfex, sizeof(WAVEFORMATEX));
76159b3361Sopenharmony_ci                        m_bInpuTypeSet = true;
77159b3361Sopenharmony_ci                    }
78159b3361Sopenharmony_ci
79159b3361Sopenharmony_ci                    return S_OK;
80159b3361Sopenharmony_ci                }
81159b3361Sopenharmony_ci            }
82159b3361Sopenharmony_ci        }
83159b3361Sopenharmony_ci    }
84159b3361Sopenharmony_ci
85159b3361Sopenharmony_ci    if (!bJustCheck)
86159b3361Sopenharmony_ci        m_bInpuTypeSet = false;
87159b3361Sopenharmony_ci
88159b3361Sopenharmony_ci    return E_INVALIDARG;
89159b3361Sopenharmony_ci}
90159b3361Sopenharmony_ci
91159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
92159b3361Sopenharmony_ci// SetOutputType - try to initialize encoder with given output type
93159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
94159b3361Sopenharmony_ciHRESULT CEncoder::SetOutputType(MPEG_ENCODER_CONFIG &mabsi)
95159b3361Sopenharmony_ci{
96159b3361Sopenharmony_ci    CAutoLock l(&m_lock);
97159b3361Sopenharmony_ci
98159b3361Sopenharmony_ci    m_mabsi = mabsi;
99159b3361Sopenharmony_ci    m_bOutpuTypeSet = true;
100159b3361Sopenharmony_ci
101159b3361Sopenharmony_ci    return S_OK;
102159b3361Sopenharmony_ci}
103159b3361Sopenharmony_ci
104159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
105159b3361Sopenharmony_ci// SetDefaultOutputType - sets default MPEG audio properties according
106159b3361Sopenharmony_ci// to input type
107159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
108159b3361Sopenharmony_ciHRESULT CEncoder::SetDefaultOutputType(LPWAVEFORMATEX lpwfex)
109159b3361Sopenharmony_ci{
110159b3361Sopenharmony_ci    CAutoLock l(&m_lock);
111159b3361Sopenharmony_ci
112159b3361Sopenharmony_ci    if(lpwfex->nChannels == 1 || m_mabsi.bForceMono)
113159b3361Sopenharmony_ci        m_mabsi.ChMode = MONO;
114159b3361Sopenharmony_ci
115159b3361Sopenharmony_ci    if((lpwfex->nSamplesPerSec < m_mabsi.dwSampleRate) || (lpwfex->nSamplesPerSec % m_mabsi.dwSampleRate != 0))
116159b3361Sopenharmony_ci        m_mabsi.dwSampleRate = lpwfex->nSamplesPerSec;
117159b3361Sopenharmony_ci
118159b3361Sopenharmony_ci    return S_OK;
119159b3361Sopenharmony_ci}
120159b3361Sopenharmony_ci
121159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
122159b3361Sopenharmony_ci// Init - initialized or reiniyialized encoder SDK with given input
123159b3361Sopenharmony_ci// and output settings
124159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
125159b3361Sopenharmony_ciHRESULT CEncoder::Init()
126159b3361Sopenharmony_ci{
127159b3361Sopenharmony_ci    CAutoLock l(&m_lock);
128159b3361Sopenharmony_ci
129159b3361Sopenharmony_ci    m_outOffset     = 0;
130159b3361Sopenharmony_ci    m_outReadOffset = 0;
131159b3361Sopenharmony_ci
132159b3361Sopenharmony_ci    m_bFinished     = FALSE;
133159b3361Sopenharmony_ci
134159b3361Sopenharmony_ci    m_frameCount    = 0;
135159b3361Sopenharmony_ci
136159b3361Sopenharmony_ci    if (!pgf)
137159b3361Sopenharmony_ci    {
138159b3361Sopenharmony_ci        if (!m_bInpuTypeSet || !m_bOutpuTypeSet)
139159b3361Sopenharmony_ci            return E_UNEXPECTED;
140159b3361Sopenharmony_ci
141159b3361Sopenharmony_ci        // Init Lame library
142159b3361Sopenharmony_ci        // note: newer, safer interface which doesn't
143159b3361Sopenharmony_ci        // allow or require direct access to 'gf' struct is being written
144159b3361Sopenharmony_ci        // see the file 'API' included with LAME.
145159b3361Sopenharmony_ci        if (pgf = lame_init())
146159b3361Sopenharmony_ci        {
147159b3361Sopenharmony_ci            lame_set_num_channels(pgf, m_wfex.nChannels);
148159b3361Sopenharmony_ci            lame_set_in_samplerate(pgf, m_wfex.nSamplesPerSec);
149159b3361Sopenharmony_ci            lame_set_out_samplerate(pgf, m_mabsi.dwSampleRate);
150159b3361Sopenharmony_ci            if ((lame_get_out_samplerate(pgf) >= 32000) && (m_mabsi.dwBitrate < 32))
151159b3361Sopenharmony_ci                lame_set_brate(pgf, 32);
152159b3361Sopenharmony_ci            else
153159b3361Sopenharmony_ci                lame_set_brate(pgf, m_mabsi.dwBitrate);
154159b3361Sopenharmony_ci            lame_set_VBR(pgf, m_mabsi.vmVariable);
155159b3361Sopenharmony_ci            lame_set_VBR_min_bitrate_kbps(pgf, m_mabsi.dwVariableMin);
156159b3361Sopenharmony_ci            lame_set_VBR_max_bitrate_kbps(pgf, m_mabsi.dwVariableMax);
157159b3361Sopenharmony_ci
158159b3361Sopenharmony_ci            lame_set_copyright(pgf, m_mabsi.bCopyright);
159159b3361Sopenharmony_ci            lame_set_original(pgf, m_mabsi.bOriginal);
160159b3361Sopenharmony_ci            lame_set_error_protection(pgf, m_mabsi.bCRCProtect);
161159b3361Sopenharmony_ci
162159b3361Sopenharmony_ci            lame_set_bWriteVbrTag(pgf, m_mabsi.dwXingTag);
163159b3361Sopenharmony_ci            lame_set_strict_ISO(pgf, m_mabsi.dwStrictISO);
164159b3361Sopenharmony_ci            lame_set_VBR_hard_min(pgf, m_mabsi.dwEnforceVBRmin);
165159b3361Sopenharmony_ci
166159b3361Sopenharmony_ci            if (lame_get_num_channels(pgf) == 2 && !m_mabsi.bForceMono)
167159b3361Sopenharmony_ci            {
168159b3361Sopenharmony_ci                //int act_br = pgf->VBR ? pgf->VBR_min_bitrate_kbps + pgf->VBR_max_bitrate_kbps / 2 : pgf->brate;
169159b3361Sopenharmony_ci
170159b3361Sopenharmony_ci                // Disabled. It's for user's consideration now
171159b3361Sopenharmony_ci                //int rel = pgf->out_samplerate / (act_br + 1);
172159b3361Sopenharmony_ci                //pgf->mode = rel < 200 ? m_mabsi.ChMode : JOINT_STEREO;
173159b3361Sopenharmony_ci
174159b3361Sopenharmony_ci                lame_set_mode(pgf, m_mabsi.ChMode);
175159b3361Sopenharmony_ci            }
176159b3361Sopenharmony_ci            else
177159b3361Sopenharmony_ci                lame_set_mode(pgf, MONO);
178159b3361Sopenharmony_ci
179159b3361Sopenharmony_ci            if (lame_get_mode(pgf) == JOINT_STEREO)
180159b3361Sopenharmony_ci                lame_set_force_ms(pgf, m_mabsi.dwForceMS);
181159b3361Sopenharmony_ci            else
182159b3361Sopenharmony_ci                lame_set_force_ms(pgf, 0);
183159b3361Sopenharmony_ci
184159b3361Sopenharmony_ci//            pgf->mode_fixed = m_mabsi.dwModeFixed;
185159b3361Sopenharmony_ci
186159b3361Sopenharmony_ci            if (m_mabsi.dwVoiceMode != 0)
187159b3361Sopenharmony_ci            {
188159b3361Sopenharmony_ci                lame_set_lowpassfreq(pgf,12000);
189159b3361Sopenharmony_ci                ///pgf->VBR_max_bitrate_kbps = 160;
190159b3361Sopenharmony_ci            }
191159b3361Sopenharmony_ci
192159b3361Sopenharmony_ci            if (m_mabsi.dwKeepAllFreq != 0)
193159b3361Sopenharmony_ci            {
194159b3361Sopenharmony_ci                ///pgf->lowpassfreq = -1;
195159b3361Sopenharmony_ci                ///pgf->highpassfreq = -1;
196159b3361Sopenharmony_ci                /// not available anymore
197159b3361Sopenharmony_ci            }
198159b3361Sopenharmony_ci
199159b3361Sopenharmony_ci            lame_set_quality(pgf, m_mabsi.dwQuality);
200159b3361Sopenharmony_ci            lame_set_VBR_q(pgf, m_mabsi.dwVBRq);
201159b3361Sopenharmony_ci
202159b3361Sopenharmony_ci            lame_init_params(pgf);
203159b3361Sopenharmony_ci
204159b3361Sopenharmony_ci            // encoder delay compensation
205159b3361Sopenharmony_ci            {
206159b3361Sopenharmony_ci                int const nch = lame_get_num_channels(pgf);
207159b3361Sopenharmony_ci                short * start_padd = (short *)calloc(48, nch * sizeof(short));
208159b3361Sopenharmony_ci
209159b3361Sopenharmony_ci				int out_bytes = 0;
210159b3361Sopenharmony_ci
211159b3361Sopenharmony_ci                if (nch == 2)
212159b3361Sopenharmony_ci                    out_bytes = lame_encode_buffer_interleaved(pgf, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE);
213159b3361Sopenharmony_ci                else
214159b3361Sopenharmony_ci                    out_bytes = lame_encode_buffer(pgf, start_padd, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE);
215159b3361Sopenharmony_ci
216159b3361Sopenharmony_ci				if (out_bytes > 0)
217159b3361Sopenharmony_ci					m_outOffset += out_bytes;
218159b3361Sopenharmony_ci
219159b3361Sopenharmony_ci                free(start_padd);
220159b3361Sopenharmony_ci            }
221159b3361Sopenharmony_ci
222159b3361Sopenharmony_ci            return S_OK;
223159b3361Sopenharmony_ci        }
224159b3361Sopenharmony_ci
225159b3361Sopenharmony_ci        return E_FAIL;
226159b3361Sopenharmony_ci    }
227159b3361Sopenharmony_ci
228159b3361Sopenharmony_ci    return S_OK;
229159b3361Sopenharmony_ci}
230159b3361Sopenharmony_ci
231159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
232159b3361Sopenharmony_ci// Close - closes encoder
233159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
234159b3361Sopenharmony_ciHRESULT CEncoder::Close(IStream* pStream)
235159b3361Sopenharmony_ci{
236159b3361Sopenharmony_ci	CAutoLock l(&m_lock);
237159b3361Sopenharmony_ci    if (pgf)
238159b3361Sopenharmony_ci    {
239159b3361Sopenharmony_ci		if(lame_get_bWriteVbrTag(pgf) && pStream)
240159b3361Sopenharmony_ci		{
241159b3361Sopenharmony_ci			updateLameTagFrame(pStream);
242159b3361Sopenharmony_ci		}
243159b3361Sopenharmony_ci
244159b3361Sopenharmony_ci        lame_close(pgf);
245159b3361Sopenharmony_ci        pgf = NULL;
246159b3361Sopenharmony_ci    }
247159b3361Sopenharmony_ci
248159b3361Sopenharmony_ci    return S_OK;
249159b3361Sopenharmony_ci}
250159b3361Sopenharmony_ci
251159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
252159b3361Sopenharmony_ci// Encode - encodes data placed on pdata and returns
253159b3361Sopenharmony_ci// the number of processed bytes
254159b3361Sopenharmony_ci//////////////////////////////////////////////////////////////////////
255159b3361Sopenharmony_ciint CEncoder::Encode(const short * pdata, int data_size)
256159b3361Sopenharmony_ci{
257159b3361Sopenharmony_ci    CAutoLock l(&m_lock);
258159b3361Sopenharmony_ci
259159b3361Sopenharmony_ci    if (!pgf || !m_outFrameBuf || !pdata || data_size < 0 || (data_size & (sizeof(short) - 1)))
260159b3361Sopenharmony_ci        return -1;
261159b3361Sopenharmony_ci
262159b3361Sopenharmony_ci    // some data left in the buffer, shift to start
263159b3361Sopenharmony_ci    if (m_outReadOffset > 0)
264159b3361Sopenharmony_ci    {
265159b3361Sopenharmony_ci        if (m_outOffset > m_outReadOffset)
266159b3361Sopenharmony_ci            memmove(m_outFrameBuf, m_outFrameBuf + m_outReadOffset, m_outOffset - m_outReadOffset);
267159b3361Sopenharmony_ci
268159b3361Sopenharmony_ci        m_outOffset -= m_outReadOffset;
269159b3361Sopenharmony_ci    }
270159b3361Sopenharmony_ci
271159b3361Sopenharmony_ci    m_outReadOffset = 0;
272159b3361Sopenharmony_ci
273159b3361Sopenharmony_ci
274159b3361Sopenharmony_ci
275159b3361Sopenharmony_ci    m_bFinished = FALSE;
276159b3361Sopenharmony_ci
277159b3361Sopenharmony_ci    int bytes_processed = 0;
278159b3361Sopenharmony_ci    int const nch = lame_get_num_channels(pgf);
279159b3361Sopenharmony_ci
280159b3361Sopenharmony_ci    while (1)
281159b3361Sopenharmony_ci    {
282159b3361Sopenharmony_ci        int nsamples = (data_size - bytes_processed) / (sizeof(short) * nch);
283159b3361Sopenharmony_ci
284159b3361Sopenharmony_ci        if (nsamples <= 0)
285159b3361Sopenharmony_ci            break;
286159b3361Sopenharmony_ci
287159b3361Sopenharmony_ci        if (nsamples > 1152)
288159b3361Sopenharmony_ci            nsamples = 1152;
289159b3361Sopenharmony_ci
290159b3361Sopenharmony_ci        if (m_outOffset >= OUT_BUFFER_MAX)
291159b3361Sopenharmony_ci            break;
292159b3361Sopenharmony_ci
293159b3361Sopenharmony_ci        int out_bytes = 0;
294159b3361Sopenharmony_ci
295159b3361Sopenharmony_ci        if (nch == 2)
296159b3361Sopenharmony_ci            out_bytes = lame_encode_buffer_interleaved(
297159b3361Sopenharmony_ci                                            pgf,
298159b3361Sopenharmony_ci                                            (short *)(pdata + (bytes_processed / sizeof(short))),
299159b3361Sopenharmony_ci                                            nsamples,
300159b3361Sopenharmony_ci                                            m_outFrameBuf + m_outOffset,
301159b3361Sopenharmony_ci                                            OUT_BUFFER_SIZE - m_outOffset);
302159b3361Sopenharmony_ci        else
303159b3361Sopenharmony_ci            out_bytes = lame_encode_buffer(
304159b3361Sopenharmony_ci                                            pgf,
305159b3361Sopenharmony_ci                                            pdata + (bytes_processed / sizeof(short)),
306159b3361Sopenharmony_ci                                            pdata + (bytes_processed / sizeof(short)),
307159b3361Sopenharmony_ci                                            nsamples,
308159b3361Sopenharmony_ci                                            m_outFrameBuf + m_outOffset,
309159b3361Sopenharmony_ci                                            OUT_BUFFER_SIZE - m_outOffset);
310159b3361Sopenharmony_ci
311159b3361Sopenharmony_ci        if (out_bytes < 0)
312159b3361Sopenharmony_ci            return -1;
313159b3361Sopenharmony_ci
314159b3361Sopenharmony_ci        m_outOffset     += out_bytes;
315159b3361Sopenharmony_ci        bytes_processed += nsamples * nch * sizeof(short);
316159b3361Sopenharmony_ci    }
317159b3361Sopenharmony_ci
318159b3361Sopenharmony_ci    return bytes_processed;
319159b3361Sopenharmony_ci}
320159b3361Sopenharmony_ci
321159b3361Sopenharmony_ci//
322159b3361Sopenharmony_ci// Finsh - flush the buffered samples
323159b3361Sopenharmony_ci//
324159b3361Sopenharmony_ciHRESULT CEncoder::Finish()
325159b3361Sopenharmony_ci{
326159b3361Sopenharmony_ci    CAutoLock l(&m_lock);
327159b3361Sopenharmony_ci
328159b3361Sopenharmony_ci    if (!pgf || !m_outFrameBuf || (m_outOffset >= OUT_BUFFER_MAX))
329159b3361Sopenharmony_ci        return E_FAIL;
330159b3361Sopenharmony_ci
331159b3361Sopenharmony_ci    m_outOffset += lame_encode_flush(pgf, m_outFrameBuf + m_outOffset, OUT_BUFFER_SIZE - m_outOffset);
332159b3361Sopenharmony_ci
333159b3361Sopenharmony_ci    m_bFinished = TRUE;
334159b3361Sopenharmony_ci
335159b3361Sopenharmony_ci    return S_OK;
336159b3361Sopenharmony_ci}
337159b3361Sopenharmony_ci
338159b3361Sopenharmony_ci
339159b3361Sopenharmony_ciint getFrameLength(const unsigned char * pdata)
340159b3361Sopenharmony_ci{
341159b3361Sopenharmony_ci    if (!pdata || pdata[0] != 0xff || (pdata[1] & 0xe0) != 0xe0)
342159b3361Sopenharmony_ci        return -1;
343159b3361Sopenharmony_ci
344159b3361Sopenharmony_ci    const int sample_rate_tab[4][4] =
345159b3361Sopenharmony_ci    {
346159b3361Sopenharmony_ci        {11025,12000,8000,1},
347159b3361Sopenharmony_ci        {1,1,1,1},
348159b3361Sopenharmony_ci        {22050,24000,16000,1},
349159b3361Sopenharmony_ci        {44100,48000,32000,1}
350159b3361Sopenharmony_ci    };
351159b3361Sopenharmony_ci
352159b3361Sopenharmony_ci#define MPEG_VERSION_RESERVED   1
353159b3361Sopenharmony_ci#define MPEG_VERSION_1          3
354159b3361Sopenharmony_ci
355159b3361Sopenharmony_ci#define LAYER_III               1
356159b3361Sopenharmony_ci
357159b3361Sopenharmony_ci#define BITRATE_FREE            0
358159b3361Sopenharmony_ci#define BITRATE_RESERVED        15
359159b3361Sopenharmony_ci
360159b3361Sopenharmony_ci#define SRATE_RESERVED          3
361159b3361Sopenharmony_ci
362159b3361Sopenharmony_ci#define EMPHASIS_RESERVED       2
363159b3361Sopenharmony_ci
364159b3361Sopenharmony_ci    int version_id      = (pdata[1] & 0x18) >> 3;
365159b3361Sopenharmony_ci    int layer           = (pdata[1] & 0x06) >> 1;
366159b3361Sopenharmony_ci    int bitrate_id      = (pdata[2] & 0xF0) >> 4;
367159b3361Sopenharmony_ci    int sample_rate_id  = (pdata[2] & 0x0C) >> 2;
368159b3361Sopenharmony_ci    int padding         = (pdata[2] & 0x02) >> 1;
369159b3361Sopenharmony_ci    int emphasis        =  pdata[3] & 0x03;
370159b3361Sopenharmony_ci
371159b3361Sopenharmony_ci    if (version_id      != MPEG_VERSION_RESERVED &&
372159b3361Sopenharmony_ci        layer           == LAYER_III &&
373159b3361Sopenharmony_ci        bitrate_id      != BITRATE_FREE &&
374159b3361Sopenharmony_ci        bitrate_id      != BITRATE_RESERVED &&
375159b3361Sopenharmony_ci        sample_rate_id  != SRATE_RESERVED &&
376159b3361Sopenharmony_ci        emphasis        != EMPHASIS_RESERVED)
377159b3361Sopenharmony_ci    {
378159b3361Sopenharmony_ci        int spf         = (version_id == MPEG_VERSION_1) ? 1152 : 576;
379159b3361Sopenharmony_ci        int sample_rate = sample_rate_tab[version_id][sample_rate_id];
380159b3361Sopenharmony_ci        int bitrate     = dwBitRateValue[version_id != MPEG_VERSION_1][bitrate_id - 1] * 1000;
381159b3361Sopenharmony_ci
382159b3361Sopenharmony_ci        return (bitrate * spf) / (8 * sample_rate) + padding;
383159b3361Sopenharmony_ci    }
384159b3361Sopenharmony_ci
385159b3361Sopenharmony_ci    return -1;
386159b3361Sopenharmony_ci}
387159b3361Sopenharmony_ci
388159b3361Sopenharmony_ci
389159b3361Sopenharmony_ciint CEncoder::GetFrame(const unsigned char ** pframe)
390159b3361Sopenharmony_ci{
391159b3361Sopenharmony_ci    if (!pgf || !m_outFrameBuf || !pframe)
392159b3361Sopenharmony_ci        return -1;
393159b3361Sopenharmony_ci
394159b3361Sopenharmony_ci	while ((m_outOffset - m_outReadOffset) > 4)
395159b3361Sopenharmony_ci    {
396159b3361Sopenharmony_ci        int frame_length = getFrameLength(m_outFrameBuf + m_outReadOffset);
397159b3361Sopenharmony_ci
398159b3361Sopenharmony_ci        if (frame_length < 0)
399159b3361Sopenharmony_ci        {
400159b3361Sopenharmony_ci            m_outReadOffset++;
401159b3361Sopenharmony_ci        }
402159b3361Sopenharmony_ci        else if (frame_length <= (m_outOffset - m_outReadOffset))
403159b3361Sopenharmony_ci        {
404159b3361Sopenharmony_ci            *pframe = m_outFrameBuf + m_outReadOffset;
405159b3361Sopenharmony_ci            m_outReadOffset += frame_length;
406159b3361Sopenharmony_ci
407159b3361Sopenharmony_ci            m_frameCount++;
408159b3361Sopenharmony_ci
409159b3361Sopenharmony_ci            // don't deliver the first and the last frames
410159b3361Sopenharmony_ci            if (m_frameCount != 1 && !(m_bFinished && (m_outOffset - m_outReadOffset) < 5))
411159b3361Sopenharmony_ci                return frame_length;
412159b3361Sopenharmony_ci        }
413159b3361Sopenharmony_ci        else
414159b3361Sopenharmony_ci            break;
415159b3361Sopenharmony_ci    }
416159b3361Sopenharmony_ci
417159b3361Sopenharmony_ci    return 0;
418159b3361Sopenharmony_ci}
419159b3361Sopenharmony_ci
420159b3361Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
421159b3361Sopenharmony_ci// Returns block of a mp3 file, witch size integer multiples of cbAlign
422159b3361Sopenharmony_ci// or not aligned if finished
423159b3361Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
424159b3361Sopenharmony_ciint CEncoder::GetBlockAligned(const unsigned char ** pblock, int* piBufferSize, const long& cbAlign)
425159b3361Sopenharmony_ci{
426159b3361Sopenharmony_ci	ASSERT(piBufferSize);
427159b3361Sopenharmony_ci    if (!pgf || !m_outFrameBuf || !pblock)
428159b3361Sopenharmony_ci        return -1;
429159b3361Sopenharmony_ci
430159b3361Sopenharmony_ci	int iBlockLen = m_outOffset - m_outReadOffset;
431159b3361Sopenharmony_ci	ASSERT(iBlockLen >= 0);
432159b3361Sopenharmony_ci
433159b3361Sopenharmony_ci	if(!m_bFinished)
434159b3361Sopenharmony_ci	{
435159b3361Sopenharmony_ci		if(cbAlign > 0)
436159b3361Sopenharmony_ci			iBlockLen-=iBlockLen%cbAlign;
437159b3361Sopenharmony_ci		*piBufferSize = iBlockLen;
438159b3361Sopenharmony_ci	}
439159b3361Sopenharmony_ci	else
440159b3361Sopenharmony_ci	{
441159b3361Sopenharmony_ci		if(cbAlign && iBlockLen%cbAlign)
442159b3361Sopenharmony_ci		{
443159b3361Sopenharmony_ci			*piBufferSize = iBlockLen + cbAlign - iBlockLen%cbAlign;
444159b3361Sopenharmony_ci		}
445159b3361Sopenharmony_ci		else
446159b3361Sopenharmony_ci		{
447159b3361Sopenharmony_ci			*piBufferSize = iBlockLen;
448159b3361Sopenharmony_ci		}
449159b3361Sopenharmony_ci	}
450159b3361Sopenharmony_ci
451159b3361Sopenharmony_ci	if(iBlockLen) {
452159b3361Sopenharmony_ci		*pblock = m_outFrameBuf + m_outReadOffset;
453159b3361Sopenharmony_ci		m_outReadOffset+=iBlockLen;
454159b3361Sopenharmony_ci	}
455159b3361Sopenharmony_ci
456159b3361Sopenharmony_ci	return iBlockLen;
457159b3361Sopenharmony_ci}
458159b3361Sopenharmony_ci
459159b3361Sopenharmony_ciHRESULT CEncoder::maybeSyncWord(IStream *pStream)
460159b3361Sopenharmony_ci{
461159b3361Sopenharmony_ci	HRESULT hr = S_OK;
462159b3361Sopenharmony_ci    unsigned char mp3_frame_header[4];
463159b3361Sopenharmony_ci	ULONG nbytes;
464159b3361Sopenharmony_ci	if(FAILED(hr = pStream->Read(mp3_frame_header, sizeof(mp3_frame_header), &nbytes)))
465159b3361Sopenharmony_ci		return hr;
466159b3361Sopenharmony_ci
467159b3361Sopenharmony_ci    if ( nbytes != sizeof(mp3_frame_header) ) {
468159b3361Sopenharmony_ci        return E_FAIL;
469159b3361Sopenharmony_ci    }
470159b3361Sopenharmony_ci    if ( mp3_frame_header[0] != 0xffu ) {
471159b3361Sopenharmony_ci        return S_FALSE; /* doesn't look like a sync word */
472159b3361Sopenharmony_ci    }
473159b3361Sopenharmony_ci    if ( (mp3_frame_header[1] & 0xE0u) != 0xE0u ) {
474159b3361Sopenharmony_ci		return S_FALSE; /* doesn't look like a sync word */
475159b3361Sopenharmony_ci    }
476159b3361Sopenharmony_ci    return S_OK;
477159b3361Sopenharmony_ci}
478159b3361Sopenharmony_ci
479159b3361Sopenharmony_ciHRESULT CEncoder::skipId3v2(IStream *pStream, size_t lametag_frame_size)
480159b3361Sopenharmony_ci{
481159b3361Sopenharmony_ci	HRESULT hr = S_OK;
482159b3361Sopenharmony_ci    ULONG  nbytes;
483159b3361Sopenharmony_ci    size_t  id3v2TagSize = 0;
484159b3361Sopenharmony_ci    unsigned char id3v2Header[10];
485159b3361Sopenharmony_ci	LARGE_INTEGER seekTo;
486159b3361Sopenharmony_ci
487159b3361Sopenharmony_ci    /* seek to the beginning of the stream */
488159b3361Sopenharmony_ci	seekTo.QuadPart = 0;
489159b3361Sopenharmony_ci	if (FAILED(hr = pStream->Seek(seekTo,  STREAM_SEEK_SET, NULL))) {
490159b3361Sopenharmony_ci        return hr;  /* not seekable, abort */
491159b3361Sopenharmony_ci    }
492159b3361Sopenharmony_ci    /* read 10 bytes in case there's an ID3 version 2 header here */
493159b3361Sopenharmony_ci	hr = pStream->Read(id3v2Header, sizeof(id3v2Header), &nbytes);
494159b3361Sopenharmony_ci    if (FAILED(hr))
495159b3361Sopenharmony_ci		return hr;
496159b3361Sopenharmony_ci	if(nbytes != sizeof(id3v2Header)) {
497159b3361Sopenharmony_ci        return E_FAIL;  /* not readable, maybe opened Write-Only */
498159b3361Sopenharmony_ci    }
499159b3361Sopenharmony_ci    /* does the stream begin with the ID3 version 2 file identifier? */
500159b3361Sopenharmony_ci    if (!strncmp((char *) id3v2Header, "ID3", 3)) {
501159b3361Sopenharmony_ci        /* the tag size (minus the 10-byte header) is encoded into four
502159b3361Sopenharmony_ci        * bytes where the most significant bit is clear in each byte
503159b3361Sopenharmony_ci        */
504159b3361Sopenharmony_ci        id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21)
505159b3361Sopenharmony_ci            | ((id3v2Header[7] & 0x7f) << 14)
506159b3361Sopenharmony_ci            | ((id3v2Header[8] & 0x7f) << 7)
507159b3361Sopenharmony_ci            | (id3v2Header[9] & 0x7f))
508159b3361Sopenharmony_ci            + sizeof id3v2Header;
509159b3361Sopenharmony_ci    }
510159b3361Sopenharmony_ci    /* Seek to the beginning of the audio stream */
511159b3361Sopenharmony_ci	seekTo.QuadPart = id3v2TagSize;
512159b3361Sopenharmony_ci	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
513159b3361Sopenharmony_ci        return hr;
514159b3361Sopenharmony_ci    }
515159b3361Sopenharmony_ci    if (S_OK != (hr = maybeSyncWord(pStream))) {
516159b3361Sopenharmony_ci		return SUCCEEDED(hr)?E_FAIL:hr;
517159b3361Sopenharmony_ci    }
518159b3361Sopenharmony_ci	seekTo.QuadPart = id3v2TagSize+lametag_frame_size;
519159b3361Sopenharmony_ci	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
520159b3361Sopenharmony_ci        return hr;
521159b3361Sopenharmony_ci    }
522159b3361Sopenharmony_ci    if (S_OK != (hr = maybeSyncWord(pStream))) {
523159b3361Sopenharmony_ci        return SUCCEEDED(hr)?E_FAIL:hr;
524159b3361Sopenharmony_ci    }
525159b3361Sopenharmony_ci    /* OK, it seems we found our LAME-Tag/Xing frame again */
526159b3361Sopenharmony_ci    /* Seek to the beginning of the audio stream */
527159b3361Sopenharmony_ci	seekTo.QuadPart = id3v2TagSize;
528159b3361Sopenharmony_ci	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
529159b3361Sopenharmony_ci        return hr;
530159b3361Sopenharmony_ci    }
531159b3361Sopenharmony_ci    return S_OK;
532159b3361Sopenharmony_ci}
533159b3361Sopenharmony_ci
534159b3361Sopenharmony_ci// Updates VBR tag
535159b3361Sopenharmony_ciHRESULT CEncoder::updateLameTagFrame(IStream* pStream)
536159b3361Sopenharmony_ci{
537159b3361Sopenharmony_ci	HRESULT hr = S_OK;
538159b3361Sopenharmony_ci	size_t n = lame_get_lametag_frame( pgf, 0, 0 ); /* ask for bufer size */
539159b3361Sopenharmony_ci
540159b3361Sopenharmony_ci    if ( n > 0 )
541159b3361Sopenharmony_ci    {
542159b3361Sopenharmony_ci        unsigned char* buffer = 0;
543159b3361Sopenharmony_ci        ULONG m = n;
544159b3361Sopenharmony_ci
545159b3361Sopenharmony_ci        if ( FAILED(hr = skipId3v2(pStream, n) ))
546159b3361Sopenharmony_ci        {
547159b3361Sopenharmony_ci            /*DispErr( "Error updating LAME-tag frame:\n\n"
548159b3361Sopenharmony_ci                     "can't locate old frame\n" );*/
549159b3361Sopenharmony_ci            return hr;
550159b3361Sopenharmony_ci        }
551159b3361Sopenharmony_ci
552159b3361Sopenharmony_ci        buffer = (unsigned char*)malloc( n );
553159b3361Sopenharmony_ci
554159b3361Sopenharmony_ci        if ( buffer == 0 )
555159b3361Sopenharmony_ci        {
556159b3361Sopenharmony_ci            /*DispErr( "Error updating LAME-tag frame:\n\n"
557159b3361Sopenharmony_ci                     "can't allocate frame buffer\n" );*/
558159b3361Sopenharmony_ci            return E_OUTOFMEMORY;
559159b3361Sopenharmony_ci        }
560159b3361Sopenharmony_ci
561159b3361Sopenharmony_ci        /* Put it all to disk again */
562159b3361Sopenharmony_ci        n = lame_get_lametag_frame( pgf, buffer, n );
563159b3361Sopenharmony_ci        if ( n > 0 )
564159b3361Sopenharmony_ci        {
565159b3361Sopenharmony_ci			hr = pStream->Write(buffer, n, &m);
566159b3361Sopenharmony_ci        }
567159b3361Sopenharmony_ci        free( buffer );
568159b3361Sopenharmony_ci
569159b3361Sopenharmony_ci        if ( m != n )
570159b3361Sopenharmony_ci        {
571159b3361Sopenharmony_ci            /*DispErr( "Error updating LAME-tag frame:\n\n"
572159b3361Sopenharmony_ci                     "couldn't write frame into file\n" );*/
573159b3361Sopenharmony_ci			return E_FAIL;
574159b3361Sopenharmony_ci        }
575159b3361Sopenharmony_ci    }
576159b3361Sopenharmony_ci    return hr;
577159b3361Sopenharmony_ci}
578