decklink-device-instance.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. #include "decklink-device-instance.hpp"
  2. #include "audio-repack.hpp"
  3. #include "DecklinkInput.hpp"
  4. #include "DecklinkOutput.hpp"
  5. #include <util/platform.h>
  6. #include <util/threading.h>
  7. #include <sstream>
  8. #include <algorithm>
  9. #ifdef _WIN32
  10. #define IS_WIN 1
  11. #else
  12. #define IS_WIN 0
  13. #endif
  14. static inline enum video_format ConvertPixelFormat(BMDPixelFormat format)
  15. {
  16. switch (format) {
  17. case bmdFormat8BitBGRA: return VIDEO_FORMAT_BGRX;
  18. default:
  19. case bmdFormat8BitYUV:;
  20. }
  21. return VIDEO_FORMAT_UYVY;
  22. }
  23. static inline int ConvertChannelFormat(speaker_layout format)
  24. {
  25. switch (format) {
  26. case SPEAKERS_2POINT1:
  27. case SPEAKERS_4POINT0:
  28. case SPEAKERS_4POINT1:
  29. case SPEAKERS_5POINT1:
  30. case SPEAKERS_7POINT1:
  31. return 8;
  32. default:
  33. case SPEAKERS_STEREO:
  34. return 2;
  35. }
  36. }
  37. static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format)
  38. {
  39. switch (format) {
  40. case SPEAKERS_2POINT1:
  41. return repack_mode_8to3ch_swap23;
  42. case SPEAKERS_4POINT0:
  43. return repack_mode_8to4ch_swap23;
  44. case SPEAKERS_4POINT1:
  45. return repack_mode_8to5ch_swap23;
  46. case SPEAKERS_5POINT1:
  47. return repack_mode_8to6ch_swap23;
  48. case SPEAKERS_7POINT1:
  49. return repack_mode_8ch_swap23_swap46_swap57;
  50. default:
  51. assert(false && "No repack requested");
  52. return (audio_repack_mode_t)-1;
  53. }
  54. }
  55. DeckLinkDeviceInstance::DeckLinkDeviceInstance(DecklinkBase *decklink_,
  56. DeckLinkDevice *device_) :
  57. currentFrame(), currentPacket(), decklink(decklink_), device(device_)
  58. {
  59. currentPacket.samples_per_sec = 48000;
  60. currentPacket.speakers = SPEAKERS_STEREO;
  61. currentPacket.format = AUDIO_FORMAT_16BIT;
  62. }
  63. DeckLinkDeviceInstance::~DeckLinkDeviceInstance()
  64. {
  65. }
  66. void DeckLinkDeviceInstance::HandleAudioPacket(
  67. IDeckLinkAudioInputPacket *audioPacket,
  68. const uint64_t timestamp)
  69. {
  70. if (audioPacket == nullptr)
  71. return;
  72. void *bytes;
  73. if (audioPacket->GetBytes(&bytes) != S_OK) {
  74. LOG(LOG_WARNING, "Failed to get audio packet data");
  75. return;
  76. }
  77. const uint32_t frameCount = (uint32_t)audioPacket->GetSampleFrameCount();
  78. currentPacket.frames = frameCount;
  79. currentPacket.timestamp = timestamp;
  80. if (decklink && !static_cast<DeckLinkInput*>(decklink)->buffering) {
  81. currentPacket.timestamp = os_gettime_ns();
  82. currentPacket.timestamp -=
  83. (uint64_t)frameCount * 1000000000ULL /
  84. (uint64_t)currentPacket.samples_per_sec;
  85. }
  86. int maxdevicechannel = device->GetMaxChannel();
  87. bool isWin = IS_WIN;
  88. if (channelFormat != SPEAKERS_UNKNOWN &&
  89. channelFormat != SPEAKERS_MONO &&
  90. channelFormat != SPEAKERS_STEREO &&
  91. maxdevicechannel >= 8 &&
  92. isWin) {
  93. if (audioRepacker->repack((uint8_t *)bytes, frameCount) < 0) {
  94. LOG(LOG_ERROR, "Failed to convert audio packet data");
  95. return;
  96. }
  97. currentPacket.data[0] = (*audioRepacker)->packet_buffer;
  98. } else {
  99. currentPacket.data[0] = (uint8_t *)bytes;
  100. }
  101. nextAudioTS = timestamp +
  102. ((uint64_t)frameCount * 1000000000ULL / 48000ULL) + 1;
  103. obs_source_output_audio(static_cast<DeckLinkInput*>(decklink)->GetSource(), &currentPacket);
  104. }
  105. void DeckLinkDeviceInstance::HandleVideoFrame(
  106. IDeckLinkVideoInputFrame *videoFrame, const uint64_t timestamp)
  107. {
  108. if (videoFrame == nullptr)
  109. return;
  110. void *bytes;
  111. if (videoFrame->GetBytes(&bytes) != S_OK) {
  112. LOG(LOG_WARNING, "Failed to get video frame data");
  113. return;
  114. }
  115. currentFrame.data[0] = (uint8_t *)bytes;
  116. currentFrame.linesize[0] = (uint32_t)videoFrame->GetRowBytes();
  117. currentFrame.width = (uint32_t)videoFrame->GetWidth();
  118. currentFrame.height = (uint32_t)videoFrame->GetHeight();
  119. currentFrame.timestamp = timestamp;
  120. obs_source_output_video(static_cast<DeckLinkInput*>(decklink)->GetSource(), &currentFrame);
  121. }
  122. void DeckLinkDeviceInstance::FinalizeStream()
  123. {
  124. input->SetCallback(nullptr);
  125. input->DisableVideoInput();
  126. if (channelFormat != SPEAKERS_UNKNOWN)
  127. input->DisableAudioInput();
  128. if (audioRepacker != nullptr)
  129. {
  130. delete audioRepacker;
  131. audioRepacker = nullptr;
  132. }
  133. mode = nullptr;
  134. }
  135. //#define LOG_SETUP_VIDEO_FORMAT 1
  136. void DeckLinkDeviceInstance::SetupVideoFormat(DeckLinkDeviceMode *mode_)
  137. {
  138. if (mode_ == nullptr)
  139. return;
  140. currentFrame.format = ConvertPixelFormat(pixelFormat);
  141. colorSpace = static_cast<DeckLinkInput*>(decklink)->GetColorSpace();
  142. if (colorSpace == VIDEO_CS_DEFAULT) {
  143. const BMDDisplayModeFlags flags = mode_->GetDisplayModeFlags();
  144. if (flags & bmdDisplayModeColorspaceRec709)
  145. activeColorSpace = VIDEO_CS_709;
  146. else if (flags & bmdDisplayModeColorspaceRec601)
  147. activeColorSpace = VIDEO_CS_601;
  148. else
  149. activeColorSpace = VIDEO_CS_DEFAULT;
  150. } else {
  151. activeColorSpace = colorSpace;
  152. }
  153. colorRange = static_cast<DeckLinkInput*>(decklink)->GetColorRange();
  154. currentFrame.full_range = colorRange == VIDEO_RANGE_FULL;
  155. video_format_get_parameters(activeColorSpace, colorRange,
  156. currentFrame.color_matrix, currentFrame.color_range_min,
  157. currentFrame.color_range_max);
  158. #ifdef LOG_SETUP_VIDEO_FORMAT
  159. LOG(LOG_INFO, "Setup video format: %s, %s, %s",
  160. pixelFormat == bmdFormat8BitYUV ? "YUV" : "RGB",
  161. activeColorSpace == VIDEO_CS_709 ? "BT.709" : "BT.601",
  162. colorRange == VIDEO_RANGE_FULL ? "full" : "limited");
  163. #endif
  164. }
  165. bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
  166. {
  167. if (mode != nullptr)
  168. return false;
  169. if (mode_ == nullptr)
  170. return false;
  171. LOG(LOG_INFO, "Starting capture...");
  172. if (!device->GetInput(&input))
  173. return false;
  174. BMDVideoInputFlags flags;
  175. bool isauto = mode_->GetName() == "Auto";
  176. if (isauto) {
  177. displayMode = bmdModeNTSC;
  178. pixelFormat = bmdFormat8BitYUV;
  179. flags = bmdVideoInputEnableFormatDetection;
  180. } else {
  181. displayMode = mode_->GetDisplayMode();
  182. pixelFormat = static_cast<DeckLinkInput*>(decklink)->GetPixelFormat();
  183. flags = bmdVideoInputFlagDefault;
  184. }
  185. const HRESULT videoResult = input->EnableVideoInput(displayMode,
  186. pixelFormat, flags);
  187. if (videoResult != S_OK) {
  188. LOG(LOG_ERROR, "Failed to enable video input");
  189. return false;
  190. }
  191. SetupVideoFormat(mode_);
  192. channelFormat = static_cast<DeckLinkInput*>(decklink)->GetChannelFormat();
  193. currentPacket.speakers = channelFormat;
  194. int maxdevicechannel = device->GetMaxChannel();
  195. bool isWin = IS_WIN;
  196. if (channelFormat != SPEAKERS_UNKNOWN) {
  197. const int channel = ConvertChannelFormat(channelFormat);
  198. const HRESULT audioResult = input->EnableAudioInput(
  199. bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
  200. channel);
  201. if (audioResult != S_OK)
  202. LOG(LOG_WARNING, "Failed to enable audio input; continuing...");
  203. if (channelFormat != SPEAKERS_UNKNOWN &&
  204. channelFormat != SPEAKERS_MONO &&
  205. channelFormat != SPEAKERS_STEREO &&
  206. maxdevicechannel >= 8 &&
  207. isWin) {
  208. const audio_repack_mode_t repack_mode = ConvertRepackFormat
  209. (channelFormat);
  210. audioRepacker = new AudioRepacker(repack_mode);
  211. }
  212. }
  213. if (input->SetCallback(this) != S_OK) {
  214. LOG(LOG_ERROR, "Failed to set callback");
  215. FinalizeStream();
  216. return false;
  217. }
  218. if (input->StartStreams() != S_OK) {
  219. LOG(LOG_ERROR, "Failed to start streams");
  220. FinalizeStream();
  221. return false;
  222. }
  223. mode = mode_;
  224. return true;
  225. }
  226. bool DeckLinkDeviceInstance::StopCapture(void)
  227. {
  228. if (mode == nullptr || input == nullptr)
  229. return false;
  230. LOG(LOG_INFO, "Stopping capture of '%s'...",
  231. GetDevice()->GetDisplayName().c_str());
  232. input->StopStreams();
  233. FinalizeStream();
  234. return true;
  235. }
  236. bool DeckLinkDeviceInstance::StartOutput(DeckLinkDeviceMode *mode_)
  237. {
  238. if (mode != nullptr)
  239. return false;
  240. if (mode_ == nullptr)
  241. return false;
  242. LOG(LOG_INFO, "Starting output...");
  243. if (!device->GetOutput(&output))
  244. return false;
  245. const HRESULT videoResult = output->EnableVideoOutput(
  246. mode_->GetDisplayMode(),
  247. bmdVideoOutputFlagDefault);
  248. if (videoResult != S_OK) {
  249. LOG(LOG_ERROR, "Failed to enable video output");
  250. return false;
  251. }
  252. const HRESULT audioResult = output->EnableAudioOutput(
  253. bmdAudioSampleRate48kHz,
  254. bmdAudioSampleType16bitInteger,
  255. 2,
  256. bmdAudioOutputStreamTimestamped);
  257. if (audioResult != S_OK) {
  258. LOG(LOG_ERROR, "Failed to enable audio output");
  259. return false;
  260. }
  261. mode = mode_;
  262. auto decklinkOutput = dynamic_cast<DeckLinkOutput*>(decklink);
  263. if (decklinkOutput == nullptr)
  264. return false;
  265. HRESULT result;
  266. result = output->CreateVideoFrame(decklinkOutput->GetWidth(),
  267. decklinkOutput->GetHeight(),
  268. decklinkOutput->GetWidth() * 2,
  269. bmdFormat8BitYUV,
  270. bmdFrameFlagDefault,
  271. &decklinkOutputFrame);
  272. if (result != S_OK) {
  273. blog(LOG_ERROR ,"failed to make frame 0x%X", result);
  274. return false;
  275. }
  276. return true;
  277. }
  278. bool DeckLinkDeviceInstance::StopOutput()
  279. {
  280. if (mode == nullptr || output == nullptr)
  281. return false;
  282. LOG(LOG_INFO, "Stopping output of '%s'...",
  283. GetDevice()->GetDisplayName().c_str());
  284. output->DisableVideoOutput();
  285. output->DisableAudioOutput();
  286. if (decklinkOutputFrame != nullptr) {
  287. decklinkOutputFrame->Release();
  288. decklinkOutputFrame = nullptr;
  289. }
  290. return true;
  291. }
  292. void DeckLinkDeviceInstance::DisplayVideoFrame(video_data *frame)
  293. {
  294. auto decklinkOutput = dynamic_cast<DeckLinkOutput*>(decklink);
  295. if (decklinkOutput == nullptr)
  296. return;
  297. uint8_t *destData;
  298. decklinkOutputFrame->GetBytes((void**)&destData);
  299. uint8_t *outData = frame->data[0];
  300. std::copy(outData, outData + (decklinkOutput->GetWidth() *
  301. decklinkOutput->GetHeight() * 2), destData);
  302. output->DisplayVideoFrameSync(decklinkOutputFrame);
  303. }
  304. void DeckLinkDeviceInstance::WriteAudio(audio_data *frames)
  305. {
  306. uint32_t sampleFramesWritten;
  307. output->WriteAudioSamplesSync(frames->data[0],
  308. frames->frames,
  309. &sampleFramesWritten);
  310. }
  311. #define TIME_BASE 1000000000
  312. HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFrameArrived(
  313. IDeckLinkVideoInputFrame *videoFrame,
  314. IDeckLinkAudioInputPacket *audioPacket)
  315. {
  316. BMDTimeValue videoTS = 0;
  317. BMDTimeValue videoDur = 0;
  318. BMDTimeValue audioTS = 0;
  319. if (videoFrame) {
  320. videoFrame->GetStreamTime(&videoTS, &videoDur, TIME_BASE);
  321. lastVideoTS = (uint64_t)videoTS;
  322. }
  323. if (audioPacket) {
  324. BMDTimeValue newAudioTS = 0;
  325. int64_t diff;
  326. audioPacket->GetPacketTime(&newAudioTS, TIME_BASE);
  327. audioTS = newAudioTS + audioOffset;
  328. diff = (int64_t)audioTS - (int64_t)nextAudioTS;
  329. if (diff > 10000000LL) {
  330. audioOffset -= diff;
  331. audioTS = newAudioTS + audioOffset;
  332. } else if (diff < -1000000) {
  333. audioOffset = 0;
  334. audioTS = newAudioTS;
  335. }
  336. }
  337. if (videoFrame && videoTS >= 0)
  338. HandleVideoFrame(videoFrame, (uint64_t)videoTS);
  339. if (audioPacket && audioTS >= 0)
  340. HandleAudioPacket(audioPacket, (uint64_t)audioTS);
  341. return S_OK;
  342. }
  343. HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFormatChanged(
  344. BMDVideoInputFormatChangedEvents events,
  345. IDeckLinkDisplayMode *newMode,
  346. BMDDetectedVideoInputFormatFlags detectedSignalFlags)
  347. {
  348. input->PauseStreams();
  349. mode->SetMode(newMode);
  350. if (events & bmdVideoInputDisplayModeChanged) {
  351. displayMode = mode->GetDisplayMode();
  352. }
  353. if (events & bmdVideoInputColorspaceChanged) {
  354. switch (detectedSignalFlags) {
  355. case bmdDetectedVideoInputRGB444:
  356. pixelFormat = bmdFormat8BitBGRA;
  357. break;
  358. default:
  359. case bmdDetectedVideoInputYCbCr422:
  360. pixelFormat = bmdFormat8BitYUV;
  361. break;
  362. }
  363. }
  364. const HRESULT videoResult = input->EnableVideoInput(displayMode,
  365. pixelFormat, bmdVideoInputEnableFormatDetection);
  366. if (videoResult != S_OK) {
  367. LOG(LOG_ERROR, "Failed to enable video input");
  368. input->StopStreams();
  369. FinalizeStream();
  370. return E_FAIL;
  371. }
  372. SetupVideoFormat(mode);
  373. input->FlushStreams();
  374. input->StartStreams();
  375. return S_OK;
  376. }
  377. ULONG STDMETHODCALLTYPE DeckLinkDeviceInstance::AddRef(void)
  378. {
  379. return os_atomic_inc_long(&refCount);
  380. }
  381. HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::QueryInterface(REFIID iid,
  382. LPVOID *ppv)
  383. {
  384. HRESULT result = E_NOINTERFACE;
  385. *ppv = nullptr;
  386. CFUUIDBytes unknown = CFUUIDGetUUIDBytes(IUnknownUUID);
  387. if (memcmp(&iid, &unknown, sizeof(REFIID)) == 0) {
  388. *ppv = this;
  389. AddRef();
  390. result = S_OK;
  391. } else if (memcmp(&iid, &IID_IDeckLinkNotificationCallback,
  392. sizeof(REFIID)) == 0) {
  393. *ppv = (IDeckLinkNotificationCallback *)this;
  394. AddRef();
  395. result = S_OK;
  396. }
  397. return result;
  398. }
  399. ULONG STDMETHODCALLTYPE DeckLinkDeviceInstance::Release(void)
  400. {
  401. const long newRefCount = os_atomic_dec_long(&refCount);
  402. if (newRefCount == 0) {
  403. delete this;
  404. return 0;
  405. }
  406. return newRefCount;
  407. }