⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audiohandler.cc

📁 Linux下比较早的基于命令行的DVD播放器
💻 CC
字号:
// Copyright (c) 2005 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 "AudioHandler.h"#include "AudioDevice.h"#include "Timer.h"#include "dvd/packet/PacketQueue.h"#include "dvd/packet/DataBlockTypes.h"#include "sched/Scheduler.h"#include "util/Config.h"//------------------------------------------------------------------------------using output::AudioHandler;using dvd::packet::PacketQueue;using dvd::packet::TimedAudioPacket;using dvd::packet::DataBlockTypes;using sched::Scheduler;//------------------------------------------------------------------------------const unsigned char AudioHandler::gapBuffer[4096] = { 0 };//------------------------------------------------------------------------------inline audioMode_t AudioHandler::getAudioMode(audioEncoding_t encoding){    switch(encoding) {      case AC3:      case DTS:        return AM_DIGITAL_AC3;      default:        return AM_ANALOGUE;    }}//------------------------------------------------------------------------------inline size_t AudioHandler::getSampleSize() const{    return audioDevice.getSampleSize();}//------------------------------------------------------------------------------inline size_t AudioHandler::samples2Bytes(size_t numSamples) const{    return numSamples * getSampleSize();}//------------------------------------------------------------------------------inline size_t AudioHandler::pts2Samples(pts_t diff) const{    diff *= audioDevice.getSampleRate();    diff /= Util::ptsFrequency;    return static_cast<size_t>(diff);}//------------------------------------------------------------------------------inline size_t AudioHandler::millis2Samples(millis_t millis) const{    millis *= audioDevice.getSampleRate();    millis /= 1000;        return static_cast<size_t>(millis);}//------------------------------------------------------------------------------inline ptsdiff_t AudioHandler::getPTSWritten() const{    ptsdiff_t diff = samplesWritten;        diff *= Util::ptsFrequency;    diff /= audioDevice.getSampleRate();    return diff;}//------------------------------------------------------------------------------//------------------------------------------------------------------------------AudioHandler::AudioHandler(AudioDevice& audioDevice,                           Timer& timer,                           PacketQueue& inputQueue) :    Schedulable("output::AudioHandler"),    timer(timer),    inputQueue(inputQueue),    audioDevice(audioDevice),    audioStopped("output::AudioHandler", "audioStopped"),    startPTS(INVALID_PTS),    samplesWritten(0),    endPTS(INVALID_PTS),    updateTimerPTS(INVALID_PTS),    toFlush(false){    audioDevice.setup(Config::get().audioMode, 48000, true);}//------------------------------------------------------------------------------void AudioHandler::run(){    while(!shouldQuit()) {        clearInterrupt();        toFlush = false;        prebuffer();                play();                finish();    }        samplesWritten = 0;    audioDevice.stopPlayback();    audioStopped.set();    audioDevice.stop();}//------------------------------------------------------------------------------void AudioHandler::reset(){    currentPacket = 0;    interrupt();}//------------------------------------------------------------------------------void AudioHandler::flush(){    size_t minPlayableSamples = audioDevice.isTriggerable() ?         millis2Samples(prebufferMillis) : 1;    if (samplesWritten<minPlayableSamples) {        toFlush = true;        interrupt();    }}//------------------------------------------------------------------------------void AudioHandler::waitStop(){    while(samplesWritten>0) {        flush();        Scheduler::wait(audioStopped);    }}//------------------------------------------------------------------------------void AudioHandler::setFormat(const AudioFormat& audioFormat){    Log::debug("output::AudioHandler::setFormat: encoding=%d, sampleRate=%u, # of channels=%u\n",               (int)audioFormat.encoding, audioFormat.sampleRate, audioFormat.numberOfChannels);    audioDevice.setup(getAudioMode(audioFormat.encoding),                      audioFormat.sampleRate,                       audioFormat.numberOfChannels>=2);}//------------------------------------------------------------------------------bool AudioHandler::isDifferent(const AudioFormat& audioFormat) const{    if (audioFormat.sampleRate!=audioDevice.getSampleRate()) return true;        bool stereoNeeded =         audioFormat.numberOfChannels >= 2 || audioFormat.encoding==AC3;    if (stereoNeeded!=audioDevice.isStereo()) return true;    if (getAudioMode(audioFormat.encoding)!=audioDevice.getAudioMode())      return true;    return false;}//------------------------------------------------------------------------------void AudioHandler::prebuffer(){    audioDevice.stopPlayback();    Log::debug("output::AudioHandler::prebuffer\n");    startPTS = endPTS = updateTimerPTS = INVALID_PTS;        samplesWritten = 0;    audioStopped.set();        do {        if (!currentPacket.isValid()) {            currentPacket = TimedAudioPacket::convert(inputQueue.get());        }        if (currentPacket.isValid()) {            assert(currentPacket->getType()==DataBlockTypes::audio);            const AudioFormat& format = currentPacket->getFormat();            if (isDifferent(format)) {                if (samplesWritten==0) {                    setFormat(format);                } else {                    Log::debug("output::dxr3::AudioHandler::prebuffer: audio format changed, flushing.\n");                    toFlush = true;                    interrupt();                    break;                }            }                        setupStartPTS(currentPacket);            if (audioDevice.isTriggerable()) {                writeCurrentPacket();            }        }    } while(!isInterrupted() &&             samplesWritten<millis2Samples(prebufferMillis) &&            audioDevice.isTriggerable());    if (audioDevice.isTriggerable() || currentPacket.isValid()) {        startPlayback();    }}//------------------------------------------------------------------------------void AudioHandler::setupStartPTS(Reference<TimedAudioPacket> packet){    if (startPTS!=INVALID_PTS) return;    pts_t dataPTS = packet->getPTS();    if (dataPTS==INVALID_PTS) return;    startPTS = dataPTS;    if (samplesWritten==0) return;    ptsdiff_t ptsDiff = getPTSWritten();    if (ptsDiff<static_cast<ptsdiff_t>(startPTS)) startPTS -= ptsDiff;    else startPTS = 0;}//------------------------------------------------------------------------------void AudioHandler::startPlayback(){    if (startPTS==INVALID_PTS || toFlush) {        startPTS = timer.getCurrentSCR();    } else while(!isInterrupted()) {        pts_t currentSCR = timer.getCurrentSCR();        pts_t compensatedStartPTS = startPTS + timer.getPTSCompensation();                if (currentSCR < compensatedStartPTS) {            timer.sleepInterruptible(compensatedStartPTS);        } else {            ptsdiff_t diff = currentSCR - compensatedStartPTS;            timer.advancePTSCompensation(diff);            startPTS += timer.getPTSCompensation();            break;        }    }    if ( (!isInterrupted() || toFlush) &&          (samplesWritten>0 || !audioDevice.isTriggerable()) )    {        updateTimerPTS = startPTS + timerUpdateInterval;        updateEndPTS();        if (audioDevice.isTriggerable()) {            audioDevice.startPlayback();        } else {            writeCurrentPacket();        }        Log::debug("output::dxr3::AudioHandler::startPlayback: audio of PTS %llu (compensated with %lld) at %llu\n",                   startPTS, timer.getPTSCompensation(), timer.getCurrentSCR());    } else {        samplesWritten = 0;    }}//------------------------------------------------------------------------------void AudioHandler::play(){    while(!isInterrupted()) {        if (!currentPacket.isValid()) {            pts_t timeoutPTS = endPTS;            if (!audioDevice.isRealTime()) timeoutPTS -= ptsTolerance;                        millis_t timeout = timer.getMillis(timeoutPTS);            currentPacket = TimedAudioPacket::convert(inputQueue.get(timeout));        }         if (currentPacket.isValid()) {            assert(currentPacket->getType()==DataBlockTypes::audio);            if (isDifferent(currentPacket->getFormat())) {                Log::debug("output::AudioHandler::play: audio format changed during play\n");                break;            }            if (audioDevice.isRealTime()) {                pts_t ptsBuffered = audioDevice.getPTSBuffered();                if ( ptsBuffered < millis2PTS(minPlayabaleMillis) )                 {                    Log::debug("output::AudioHandler::play: "                               "too little (%llu) remained to be played, packet is probably late\n",                               ptsBuffered);                    break;                }            }                        size_t gapSize = calculateGapSize(currentPacket);            if (gapSize>samples2Bytes(millis2Samples(minGapMillis))) {                Log::debug("output::AudioHandler::play: PTS increased, adding gap of size %u\n",                           gapSize);                if (audioDevice.getAudioMode()==AM_DIGITAL_AC3) {                    break;                } else {                    writeGap(gapSize);                }            }                        if (!isInterrupted()) {                writeCurrentPacket();                                bool updateTimer = updateEndPTS();                                if (audioDevice.isRealTime() && updateTimer) {                    pts_t ptsPlayed = audioDevice.getPTSPlayed();                    timer.adjustFrequency(startPTS + ptsPlayed);                    updateTimerPTS += timerUpdateInterval;                }                            }        } else if (!isInterrupted()) {            Log::debug("output::AudioHandler::play: timeout while waiting for packet\n");            break;        }    }}//------------------------------------------------------------------------------void AudioHandler::finish(){}//------------------------------------------------------------------------------size_t AudioHandler::calculateGapSize(Reference<TimedAudioPacket> packet){    pts_t dataPTS = packet->getPTS();        if (dataPTS==INVALID_PTS) {        return 0;    }    dataPTS += timer.getPTSCompensation();    if (dataPTS<endPTS) {        ptsdiff_t diff = endPTS - dataPTS;                    Log::debug("output::AudioHandler::calculateGapSize: PTS decrased by %lld, compensating\n",                   diff);                timer.advancePTSCompensation(diff);        dataPTS += diff;                return 0;    } else if (dataPTS>endPTS) {        return samples2Bytes(pts2Samples(dataPTS - endPTS));    } else {        return 0;    }}//------------------------------------------------------------------------------bool AudioHandler::updateEndPTS(){    endPTS = startPTS + getPTSWritten();    return endPTS>=updateTimerPTS;}//------------------------------------------------------------------------------void AudioHandler::write(const unsigned char* buffer, size_t length,                         bool interruptible){    size_t written = audioDevice.play(buffer, length, interruptible);    samplesWritten += written / getSampleSize();}//------------------------------------------------------------------------------void AudioHandler::writeGap(size_t gapSize, bool interruptible){    while((!isInterrupted() || !interruptible) && gapSize>0) {        size_t toWrite = sizeof(gapBuffer);        if (toWrite>gapSize) toWrite = gapSize;        write(gapBuffer, toWrite, interruptible);        gapSize -= toWrite;    }}//------------------------------------------------------------------------------void AudioHandler::writeCurrentPacket(){    assert(currentPacket.isValid());    write(currentPacket->getData(), currentPacket->getLength());    currentPacket = 0;}//------------------------------------------------------------------------------// Local Variables:// mode: C++// c-basic-offset: 4// indent-tabs-mode: nil// End:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -