mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-03-29 03:41:53 -04:00
decklink: Add option to select channel format
Closes jp9000/obs-studio#867
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "decklink-device-instance.hpp"
|
||||
#include "audio-repack.hpp"
|
||||
|
||||
#include <util/platform.h>
|
||||
#include <util/threading.h>
|
||||
@@ -8,6 +9,8 @@
|
||||
#define LOG(level, message, ...) blog(level, "%s: " message, \
|
||||
obs_source_get_name(this->decklink->GetSource()), ##__VA_ARGS__)
|
||||
|
||||
#define ISSTEREO(flag) ((flag) == SPEAKERS_STEREO)
|
||||
|
||||
static inline enum video_format ConvertPixelFormat(BMDPixelFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
@@ -20,6 +23,36 @@ static inline enum video_format ConvertPixelFormat(BMDPixelFormat format)
|
||||
return VIDEO_FORMAT_UYVY;
|
||||
}
|
||||
|
||||
static inline int ConvertChannelFormat(speaker_layout format)
|
||||
{
|
||||
switch (format) {
|
||||
case SPEAKERS_5POINT1:
|
||||
case SPEAKERS_5POINT1_SURROUND:
|
||||
case SPEAKERS_7POINT1:
|
||||
return 8;
|
||||
|
||||
default:
|
||||
case SPEAKERS_STEREO:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format)
|
||||
{
|
||||
switch (format) {
|
||||
case SPEAKERS_5POINT1:
|
||||
case SPEAKERS_5POINT1_SURROUND:
|
||||
return repack_mode_8to6ch_swap23;
|
||||
|
||||
case SPEAKERS_7POINT1:
|
||||
return repack_mode_8ch_swap23;
|
||||
|
||||
default:
|
||||
assert(false && "No repack requested");
|
||||
return (audio_repack_mode_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
DeckLinkDeviceInstance::DeckLinkDeviceInstance(DeckLink *decklink_,
|
||||
DeckLinkDevice *device_) :
|
||||
currentFrame(), currentPacket(), decklink(decklink_), device(device_)
|
||||
@@ -46,9 +79,20 @@ void DeckLinkDeviceInstance::HandleAudioPacket(
|
||||
return;
|
||||
}
|
||||
|
||||
currentPacket.data[0] = (uint8_t *)bytes;
|
||||
currentPacket.frames = (uint32_t)audioPacket->GetSampleFrameCount();
|
||||
currentPacket.timestamp = timestamp;
|
||||
const uint32_t frameCount = (uint32_t)audioPacket->GetSampleFrameCount();
|
||||
currentPacket.frames = frameCount;
|
||||
currentPacket.timestamp = timestamp;
|
||||
|
||||
if (!ISSTEREO(channelFormat)) {
|
||||
if (audioRepacker->repack((uint8_t *)bytes, frameCount) < 0) {
|
||||
LOG(LOG_ERROR, "Failed to convert audio packet data");
|
||||
return;
|
||||
}
|
||||
|
||||
currentPacket.data[0] = (*audioRepacker)->packet_buffer;
|
||||
} else {
|
||||
currentPacket.data[0] = (uint8_t *)bytes;
|
||||
}
|
||||
|
||||
obs_source_output_audio(decklink->GetSource(), ¤tPacket);
|
||||
}
|
||||
@@ -78,6 +122,19 @@ void DeckLinkDeviceInstance::HandleVideoFrame(
|
||||
obs_source_output_video(decklink->GetSource(), ¤tFrame);
|
||||
}
|
||||
|
||||
void DeckLinkDeviceInstance::FinalizeStream()
|
||||
{
|
||||
input->SetCallback(nullptr);
|
||||
|
||||
if (audioRepacker != nullptr)
|
||||
{
|
||||
delete audioRepacker;
|
||||
audioRepacker = nullptr;
|
||||
}
|
||||
|
||||
mode = nullptr;
|
||||
}
|
||||
|
||||
bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
|
||||
{
|
||||
if (mode != nullptr)
|
||||
@@ -93,8 +150,6 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
|
||||
pixelFormat = decklink->GetPixelFormat();
|
||||
currentFrame.format = ConvertPixelFormat(pixelFormat);
|
||||
|
||||
input->SetCallback(this);
|
||||
|
||||
const BMDDisplayMode displayMode = mode_->GetDisplayMode();
|
||||
|
||||
const HRESULT videoResult = input->EnableVideoInput(displayMode,
|
||||
@@ -102,22 +157,36 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
|
||||
|
||||
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);
|
||||
channelFormat = decklink->GetChannelFormat();
|
||||
currentPacket.speakers = channelFormat;
|
||||
|
||||
if (audioResult != S_OK)
|
||||
LOG(LOG_WARNING, "Failed to enable audio input; continuing...");
|
||||
if (channelFormat != SPEAKERS_UNKNOWN) {
|
||||
const int channel = ConvertChannelFormat(channelFormat);
|
||||
const HRESULT audioResult = input->EnableAudioInput(
|
||||
bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
|
||||
channel);
|
||||
|
||||
if (audioResult != S_OK)
|
||||
LOG(LOG_WARNING, "Failed to enable audio input; continuing...");
|
||||
|
||||
if (!ISSTEREO(channelFormat)) {
|
||||
const audio_repack_mode_t repack_mode = ConvertRepackFormat(channelFormat);
|
||||
audioRepacker = new AudioRepacker(repack_mode);
|
||||
}
|
||||
}
|
||||
|
||||
if (input->SetCallback(this) != S_OK) {
|
||||
LOG(LOG_ERROR, "Failed to set callback");
|
||||
FinalizeStream();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input->StartStreams() != S_OK) {
|
||||
LOG(LOG_ERROR, "Failed to start streams");
|
||||
input->SetCallback(nullptr);
|
||||
input->DisableVideoInput();
|
||||
input->DisableAudioInput();
|
||||
FinalizeStream();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -135,11 +204,7 @@ bool DeckLinkDeviceInstance::StopCapture(void)
|
||||
GetDevice()->GetDisplayName().c_str());
|
||||
|
||||
input->StopStreams();
|
||||
input->SetCallback(nullptr);
|
||||
input->DisableVideoInput();
|
||||
input->DisableAudioInput();
|
||||
|
||||
mode = nullptr;
|
||||
FinalizeStream();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user