📄 ac3decoder.cc
字号:
//// Copyright (c) 2003 by Istv醤 V醨adi//// This file is part of dxr3Player, a DVD player written specifically // for the DXR3 (aka Hollywood+) decoder card.// This program 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.//// This program 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 "AC3Decoder.h"#include "AudioProcessor.h"#include "util/Log.h"#include "util/Config.h"extern "C" { #include <liba52/mm_accel.h>}#include "config.h"#include <cstring>#include <cmath>#include <cassert>// This is needed for GCC 2.95, otherwise it is declared // in <unistd.h>extern "C" {void swab(const void* from, void* to, ssize_t n);}//------------------------------------------------------------------------------namespace {#if defined(MM_ACCEL_SSE) int mmAccel = MM_ACCEL_X86_SSE;#elif defined(MM_ACCEL_MMXEXT) int mmAccel = MM_ACCEL_X86_MMXEXT;#elif defined(MM_ACCEL_MMX) int mmAccel = MM_ACCEL_X86_MMX;#elif defined(MM_ACCEL_3DNOWEXT) int mmAccel = MM_ACCEL_X86_3DNOWEXT;#elif defined(MM_ACCEL_3DNOW) int mmAccel = MM_ACCEL_X86_3DNOW;#else int mmAccel = 0; #endif}//------------------------------------------------------------------------------using output::AC3Decoder;//------------------------------------------------------------------------------//------------------------------------------------------------------------------inline int16_t AC3Decoder::blah(int32_t i) { if (i > 0x43c07fff) {// Log::debug("output::AC3Decoder::blah: Positive overshoot!\n"); return 32767; } else if (i < 0x43bf8000) {// Log::debug("output::AC3Decoder::blah: Negative overshoot!\n"); return -32768; } else { return i - 0x43c00000; }}/*----------------------------------------------------------------------------*/inline void AC3Decoder::float_to_int(float * _f, int16_t * s16, int num_channels) { int i; int32_t * f = (int32_t *) _f; /* XXX assumes IEEE float format */ for (i = 0; i < 256; i++) { s16[num_channels*i] = blah (f[i]); }}//------------------------------------------------------------------------------inline bool AC3Decoder::isEmpty() const{ return frameOffset==0;}//------------------------------------------------------------------------------//------------------------------------------------------------------------------AC3Decoder::AC3Decoder(AudioProcessor* audioProcessor) : AudioDecoder(*audioProcessor), samples(a52_init(mmAccel)), frameOffset(0), frameLength( (size_t)-1 ), outputFlags(A52_STEREO), outputLevel(Config::get().defaultVolume), audioEnabled(true){ memset(&a52State, 0, sizeof(a52State));}//------------------------------------------------------------------------------void AC3Decoder::reset(){ frameOffset = 0; frameLength = (size_t)-1;}//------------------------------------------------------------------------------void AC3Decoder::decodePacket(const unsigned char* data, size_t length, pts_t packetPTS){ const unsigned char* end = data + length; size_t offset = 0; while(offset<length && !audioProcessor.isInterrupted()) { const unsigned char* start = data + offset; if (isEmpty()) { audioProcessor.transferPTS(packetPTS); } bool hasFrame = decode(start, end); offset = start - data; if (hasFrame) { audioProcessor.setOutputLength(outputLength); audioProcessor.outputPacket(); } }}//------------------------------------------------------------------------------bool AC3Decoder::decode(const unsigned char*& data, const unsigned char* end){ static const char syncWord[2] = { 0x0b, 0x77 }; static const unsigned syncInfoLength = 7; while(data<end) { while(data<end && frameOffset < sizeof(syncWord)) { if ( *data == syncWord[frameOffset] ) { frameBuffer[frameOffset] = *data; ++frameOffset; } else { frameOffset = 0; } ++data; } if (data>=end) return false; if( frameOffset >= sizeof(syncWord) && frameOffset < syncInfoLength ) { copy(data, end, syncInfoLength); } if (frameOffset==syncInfoLength) { int flags = outputFlags, sampleRate, bitRate; frameLength = a52_syncinfo(frameBuffer, &flags, &sampleRate, &bitRate); if (frameLength==0) { Log::debug("output::AC3Decoder::decode: invalid frame"); frameOffset = 0; }// Log::debug("output::AC3Decoder::decode: frame length: %u, flags: %0x, sampleRate: %d, bitRate: %d\n",// frameLength, flags, sampleRate, bitRate); assert(frameLength==0 || (frameLength>=128 && frameLength<=maxFrameSize)); assert( (frameLength%2)==0 ); setFormat(flags, sampleRate); } if (data>=end) return false; if ( frameOffset>=syncInfoLength && frameOffset<frameLength) { copy(data, end, frameLength); } if (frameOffset==frameLength) { bool frameValid = (audioProcessor.getOutputFormat().encoding == AC3) ? prepareFrameForHardwareDecoding() : decodeFrame(); frameOffset = 0; frameLength = (size_t)-1; if (frameValid) return true; } } return false;}//------------------------------------------------------------------------------bool AC3Decoder::toggleAudio(){ audioEnabled = !audioEnabled; if (!audioEnabled) { memset(audioProcessor.getOutputBuffer(), 0, outputLength); } return audioEnabled;}//------------------------------------------------------------------------------void AC3Decoder::copy(const unsigned char*& data, const unsigned char* end, size_t targetOffset){ unsigned tocopy = targetOffset - frameOffset; unsigned blockLength = end - data; if (tocopy>blockLength) tocopy = blockLength; memcpy(frameBuffer + frameOffset, data, tocopy); frameOffset += tocopy; data += tocopy; assert(data<=end);}//------------------------------------------------------------------------------void AC3Decoder::setFormat(int flags, int sampleRate){ AudioFormat& format = audioProcessor.getOutputFormat(); format.encoding = (Config::get().audioMode == AM_DIGITAL_AC3) ? AC3 : LPCM_LE; format.sampleRate = (unsigned)sampleRate; if (format.encoding==LPCM_LE) { format.numberOfChannels = 2; } else { switch(flags&A52_CHANNEL_MASK) { case A52_MONO: format.numberOfChannels = 1; break; case A52_STEREO: format.numberOfChannels = 2; break; case A52_3F: case A52_2F1R: format.numberOfChannels = 3; break; case A52_3F1R: case A52_2F2R: format.numberOfChannels = 4; break; case A52_3F2R: default: format.numberOfChannels = 5; break; } if (flags&A52_LFE) { ++format.numberOfChannels; } }}//------------------------------------------------------------------------------bool AC3Decoder::decodeFrame(){ if (!audioEnabled) return true; int flags = outputFlags | A52_ADJUST_LEVEL; float level = pow(2.0, ((int)outputLevel-40)/10.0); if (a52_frame(&a52State, frameBuffer, &flags, &level, 384)) { Log::error("output::AC3Decoder::decodeFrame: A52 frame error\n"); return false; } /* a52_dynrng(&a52State, 0, 0); */ int16_t* decodedOutput = reinterpret_cast<int16_t*>(audioProcessor.getOutputBuffer()); for (size_t i = 0; i < 6; i++) { if (a52_block(&a52State, samples)) { Log::error("output::AC3Decoder::decodeFrame: A52 block error: %u\n", i); return false; } float_to_int (samples + 0*256, decodedOutput + (i*256*2), 2); float_to_int (samples + 1*256, decodedOutput + (i*256*2)+1, 2); } return true;}//------------------------------------------------------------------------------bool AC3Decoder::prepareFrameForHardwareDecoding(){ unsigned char* output = audioProcessor.getOutputBuffer(); output[0] = 0x72; output[1] = 0xf8; output[2] = 0x1f; output[3] = 0x4e; output[4] = 0x01; output[5] = 0x00; output[6] = (frameLength<<3) & 0xff; output[7] = (frameLength>>5) & 0xff; swab(frameBuffer, output+8, frameLength); memset(output + 8 + frameLength, 0, outputLength - 8 - frameLength); return true;}//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -