www.pudn.com > mediator15src.zip > AudioCompressor.cpp
/* * AudioCompressor.cpp * Copyright (C) 2002 Arno Hornberger* Original Version Copyright (C) Alberto Vigata - January 2000 - ultraflask@yahoo.com * Class 'AudioL3Corrector' Copyright (C) 1998-2001 Avery Lee * * This file is part of MPEG Mediator, a free MPEG stream converter. * * MPEG Mediator is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MPEG Mediator 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 "stdafx.h" #include "opendmlavioutput.h" #include "AudioCompressor.h" #include "error.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif /////////////////////////////////////////////////////////////////////////// // // Corrects the nAvgBytesPerFrame for that stupid Fraunhofer-IIS // codec. AudioL3Corrector::AudioL3Corrector() { samples = frame_bytes = 0; read_left = 4; header_mode = true; } long AudioL3Corrector::ComputeByterate(long sample_rate) { return MulDiv(frame_bytes, sample_rate, samples); } void AudioL3Corrector::Process(void *buffer, long bytes) { static const int bitrates[2][16]={ {0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160,0}, {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0} }; static const long samp_freq[4] = {44100, 48000, 32000, 0}; int cnt=0; int tc; while(cnt < bytes) { tc = bytes - cnt; if (tc > read_left) tc = read_left; if (header_mode) memcpy(&hdr_buffer[4-read_left], buffer, tc); buffer = (char *)buffer + tc; cnt += tc; read_left -= tc; if (read_left <= 0) if (header_mode) { // We've got a header! Process it... long hdr = *(long *)hdr_buffer; long samp_rate, framelen; if ((hdr & 0xE0FF) != 0xE0FF) throw MyError("AudioL3Corrector::Process - MPEG audio sync error"); samp_rate = samp_freq[(hdr>>18)&3]; if (!((hdr>>11)&1)) { samp_rate /= 2; samples += 576; } else samples += 1152; if (!(hdr & 0x1000)) samp_rate /= 2; framelen = (bitrates[(hdr>>11)&1][(hdr>>20)&15] * (((hdr>>11)&1) ? 144000 : 72000)) / samp_rate; if (hdr&0x20000) ++framelen; // update statistics frame_bytes += framelen; // start skipping the remainder read_left = framelen - 4; header_mode = false; } else { // Done skipping frame data; collect the next header read_left = 4; header_mode = true; } } } CAudioCompressor::CAudioCompressor(HACMDRIVERID hadid, WAVEFORMATEX *wfxIn, WAVEFORMATEX *wfxOut, bool hq) { pInAudio = new BYTE[AUDIO_BUFFER_SIZE]; pOutAudio = new BYTE[AUDIO_BUFFER_SIZE]; if (acmDriverOpen(&m_hHad, hadid, 0)) throw MyError("CAudioCompressor::CAudioCompressor - error opening acm driver"); if (acmStreamOpen(&m_hHas, m_hHad, wfxIn, wfxOut, NULL, NULL, 0, hq ? ACM_STREAMOPENF_NONREALTIME : 0)) { acmDriverClose(m_hHad, 0); throw MyError("CAudioCompressor::CAudioCompressor - error opening acm stream"); } memset(&m_sStreamHdr, 0, sizeof(ACMSTREAMHEADER)); m_sStreamHdr.cbStruct = sizeof(ACMSTREAMHEADER); m_sStreamHdr.pbSrc = pInAudio; m_sStreamHdr.cbSrcLength = AUDIO_BUFFER_SIZE; m_sStreamHdr.pbDst = pOutAudio; m_sStreamHdr.cbDstLength = AUDIO_BUFFER_SIZE; if (acmStreamPrepareHeader(m_hHas, &m_sStreamHdr, 0)) { acmStreamClose(m_hHas, 0); acmDriverClose(m_hHad, 0); throw MyError("CAudioCompressor::CAudioCompressor - error preparing stream header"); } m_nBufferPtr = 0; } CAudioCompressor::~CAudioCompressor() { acmStreamUnprepareHeader(m_hHas, &m_sStreamHdr, 0); acmStreamClose(m_hHas, 0); acmDriverClose(m_hHad, 0); delete []pInAudio; delete []pOutAudio; } /* bool CAudioCompressor::DeInitAudioCompressor() { acmStreamUnprepareHeader(m_hHas, &m_sStreamHdr, 0); acmStreamClose(m_hHas, 0); acmDriverClose(m_hHad, 0); return true; } */ /* bool CAudioCompressor::InitAudioCompressor(HACMDRIVERID hadid, WAVEFORMATEX *wfxIn, WAVEFORMATEX *wfxOut, bool hq) { if (acmDriverOpen(&m_hHad, hadid, 0)) return false; if (acmStreamOpen(&m_hHas, m_hHad, wfxIn, wfxOut, NULL, NULL, 0, hq ? ACM_STREAMOPENF_NONREALTIME : 0)) { acmDriverClose(m_hHad, 0); return false; } memset(&m_sStreamHdr, 0, sizeof(ACMSTREAMHEADER)); m_sStreamHdr.cbStruct = sizeof(ACMSTREAMHEADER); m_sStreamHdr.pbSrc = pInAudio; m_sStreamHdr.cbSrcLength = AUDIO_BUFFER_SIZE; m_sStreamHdr.pbDst = pOutAudio; m_sStreamHdr.cbDstLength = AUDIO_BUFFER_SIZE; if (acmStreamPrepareHeader(m_hHas, &m_sStreamHdr, 0)) { acmStreamClose(m_hHas, 0); acmDriverClose(m_hHad, 0); return false; } m_nBufferPtr = 0; return true; } */ bool CAudioCompressor::Compress(PBYTE inAudio, long inSize, PBYTE &outAudio, long &outSize) { outAudio = NULL; outSize = 0; // copy source data to our stream header if ((m_nBufferPtr + inSize) > MIN_AUDIO_BUFFER) { // check that inSize is not too much if ((m_nBufferPtr + inSize) > AUDIO_BUFFER_SIZE) return false; // we have enough data to be compressed // copy the data memcpy(m_sStreamHdr.pbSrc + m_nBufferPtr, inAudio, inSize); m_nBufferPtr += inSize; } else { // copy data and exit memcpy(m_sStreamHdr.pbSrc + m_nBufferPtr, inAudio, inSize); m_nBufferPtr += inSize; return false; } m_sStreamHdr.cbSrcLength = m_nBufferPtr; m_sStreamHdr.cbSrcLengthUsed = 0; m_sStreamHdr.cbDstLengthUsed = 0; // try to compress this buffer if (acmStreamConvert(m_hHas, &m_sStreamHdr, ACM_STREAMCONVERTF_BLOCKALIGN)) return false; if (!(m_sStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)) return false; // conversion was successful // copy remaining data after conversion in source buffer int newBufSize = 0; for (int j = 0, i = m_sStreamHdr.cbSrcLengthUsed; i < m_nBufferPtr; i++, j++) { pInAudio[j] = pInAudio[i]; newBufSize++; } m_nBufferPtr = newBufSize; // output the compressed data outAudio = m_sStreamHdr.pbDst; outSize = m_sStreamHdr.cbDstLengthUsed; return true; }