123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- #include "captions-mssapi-stream.hpp"
- #include "captions-mssapi.hpp"
- #include <mmreg.h>
- #include <util/windows/CoTaskMemPtr.hpp>
- #include <util/threading.h>
- #include <util/base.h>
- using namespace std;
- #if 0
- #define debugfunc(format, ...) blog(LOG_DEBUG, "[Captions] %s(" format ")", __FUNCTION__, ##__VA_ARGS__)
- #else
- #define debugfunc(format, ...)
- #endif
- CaptionStream::CaptionStream(DWORD samplerate_, mssapi_captions *handler_)
- : handler(handler_),
- samplerate(samplerate_),
- event(CreateEvent(nullptr, false, false, nullptr))
- {
- buf_info.ulMsMinNotification = 50;
- buf_info.ulMsBufferSize = 500;
- buf_info.ulMsEventBias = 0;
- format.wFormatTag = WAVE_FORMAT_PCM;
- format.nChannels = 1;
- format.nSamplesPerSec = 16000;
- format.nAvgBytesPerSec = format.nSamplesPerSec * sizeof(uint16_t);
- format.nBlockAlign = 2;
- format.wBitsPerSample = 16;
- format.cbSize = sizeof(format);
- }
- void CaptionStream::Stop()
- {
- {
- lock_guard<mutex> lock(m);
- deque_free(buf);
- }
- cv.notify_one();
- }
- void CaptionStream::PushAudio(const void *data, size_t frames)
- {
- bool ready = false;
- lock_guard<mutex> lock(m);
- deque_push_back(buf, data, frames * sizeof(int16_t));
- write_pos += frames * sizeof(int16_t);
- if (wait_size && buf->size >= wait_size)
- ready = true;
- if (ready)
- cv.notify_one();
- }
- // IUnknown methods
- STDMETHODIMP CaptionStream::QueryInterface(REFIID riid, void **ppv)
- {
- if (riid == IID_IUnknown) {
- AddRef();
- *ppv = this;
- } else if (riid == IID_IStream) {
- AddRef();
- *ppv = (IStream *)this;
- } else if (riid == IID_ISpStreamFormat) {
- AddRef();
- *ppv = (ISpStreamFormat *)this;
- } else if (riid == IID_ISpAudio) {
- AddRef();
- *ppv = (ISpAudio *)this;
- } else {
- *ppv = nullptr;
- return E_NOINTERFACE;
- }
- return NOERROR;
- }
- STDMETHODIMP_(ULONG) CaptionStream::AddRef()
- {
- return (ULONG)os_atomic_inc_long(&refs);
- }
- STDMETHODIMP_(ULONG) CaptionStream::Release()
- {
- ULONG new_refs = (ULONG)os_atomic_dec_long(&refs);
- if (!new_refs)
- delete this;
- return new_refs;
- }
- // ISequentialStream methods
- STDMETHODIMP CaptionStream::Read(void *data, ULONG bytes, ULONG *read_bytes)
- {
- HRESULT hr = S_OK;
- size_t cur_size;
- debugfunc("data, %lu, read_bytes", bytes);
- if (!data)
- return STG_E_INVALIDPOINTER;
- {
- lock_guard<mutex> lock1(m);
- wait_size = bytes;
- cur_size = buf->size;
- }
- unique_lock<mutex> lock(m);
- if (bytes > cur_size)
- cv.wait(lock);
- if (bytes > (ULONG)buf->size) {
- bytes = (ULONG)buf->size;
- hr = S_FALSE;
- }
- if (bytes)
- deque_pop_front(buf, data, bytes);
- if (read_bytes)
- *read_bytes = bytes;
- wait_size = 0;
- pos.QuadPart += bytes;
- return hr;
- }
- STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes, ULONG *)
- {
- debugfunc("data, %lu, written_bytes", bytes);
- return STG_E_INVALIDFUNCTION;
- }
- // IStream methods
- STDMETHODIMP CaptionStream::Seek(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
- {
- debugfunc("%lld, %lx, new_pos", move, origin);
- if (!new_pos)
- return E_POINTER;
- if (origin != SEEK_CUR || move.QuadPart != 0)
- return E_NOTIMPL;
- *new_pos = pos;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::SetSize(ULARGE_INTEGER new_size)
- {
- debugfunc("%llu", new_size);
- return STG_E_INVALIDFUNCTION;
- }
- STDMETHODIMP CaptionStream::CopyTo(IStream *stream, ULARGE_INTEGER bytes, ULARGE_INTEGER *read_bytes,
- ULARGE_INTEGER *written_bytes)
- {
- HRESULT hr;
- debugfunc("stream, %llu, read_bytes, written_bytes", bytes);
- if (!stream)
- return STG_E_INVALIDPOINTER;
- ULONG written = 0;
- if (bytes.QuadPart > (ULONGLONG)buf->size)
- bytes.QuadPart = (ULONGLONG)buf->size;
- lock_guard<mutex> lock(m);
- temp_buf.resize((size_t)bytes.QuadPart);
- deque_peek_front(buf, &temp_buf[0], (size_t)bytes.QuadPart);
- hr = stream->Write(temp_buf.data(), (ULONG)bytes.QuadPart, &written);
- if (read_bytes)
- *read_bytes = bytes;
- if (written_bytes)
- written_bytes->QuadPart = written;
- return hr;
- }
- STDMETHODIMP CaptionStream::Commit(DWORD commit_flags)
- {
- debugfunc("%lx", commit_flags);
- /* TODO? */
- return S_OK;
- }
- STDMETHODIMP CaptionStream::Revert(void)
- {
- debugfunc("");
- return S_OK;
- }
- STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type)
- {
- debugfunc("%llu, %llu, %ld", offset, size, type);
- /* TODO? */
- return STG_E_INVALIDFUNCTION;
- }
- STDMETHODIMP CaptionStream::UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type)
- {
- debugfunc("%llu, %llu, %ld", offset, size, type);
- /* TODO? */
- return STG_E_INVALIDFUNCTION;
- }
- static const wchar_t *stat_name = L"Caption stream";
- STDMETHODIMP CaptionStream::Stat(STATSTG *stg, DWORD flag)
- {
- debugfunc("stg, %lu", flag);
- if (!stg)
- return E_POINTER;
- lock_guard<mutex> lock(m);
- *stg = {};
- stg->type = STGTY_STREAM;
- stg->cbSize.QuadPart = (ULONGLONG)buf->size;
- if (flag == STATFLAG_DEFAULT) {
- size_t byte_size = (wcslen(stat_name) + 1) * sizeof(wchar_t);
- stg->pwcsName = (wchar_t *)CoTaskMemAlloc(byte_size);
- memcpy(stg->pwcsName, stat_name, byte_size);
- }
- return S_OK;
- }
- STDMETHODIMP CaptionStream::Clone(IStream **stream)
- {
- debugfunc("stream");
- *stream = nullptr;
- return E_NOTIMPL;
- }
- // ISpStreamFormat methods
- STDMETHODIMP CaptionStream::GetFormat(GUID *guid, WAVEFORMATEX **co_mem_wfex_out)
- {
- debugfunc("guid, co_mem_wfex_out");
- if (!guid || !co_mem_wfex_out)
- return E_POINTER;
- if (format.wFormatTag == 0) {
- *co_mem_wfex_out = nullptr;
- return S_OK;
- }
- void *wfex = CoTaskMemAlloc(sizeof(format));
- memcpy(wfex, &format, sizeof(format));
- *co_mem_wfex_out = (WAVEFORMATEX *)wfex;
- return S_OK;
- }
- // ISpAudio methods
- STDMETHODIMP CaptionStream::SetState(SPAUDIOSTATE state_, ULONGLONG)
- {
- debugfunc("%lu, reserved", state_);
- state = state_;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref, const WAVEFORMATEX *wfex)
- {
- debugfunc("guid, wfex");
- if (!wfex)
- return E_INVALIDARG;
- if (guid_ref == SPDFID_WaveFormatEx) {
- lock_guard<mutex> lock(m);
- memcpy(&format, wfex, sizeof(format));
- if (!handler->reset_resampler(AUDIO_FORMAT_16BIT, wfex->nSamplesPerSec))
- return E_FAIL;
- /* 50 msec */
- DWORD size = format.nSamplesPerSec / 20;
- DWORD byte_size = size * format.nBlockAlign;
- deque_reserve(buf, (size_t)byte_size);
- }
- return S_OK;
- }
- STDMETHODIMP CaptionStream::GetStatus(SPAUDIOSTATUS *status)
- {
- debugfunc("status");
- if (!status)
- return E_POINTER;
- /* TODO? */
- lock_guard<mutex> lock(m);
- *status = {};
- status->cbNonBlockingIO = (ULONG)buf->size;
- status->State = state;
- status->CurSeekPos = pos.QuadPart;
- status->CurDevicePos = write_pos;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info_)
- {
- debugfunc("buf_info");
- /* TODO */
- buf_info = *buf_info_;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::GetBufferInfo(SPAUDIOBUFFERINFO *buf_info_)
- {
- debugfunc("buf_info");
- if (!buf_info_)
- return E_POINTER;
- *buf_info_ = buf_info;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format, WAVEFORMATEX **co_mem_wfex_out)
- {
- debugfunc("format, co_mem_wfex_out");
- if (!format || !co_mem_wfex_out)
- return E_POINTER;
- void *wfex = CoTaskMemAlloc(sizeof(format));
- memcpy(wfex, &format, sizeof(format));
- *format = SPDFID_WaveFormatEx;
- *co_mem_wfex_out = (WAVEFORMATEX *)wfex;
- return S_OK;
- }
- STDMETHODIMP_(HANDLE) CaptionStream::EventHandle(void)
- {
- debugfunc("");
- return event;
- }
- STDMETHODIMP CaptionStream::GetVolumeLevel(ULONG *level)
- {
- debugfunc("level");
- if (!level)
- return E_POINTER;
- *level = vol;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::SetVolumeLevel(ULONG level)
- {
- debugfunc("%lu", level);
- vol = level;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::GetBufferNotifySize(ULONG *size)
- {
- debugfunc("size");
- if (!size)
- return E_POINTER;
- *size = notify_size;
- return S_OK;
- }
- STDMETHODIMP CaptionStream::SetBufferNotifySize(ULONG size)
- {
- debugfunc("%lu", size);
- notify_size = size;
- return S_OK;
- }
|