📄 audio_encoder_class.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2002. All Rights Reserved. * * Contributor(s): * Bill May wmay@cisco.com * Peter Maersk-Moller peter@maersk-moller.net */#include "mp4live.h"#include "audio_encoder.h"#include "mp4av.h"//#define DEBUG_SYNC 1//#define DEBUG_AUDIO_RESAMPLER 1//#define DEBUG_AUDIO_SYNC 1CAudioEncoder::CAudioEncoder(CAudioProfile *profile, CAudioEncoder *next, u_int8_t srcChannels, u_int32_t srcSampleRate, uint16_t mtu, bool realTime) : CMediaCodec(profile, mtu, next, realTime) { m_audioSrcChannels = srcChannels; m_audioSrcSampleRate = srcSampleRate; m_audioPreEncodingBuffer = NULL; m_audioPreEncodingBufferLength = 0; m_audioPreEncodingBufferMaxLength = 0; m_audioResample = NULL; m_audioSrcFrameNumber = 0;}void CAudioEncoder::Initialize (void){ // called from derived classes init function from the start function // in the media flow m_audioSrcFrameNumber = 0; m_audioDstFrameNumber = 0; m_audioDstSampleNumber = 0; m_audioSrcElapsedDuration = 0; m_audioDstElapsedDuration = 0; // destination parameters are from the audio profile m_audioDstType = GetFrameType(); m_audioDstSampleRate = m_pConfig->GetIntegerValue(CFG_AUDIO_SAMPLE_RATE); m_audioDstChannels = m_pConfig->GetIntegerValue(CFG_AUDIO_CHANNELS); m_audioDstSamplesPerFrame = GetSamplesPerFrame(); // if we need to resample if (m_audioDstSampleRate != m_audioSrcSampleRate) { // create a resampler for each audio destination channel - // we will combine the channels before resampling m_audioResample = (resample_t *)malloc(sizeof(resample_t) * m_audioDstChannels); for (int ix = 0; ix < m_audioDstChannels; ix++) { m_audioResample[ix] = st_resample_start(m_audioSrcSampleRate, m_audioDstSampleRate); } } // this calculation doesn't take into consideration the resampling // size of the src. 4 times might not be enough - we need most likely // 2 times the max of the src samples and the dest samples m_audioPreEncodingBufferLength = 0; m_audioPreEncodingBufferMaxLength = 4 * DstSamplesToBytes(m_audioDstSamplesPerFrame); m_audioPreEncodingBuffer = (u_int8_t*)realloc( m_audioPreEncodingBuffer, m_audioPreEncodingBufferMaxLength);}// Audio encoding main processint CAudioEncoder::ThreadMain(void) { CMsg* pMsg; bool stop = false; debug_message("audio encoder thread %s %s %s start", Profile()->GetName(), Profile()->GetStringValue(CFG_AUDIO_ENCODER), Profile()->GetStringValue(CFG_AUDIO_ENCODING)); while (stop == false && SDL_SemWait(m_myMsgQueueSemaphore) == 0) { pMsg = m_myMsgQueue.get_message(); if (pMsg != NULL) { switch (pMsg->get_value()) { case MSG_NODE_STOP_THREAD: DoStopAudio(); stop = true; break; case MSG_NODE_START: // DoStartTransmit(); Anything ? break; case MSG_NODE_STOP: DoStopAudio(); break; case MSG_SINK_FRAME: { uint32_t dontcare; CMediaFrame *mf = (CMediaFrame*)pMsg->get_message(dontcare); if (m_stop_thread == false) ProcessAudioFrame(mf); if (mf->RemoveReference()) { delete mf; } break; } } delete pMsg; } } while ((pMsg = m_myMsgQueue.get_message()) != NULL) { if (pMsg->get_value() == MSG_SINK_FRAME) { uint32_t dontcare; CMediaFrame *mf = (CMediaFrame*)pMsg->get_message(dontcare); if (mf->RemoveReference()) { delete mf; } } delete pMsg; } if (m_audioResample != NULL) { for (uint ix = 0; ix < m_audioDstChannels; ix++) { st_resample_stop(m_audioResample[ix]); m_audioResample[ix] = NULL; } free(m_audioResample); } CHECK_AND_FREE(m_audioPreEncodingBuffer); debug_message("audio encoder thread %s exit", Profile()->GetName()); return 0;}void CAudioEncoder::AddSilenceFrame(void){ int bytes = DstSamplesToBytes(m_audioDstSamplesPerFrame); uint8_t *pSilenceData = (uint8_t *)Malloc(bytes); memset(pSilenceData, 0, bytes); bool rc = EncodeSamples( (int16_t*)pSilenceData, m_audioDstSamplesPerFrame, m_audioDstChannels); if (!rc) { debug_message("failed to encode audio"); return; } ForwardEncodedAudioFrames(); free(pSilenceData);}void CAudioEncoder::ProcessAudioFrame(CMediaFrame *pFrame){ const u_int8_t* frameData = (const uint8_t *)pFrame->GetData(); u_int32_t frameDataLength = pFrame->GetDataLength(); Timestamp srcFrameTimestamp = pFrame->GetTimestamp();; bool pcmMalloced = false; bool pcmBuffered; const u_int8_t* pcmData = frameData; u_int32_t pcmDataLength = frameDataLength; uint32_t audioSrcSamplesPerFrame = SrcBytesToSamples(frameDataLength); Duration subtractDuration = 0; /************************************************************************* * First convert input samples to format we need them to be in *************************************************************************/ if (m_audioSrcChannels != m_audioDstChannels) { // Convert the channels if they don't match // we either double the channel info, or combine // the left and right uint32_t samples = SrcBytesToSamples(frameDataLength); uint32_t dstLength = DstSamplesToBytes(samples); pcmData = (u_int8_t *)Malloc(dstLength); pcmDataLength = dstLength; pcmMalloced = true; int16_t *src = (int16_t *)frameData; int16_t *dst = (int16_t *)pcmData; if (m_audioSrcChannels == 1) { // 1 channel to 2 for (uint32_t ix = 0; ix < samples; ix++) { *dst++ = *src; *dst++ = *src++; } } else { // 2 channels to 1 for (uint32_t ix = 0; ix < samples; ix++) { int32_t sum = *src++; sum += *src++; sum /= 2; if (sum < -32768) sum = -32768; else if (sum > 32767) sum = 32767; *dst++ = sum & 0xffff; } } } // resample audio, if necessary if (m_audioSrcSampleRate != m_audioDstSampleRate) { subtractDuration = DstSamplesToTicks(DstBytesToSamples(m_audioPreEncodingBufferLength)); ResampleAudio(pcmData, pcmDataLength); // resampled data is now available in m_audioPreEncodingBuffer pcmBuffered = true; } else if (audioSrcSamplesPerFrame != m_audioDstSamplesPerFrame) { // reframe audio, if necessary // e.g. MP3 is 1152 samples/frame, AAC is 1024 samples/frame // add samples to end of m_audioPreEncodingBuffer // InitAudio() ensures that buffer is large enough if (m_audioPreEncodingBuffer == NULL) { m_audioPreEncodingBuffer = (u_int8_t*)realloc(m_audioPreEncodingBuffer, m_audioPreEncodingBufferMaxLength); } subtractDuration = DstSamplesToTicks(DstBytesToSamples(m_audioPreEncodingBufferLength)); memcpy( &m_audioPreEncodingBuffer[m_audioPreEncodingBufferLength], pcmData, pcmDataLength); m_audioPreEncodingBufferLength += pcmDataLength; pcmBuffered = true; } else { // default case - just use what we're passed pcmBuffered = false; } srcFrameTimestamp -= subtractDuration; /************************************************************************ * Loop while we have enough samples ************************************************************************/ Duration frametime = DstSamplesToTicks(m_audioDstSamplesPerFrame); if (m_audioDstFrameNumber == 0) debug_message("%s:frametime "U64, Profile()->GetName(), frametime); while (1) { /* * Record starting timestamps */ if (m_audioSrcFrameNumber == 0) { /* * we use m_audioStartTimestamp to determine audio output start time */ m_audioStartTimestamp = srcFrameTimestamp;#ifdef DEBUG_AUDIO_SYNC if (Profile()->GetBoolValue(CFG_AUDIO_DEBUG)) debug_message("%s:m_audioStartTimestamp = "U64, Profile()->GetName(), m_audioStartTimestamp);#endif } if (m_audioDstFrameNumber == 0) { // we wait until we see the first encoded frame. // this is because encoders usually buffer the first few // raw audio frames fed to them, and this number varies // from one encoder to another // We use this value to determine if we need to drop due to // a bad input frequency m_audioEncodingStartTimestamp = srcFrameTimestamp; } // we calculate audioSrcElapsedDuration by taking the current frame's // timestamp and subtracting the audioEncodingStartTimestamp (and NOT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -