123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- #include "decklink-device-instance.hpp"
- #include <util/platform.h>
- #include <util/threading.h>
- #include <sstream>
- #define LOG(level, message, ...) blog(level, "%s: " message, \
- obs_source_get_name(this->decklink->GetSource()), ##__VA_ARGS__)
- DeckLinkDeviceInstance::DeckLinkDeviceInstance(DeckLink *decklink_,
- DeckLinkDevice *device_) :
- currentFrame(), currentPacket(), decklink(decklink_), device(device_)
- {
- currentFrame.format = VIDEO_FORMAT_UYVY;
- currentPacket.samples_per_sec = 48000;
- currentPacket.speakers = SPEAKERS_STEREO;
- currentPacket.format = AUDIO_FORMAT_16BIT;
- }
- void DeckLinkDeviceInstance::HandleAudioPacket(
- IDeckLinkAudioInputPacket *audioPacket,
- const uint64_t timestamp)
- {
- if (audioPacket == nullptr)
- return;
- void *bytes;
- if (audioPacket->GetBytes(&bytes) != S_OK) {
- LOG(LOG_WARNING, "Failed to get audio packet data");
- return;
- }
- currentPacket.data[0] = (uint8_t *)bytes;
- currentPacket.frames = (uint32_t)audioPacket->GetSampleFrameCount();
- currentPacket.timestamp = timestamp;
- obs_source_output_audio(decklink->GetSource(), ¤tPacket);
- }
- void DeckLinkDeviceInstance::HandleVideoFrame(
- IDeckLinkVideoInputFrame *videoFrame, const uint64_t timestamp)
- {
- if (videoFrame == nullptr)
- return;
- void *bytes;
- if (videoFrame->GetBytes(&bytes) != S_OK) {
- LOG(LOG_WARNING, "Failed to get video frame data");
- return;
- }
- currentFrame.data[0] = (uint8_t *)bytes;
- currentFrame.linesize[0] = (uint32_t)videoFrame->GetRowBytes();
- currentFrame.width = (uint32_t)videoFrame->GetWidth();
- currentFrame.height = (uint32_t)videoFrame->GetHeight();
- currentFrame.timestamp = timestamp;
- video_format_get_parameters(VIDEO_CS_601, VIDEO_RANGE_PARTIAL,
- currentFrame.color_matrix, currentFrame.color_range_min,
- currentFrame.color_range_max);
- obs_source_output_video(decklink->GetSource(), ¤tFrame);
- }
- bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
- {
- if (mode != nullptr)
- return false;
- if (mode_ == nullptr)
- return false;
- LOG(LOG_INFO, "Starting capture...");
- if (!device->GetInput(&input))
- return false;
- input->SetCallback(this);
- const BMDDisplayMode displayMode = mode_->GetDisplayMode();
- const HRESULT videoResult = input->EnableVideoInput(displayMode,
- bmdFormat8BitYUV, bmdVideoInputFlagDefault);
- if (videoResult != S_OK) {
- LOG(LOG_ERROR, "Failed to enable video input");
- input->SetCallback(nullptr);
- return false;
- }
- const HRESULT audioResult = input->EnableAudioInput(
- bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
- 2);
- if (audioResult != S_OK)
- LOG(LOG_WARNING, "Failed to enable audio input; continuing...");
- if (input->StartStreams() != S_OK) {
- LOG(LOG_ERROR, "Failed to start streams");
- input->SetCallback(nullptr);
- input->DisableVideoInput();
- input->DisableAudioInput();
- return false;
- }
- mode = mode_;
- return true;
- }
- bool DeckLinkDeviceInstance::StopCapture(void)
- {
- if (mode == nullptr || input == nullptr)
- return false;
- LOG(LOG_INFO, "Stopping capture of '%s'...",
- GetDevice()->GetDisplayName().c_str());
- input->StopStreams();
- input->SetCallback(nullptr);
- input->DisableVideoInput();
- input->DisableAudioInput();
- mode = nullptr;
- return true;
- }
- HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFrameArrived(
- IDeckLinkVideoInputFrame *videoFrame,
- IDeckLinkAudioInputPacket *audioPacket)
- {
- const uint64_t timestamp = os_gettime_ns();
- HandleVideoFrame(videoFrame, timestamp);
- HandleAudioPacket(audioPacket, timestamp);
- return S_OK;
- }
- HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFormatChanged(
- BMDVideoInputFormatChangedEvents events,
- IDeckLinkDisplayMode *newMode,
- BMDDetectedVideoInputFormatFlags detectedSignalFlags)
- {
- UNUSED_PARAMETER(events);
- UNUSED_PARAMETER(newMode);
- UNUSED_PARAMETER(detectedSignalFlags);
- // There is no implementation for automatic format detection, so this
- // method goes unused.
- return S_OK;
- }
- ULONG STDMETHODCALLTYPE DeckLinkDeviceInstance::AddRef(void)
- {
- return os_atomic_inc_long(&refCount);
- }
- HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::QueryInterface(REFIID iid,
- LPVOID *ppv)
- {
- HRESULT result = E_NOINTERFACE;
- *ppv = nullptr;
- CFUUIDBytes unknown = CFUUIDGetUUIDBytes(IUnknownUUID);
- if (memcmp(&iid, &unknown, sizeof(REFIID)) == 0) {
- *ppv = this;
- AddRef();
- result = S_OK;
- } else if (memcmp(&iid, &IID_IDeckLinkNotificationCallback,
- sizeof(REFIID)) == 0) {
- *ppv = (IDeckLinkNotificationCallback *)this;
- AddRef();
- result = S_OK;
- }
- return result;
- }
- ULONG STDMETHODCALLTYPE DeckLinkDeviceInstance::Release(void)
- {
- const long newRefCount = os_atomic_dec_long(&refCount);
- if (newRefCount == 0) {
- delete this;
- return 0;
- }
- return newRefCount;
- }
|