svvitch
digital signage player
D:/vs_workspace/switch_sf/src/svvitch/FFAudioDecoder.cpp
Go to the documentation of this file.
00001 #ifdef USE_FFMPEG
00002 
00003 #include <Poco/format.h>
00004 #include <Poco/Logger.h>
00005 #include <Poco/Mutex.h>
00006 #include <Poco/Thread.h>
00007 #include <Poco/UnicodeConverter.h>
00008 #include "FFAudioDecoder.h"
00009 #include "PerformanceTimer.h"
00010 
00011 
00012 FFAudioDecoder::FFAudioDecoder(Renderer& renderer, AVFormatContext* ic, const int streamNo): FFBaseDecoder(renderer, ic, streamNo),
00013     _buffer(NULL), _bufferOffset(0), _bufferSize(0), _running(false), _data(NULL), _dataOffset(0), _len(0), _playCursor(0), _writeCursor(0)
00014 {
00015 }
00016 
00017 FFAudioDecoder::‾FFAudioDecoder() {
00018     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00019     stop();
00020     SAFE_DELETE(_data);
00021     SAFE_RELEASE(_buffer);
00022 }
00023 
00024 
00025 bool FFAudioDecoder::isReady() {
00026     return true;
00027 }
00028 
00029 void FFAudioDecoder::start() {
00030     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00031     AVCodecContext* avctx = _ic->streams[_streamNo]->codec;
00032     WORD sampleBit;
00033     string type;
00034     switch (avctx->sample_fmt) {
00035         case SAMPLE_FMT_U8:
00036             type = "unsigned 8 bits";
00037             sampleBit = 8;
00038             break;
00039         case SAMPLE_FMT_S16:
00040             type = "signed 16 bits";
00041             sampleBit = 16;
00042             break;
00043         case SAMPLE_FMT_S32:
00044             type = "signed 32 bits";
00045             sampleBit = 32;
00046             break;
00047         case SAMPLE_FMT_FLT:
00048             type = "float";
00049             sampleBit = 32;
00050             break;
00051         case SAMPLE_FMT_DBL:
00052             type = "double";
00053             sampleBit = 32;
00054             break;
00055         default:
00056             type = Poco::format("unknown format(%d)", (int)avctx->sample_fmt);
00057     }
00058     _log.information(Poco::format("audio stream: format(%s) channels: %d sample: %hubit %dHz bitrate: %d", type, avctx->channels, sampleBit, avctx->sample_rate, avctx->bit_rate));
00059 
00060     //WAVEフォーマット設定
00061     WAVEFORMATEX wfwav;
00062     ZeroMemory(&wfwav, sizeof(wfwav));
00063     wfwav.wFormatTag = WAVE_FORMAT_PCM;
00064     wfwav.nChannels = avctx->channels;
00065     wfwav.nSamplesPerSec = avctx->sample_rate;
00066     wfwav.wBitsPerSample = sampleBit;
00067     wfwav.nBlockAlign = wfwav.nChannels * wfwav.wBitsPerSample / 8;
00068     wfwav.nAvgBytesPerSec = wfwav.nSamplesPerSec * wfwav.nBlockAlign;
00069     wfwav.cbSize = 0;
00070 
00071     _bufferSize = wfwav.nAvgBytesPerSec * 20;
00072     _bufferOffset = 0;
00073     _log.information(Poco::format("sound buffer size: %lu", _bufferSize));
00074 
00075     //プライマリバッファの作成
00076     DSBUFFERDESC desc;
00077     ZeroMemory(&desc, sizeof(desc));
00078     desc.dwSize     = sizeof(desc);
00079     // desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCDEFER | DSBCAPS_CTRLFREQUENCY;
00080     // desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCDEFER | DSBCAPS_CTRLPOSITIONNOTIFY;
00081     desc.dwFlags    = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME;
00082     desc.dwBufferBytes = _bufferSize;
00083     desc.lpwfxFormat = &wfwav;
00084     desc.guid3DAlgorithm = GUID_NULL;
00085     LPDIRECTSOUND sound = _renderer.getSoundDevice();
00086     HRESULT hr = sound->CreateSoundBuffer(&desc, &_buffer, NULL);
00087     if (FAILED(hr)) {
00088         _log.warning("failed not create sound buffer");
00089 
00090     } else {
00091         hr = _buffer->SetCurrentPosition(0);
00092         // DWORD frq;
00093         // _buffer->GetFrequency(&frq);
00094         // _buffer->SetFrequency(frq * 1.25);
00095         _data = new uint8_t[BUFFER_SIZE];
00096         ZeroMemory(_data, sizeof(uint8_t) * BUFFER_SIZE);
00097     }
00098 }
00099 
00100 const UINT FFAudioDecoder::bufferedFrames() {
00101     return bufferedPackets();
00102 }
00103 
00104 void FFAudioDecoder::decode() {
00105     if (!_data) return;
00106     //_log.information("audio decoder thread start");
00107     //DWORD threadAffinityMask = ::SetThreadAffinityMask(GetCurrentThread(), 1);
00108     if (_len > 0) return;
00109     if (_dataOffset > 0) return;
00110     AVPacketList* packetList = popPacket();
00111     if (!packetList) return;
00112 
00113     PerformanceTimer timer;
00114     timer.start();
00115     AVCodecContext* avctx = _ic->streams[packetList->pkt.stream_index]->codec;
00116     AVPacket* packet = &packetList->pkt;
00117     AVPacket tmp;
00118     av_init_packet(&tmp);
00119     tmp.data = packet->data;
00120     tmp.size = packet->size;
00121     while (tmp.data && tmp.size > 0) {
00122         int frameSize = sizeof(uint8_t) * BUFFER_SIZE;
00123         int bytes = avcodec_decode_audio3(avctx, (int16_t*)(&_data[_len]), &frameSize, &tmp);
00124         if (bytes >= 0) {
00125             tmp.data += bytes;
00126             tmp.size -= bytes;
00127             if (frameSize > 0) {
00128                 _len += frameSize;
00129             }
00130             _readTime = timer.getTime();
00131             _readCount++;
00132             if (_readCount > 0) _avgTime = F(_avgTime * (_readCount - 1) + _readTime) / _readCount;
00133 
00134         } else {
00135             // throw error or something?
00136             _log.warning(Poco::format("failed avcodec_decode_audio3: %d %d", bytes, frameSize));
00137             _len = 0;
00138             break;
00139         }
00140     }
00141     if (packet->data) av_free_packet(packet);
00142     av_freep(&packetList);
00143 }
00144 
00145 void FFAudioDecoder::writeData() {
00146     if (!_buffer) return;
00147 
00148     HRESULT hr = _buffer->GetCurrentPosition(&_playCursor, &_writeCursor);
00149     if FAILED(hr) {
00150         _log.warning("failed get current position");
00151         return;
00152     }
00153     if (_len <= 0) return;
00154 
00155     if (_dataOffset > 0) {
00156         // 再生中で再生カーソルがバッファの半分以降になるまで書込み待ち
00157         // _log.information(Poco::format("buffer cursor: %lu %lu", _playCursor, (_bufferSize / 2)));
00158         if (!_running || _playCursor < _bufferSize / 2) return;
00159 
00160     } else {
00161         // 書込みカーソル以降の場合、再生カーソルのデータx2個分余裕ができるまで書込み待ち
00162         if (_writeCursor > _bufferOffset && _playCursor < _bufferOffset + _len * 2) return;
00163     }
00164 
00165     LPVOID lockedBuf = NULL;
00166     DWORD lockedLen = 0;
00167     if (_bufferOffset + _len <= _bufferSize) {
00168         // オフセット+データサイズがバッファ以下の場合はそのまますべて書込む
00169         hr = _buffer->Lock(_bufferOffset, _len, &lockedBuf, &lockedLen, NULL, 0, 0);
00170         if (SUCCEEDED(hr)) {
00171             CopyMemory(lockedBuf, &_data[_dataOffset], lockedLen);
00172             hr = _buffer->Unlock(lockedBuf, lockedLen, NULL, 0);
00173             if (FAILED(hr)) {
00174                 _log.warning("failed unlocked sound buffer");
00175             } else {
00176                 _bufferOffset = (_bufferOffset + _len) % _bufferSize;
00177                 _len = 0;
00178                 _dataOffset = 0;
00179             }
00180         } else {
00181             _log.warning(Poco::format("sound buffer not locked: %d", _len));
00182         }
00183     } else {
00184         // 残りバッファに書込みむ。残りは次回呼出し時に書込む
00185         //_log.information("round sound buffer");
00186         int lenRound = _bufferSize - _bufferOffset;
00187         hr = _buffer->Lock(_bufferOffset, lenRound, &lockedBuf, &lockedLen, NULL, 0, 0);
00188         if (SUCCEEDED(hr)) {
00189             CopyMemory(lockedBuf, _data, lockedLen);
00190             hr = _buffer->Unlock(lockedBuf, lockedLen, NULL, 0);
00191             if (FAILED(hr)) {
00192                 _log.warning("failed unlocked sound buffer");
00193             } else {
00194                 _bufferOffset = 0;
00195                 _len -= lenRound;
00196                 _dataOffset = lenRound;
00197             }
00198         } else {
00199             _log.warning(Poco::format("SoundBuffer not locked: %d", lenRound));
00200         }
00201     }
00202 }
00203 
00204 void FFAudioDecoder::finishedPacket() {
00205     if (!_buffer) return;
00206 
00207     int size = _bufferSize - _bufferOffset;
00208     LPVOID lockedBuf = NULL;
00209     DWORD lockedLen = 0;
00210     HRESULT hr = _buffer->Lock(_bufferOffset, size, &lockedBuf, &lockedLen, NULL, 0, 0);
00211     if (SUCCEEDED(hr)) {
00212         ZeroMemory(lockedBuf, lockedLen);
00213         hr = _buffer->Unlock(lockedBuf, lockedLen, NULL, 0);
00214     }
00215 }
00216 
00217 bool FFAudioDecoder::playing() {
00218     return _running;
00219 }
00220 
00221 void FFAudioDecoder::play() {
00222     if (_buffer && !_running) {
00223         HRESULT hr = _buffer->Play(0, 0, DSBPLAY_LOOPING);
00224         if (SUCCEEDED(hr)) {
00225             _running = true;
00226         } else {
00227             _log.warning("failed play sound buffer");
00228         }
00229     }
00230 }
00231 
00232 void FFAudioDecoder::stop() {
00233     if (_buffer && _running) {
00234         HRESULT hr = _buffer->Stop();
00235         if (SUCCEEDED(hr)) {
00236             _running = false;
00237         }
00238     }
00239 }
00240 
00241 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines