1
0

decklink-device-instance.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  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 <util/util_uint64.h>
  8. #include <sstream>
  9. #include <iomanip>
  10. #include <algorithm>
  11. #include "OBSVideoFrame.h"
  12. #include <caption/caption.h>
  13. #include <util/bitstream.h>
  14. template<typename T> RenderDelegate<T>::RenderDelegate(T *pOwner)
  15. {
  16. m_pOwner = pOwner;
  17. }
  18. template<typename T> RenderDelegate<T>::~RenderDelegate() {}
  19. template<typename T> HRESULT RenderDelegate<T>::QueryInterface(REFIID, LPVOID *ppv)
  20. {
  21. *ppv = NULL;
  22. return E_NOINTERFACE;
  23. }
  24. template<typename T> ULONG RenderDelegate<T>::AddRef()
  25. {
  26. return ++m_refCount;
  27. }
  28. template<typename T> ULONG RenderDelegate<T>::Release()
  29. {
  30. const ULONG newRefValue = --m_refCount;
  31. if (newRefValue == 0) {
  32. delete this;
  33. return 0;
  34. }
  35. return newRefValue;
  36. }
  37. template<typename T>
  38. HRESULT RenderDelegate<T>::ScheduledFrameCompleted(IDeckLinkVideoFrame *completedFrame, BMDOutputFrameCompletionResult)
  39. {
  40. m_pOwner->ScheduleVideoFrame(completedFrame);
  41. return S_OK;
  42. }
  43. template<typename T> HRESULT RenderDelegate<T>::ScheduledPlaybackHasStopped()
  44. {
  45. return S_OK;
  46. }
  47. static inline enum video_format ConvertPixelFormat(BMDPixelFormat format)
  48. {
  49. switch (format) {
  50. case bmdFormat8BitBGRA:
  51. return VIDEO_FORMAT_BGRX;
  52. case bmdFormat10BitRGBXLE:
  53. return VIDEO_FORMAT_R10L;
  54. case bmdFormat10BitYUV:
  55. return VIDEO_FORMAT_V210;
  56. default:
  57. case bmdFormat8BitYUV:
  58. return VIDEO_FORMAT_UYVY;
  59. }
  60. }
  61. static inline int ConvertChannelFormat(speaker_layout format)
  62. {
  63. switch (format) {
  64. case SPEAKERS_2POINT1:
  65. case SPEAKERS_4POINT0:
  66. case SPEAKERS_4POINT1:
  67. case SPEAKERS_5POINT1:
  68. case SPEAKERS_7POINT1:
  69. return 8;
  70. default:
  71. case SPEAKERS_STEREO:
  72. return 2;
  73. }
  74. }
  75. static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format, bool swap)
  76. {
  77. switch (format) {
  78. case SPEAKERS_2POINT1:
  79. return repack_mode_8to3ch;
  80. case SPEAKERS_4POINT0:
  81. return repack_mode_8to4ch;
  82. case SPEAKERS_4POINT1:
  83. return swap ? repack_mode_8to5ch_swap : repack_mode_8to5ch;
  84. case SPEAKERS_5POINT1:
  85. return swap ? repack_mode_8to6ch_swap : repack_mode_8to6ch;
  86. case SPEAKERS_7POINT1:
  87. return swap ? repack_mode_8ch_swap : repack_mode_8ch;
  88. default:
  89. assert(false && "No repack requested");
  90. return (audio_repack_mode_t)-1;
  91. }
  92. }
  93. DeckLinkDeviceInstance::DeckLinkDeviceInstance(DecklinkBase *decklink_, DeckLinkDevice *device_)
  94. : currentFrame(),
  95. currentPacket(),
  96. currentCaptions(),
  97. decklink(decklink_),
  98. device(device_)
  99. {
  100. currentPacket.samples_per_sec = 48000;
  101. currentPacket.speakers = SPEAKERS_STEREO;
  102. currentPacket.format = AUDIO_FORMAT_16BIT;
  103. }
  104. DeckLinkDeviceInstance::~DeckLinkDeviceInstance()
  105. {
  106. if (convertFrame) {
  107. delete convertFrame;
  108. }
  109. }
  110. void DeckLinkDeviceInstance::HandleAudioPacket(IDeckLinkAudioInputPacket *audioPacket, const uint64_t timestamp)
  111. {
  112. if (audioPacket == nullptr)
  113. return;
  114. void *bytes;
  115. if (audioPacket->GetBytes(&bytes) != S_OK) {
  116. LOG(LOG_WARNING, "Failed to get audio packet data");
  117. return;
  118. }
  119. const uint32_t frameCount = (uint32_t)audioPacket->GetSampleFrameCount();
  120. currentPacket.frames = frameCount;
  121. currentPacket.timestamp = timestamp;
  122. if (decklink && !static_cast<DeckLinkInput *>(decklink)->buffering) {
  123. currentPacket.timestamp = os_gettime_ns();
  124. currentPacket.timestamp -= util_mul_div64(frameCount, 1000000000ULL, currentPacket.samples_per_sec);
  125. }
  126. int maxdevicechannel = device->GetMaxChannel();
  127. if (channelFormat != SPEAKERS_UNKNOWN && channelFormat != SPEAKERS_MONO && channelFormat != SPEAKERS_STEREO &&
  128. (channelFormat != SPEAKERS_7POINT1 || static_cast<DeckLinkInput *>(decklink)->swap) &&
  129. maxdevicechannel >= 8) {
  130. if (audioRepacker->repack((uint8_t *)bytes, frameCount) < 0) {
  131. LOG(LOG_ERROR, "Failed to convert audio packet data");
  132. return;
  133. }
  134. currentPacket.data[0] = (*audioRepacker)->packet_buffer;
  135. } else {
  136. currentPacket.data[0] = (uint8_t *)bytes;
  137. }
  138. nextAudioTS = timestamp + util_mul_div64(frameCount, 1000000000ULL, 48000ULL) + 1;
  139. obs_source_output_audio(static_cast<DeckLinkInput *>(decklink)->GetSource(), &currentPacket);
  140. }
  141. void DeckLinkDeviceInstance::HandleVideoFrame(IDeckLinkVideoInputFrame *videoFrame, const uint64_t timestamp)
  142. {
  143. if (videoFrame == nullptr)
  144. return;
  145. ComPtr<IDeckLinkVideoFrameAncillaryPackets> packets;
  146. if (videoFrame->QueryInterface(IID_IDeckLinkVideoFrameAncillaryPackets, (void **)&packets) == S_OK) {
  147. ComPtr<IDeckLinkAncillaryPacketIterator> iterator;
  148. packets->GetPacketIterator(&iterator);
  149. ComPtr<IDeckLinkAncillaryPacket> packet;
  150. iterator->Next(&packet);
  151. if (packet) {
  152. auto did = packet->GetDID();
  153. auto sdid = packet->GetSDID();
  154. // Caption data
  155. if (did == 0x61 && sdid == 0x01) {
  156. this->HandleCaptionPacket(packet, timestamp);
  157. }
  158. }
  159. }
  160. ComPtr<IDeckLinkVideoFrame> frame;
  161. if (videoFrame->GetPixelFormat() != convertFrame->GetPixelFormat()) {
  162. ComPtr<IDeckLinkVideoConversion> frameConverter;
  163. frameConverter.Set(CreateVideoConversionInstance());
  164. frameConverter->ConvertFrame(videoFrame, convertFrame);
  165. frame = convertFrame;
  166. } else {
  167. frame = videoFrame;
  168. }
  169. void *bytes;
  170. if (frame->GetBytes(&bytes) != S_OK) {
  171. LOG(LOG_WARNING, "Failed to get video frame data");
  172. return;
  173. }
  174. currentFrame.data[0] = (uint8_t *)bytes;
  175. currentFrame.linesize[0] = (uint32_t)frame->GetRowBytes();
  176. currentFrame.width = (uint32_t)frame->GetWidth();
  177. currentFrame.height = (uint32_t)frame->GetHeight();
  178. currentFrame.timestamp = timestamp;
  179. if (currentFrame.width == 0 || currentFrame.height == 0)
  180. return;
  181. enum video_trc trc = VIDEO_TRC_DEFAULT;
  182. if (frame->GetFlags() & bmdFrameContainsHDRMetadata) {
  183. ComPtr<IDeckLinkVideoFrameMetadataExtensions> metadata;
  184. if (SUCCEEDED(videoFrame->QueryInterface(IID_IDeckLinkVideoFrameMetadataExtensions,
  185. (void **)&metadata))) {
  186. int64_t range;
  187. if (SUCCEEDED(
  188. metadata->GetInt(bmdDeckLinkFrameMetadataHDRElectroOpticalTransferFunc, &range))) {
  189. switch (range) {
  190. case 2:
  191. trc = VIDEO_TRC_PQ;
  192. break;
  193. case 3:
  194. trc = VIDEO_TRC_HLG;
  195. break;
  196. default:
  197. trc = VIDEO_TRC_DEFAULT;
  198. break;
  199. }
  200. }
  201. }
  202. }
  203. currentFrame.trc = trc;
  204. obs_source_output_video2(static_cast<DeckLinkInput *>(decklink)->GetSource(), &currentFrame);
  205. }
  206. void DeckLinkDeviceInstance::HandleCaptionPacket(IDeckLinkAncillaryPacket *packet, const uint64_t timestamp)
  207. {
  208. const void *data;
  209. uint32_t size;
  210. packet->GetBytes(bmdAncillaryPacketFormatUInt8, &data, &size);
  211. auto anc = (uint8_t *)data;
  212. struct bitstream_reader reader;
  213. bitstream_reader_init(&reader, anc, size);
  214. // header1
  215. bitstream_reader_r8(&reader);
  216. // header2
  217. bitstream_reader_r8(&reader);
  218. // length
  219. bitstream_reader_r8(&reader);
  220. // frameRate
  221. bitstream_reader_read_bits(&reader, 4);
  222. //reserved
  223. bitstream_reader_read_bits(&reader, 4);
  224. auto cdp_timecode_added = bitstream_reader_read_bits(&reader, 1);
  225. // cdp_data_block_added
  226. bitstream_reader_read_bits(&reader, 1);
  227. // cdp_service_info_added
  228. bitstream_reader_read_bits(&reader, 1);
  229. // cdp_service_info_start
  230. bitstream_reader_read_bits(&reader, 1);
  231. // cdp_service_info_changed
  232. bitstream_reader_read_bits(&reader, 1);
  233. // cdp_service_info_end
  234. bitstream_reader_read_bits(&reader, 1);
  235. auto cdp_contains_captions = bitstream_reader_read_bits(&reader, 1);
  236. //reserved
  237. bitstream_reader_read_bits(&reader, 1);
  238. // cdp_counter
  239. bitstream_reader_r8(&reader);
  240. // cdp_counter2
  241. bitstream_reader_r8(&reader);
  242. if (cdp_timecode_added) {
  243. // timecodeSectionID
  244. bitstream_reader_r8(&reader);
  245. //reserved
  246. bitstream_reader_read_bits(&reader, 2);
  247. bitstream_reader_read_bits(&reader, 2);
  248. bitstream_reader_read_bits(&reader, 4);
  249. // reserved
  250. bitstream_reader_read_bits(&reader, 1);
  251. bitstream_reader_read_bits(&reader, 3);
  252. bitstream_reader_read_bits(&reader, 4);
  253. bitstream_reader_read_bits(&reader, 1);
  254. bitstream_reader_read_bits(&reader, 3);
  255. bitstream_reader_read_bits(&reader, 4);
  256. bitstream_reader_read_bits(&reader, 1);
  257. bitstream_reader_read_bits(&reader, 1);
  258. bitstream_reader_read_bits(&reader, 3);
  259. bitstream_reader_read_bits(&reader, 4);
  260. }
  261. if (cdp_contains_captions) {
  262. // cdp_data_section
  263. bitstream_reader_r8(&reader);
  264. //process_em_data_flag
  265. bitstream_reader_read_bits(&reader, 1);
  266. // process_cc_data_flag
  267. bitstream_reader_read_bits(&reader, 1);
  268. //additional_data_flag
  269. bitstream_reader_read_bits(&reader, 1);
  270. auto cc_count = bitstream_reader_read_bits(&reader, 5);
  271. auto *outData = (uint8_t *)bzalloc(sizeof(uint8_t) * cc_count * 3);
  272. memcpy(outData, anc + reader.pos, cc_count * 3);
  273. currentCaptions.data = outData;
  274. currentCaptions.timestamp = timestamp;
  275. currentCaptions.packets = cc_count;
  276. obs_source_output_cea708(static_cast<DeckLinkInput *>(decklink)->GetSource(), &currentCaptions);
  277. bfree(outData);
  278. }
  279. }
  280. void DeckLinkDeviceInstance::FinalizeStream()
  281. {
  282. input->SetCallback(nullptr);
  283. input->DisableVideoInput();
  284. if (channelFormat != SPEAKERS_UNKNOWN)
  285. input->DisableAudioInput();
  286. if (audioRepacker != nullptr) {
  287. delete audioRepacker;
  288. audioRepacker = nullptr;
  289. }
  290. mode = nullptr;
  291. }
  292. //#define LOG_SETUP_VIDEO_FORMAT 1
  293. void DeckLinkDeviceInstance::SetupVideoFormat(DeckLinkDeviceMode *mode_)
  294. {
  295. if (mode_ == nullptr)
  296. return;
  297. const enum video_format format = ConvertPixelFormat(pixelFormat);
  298. currentFrame.format = format;
  299. colorSpace = static_cast<DeckLinkInput *>(decklink)->GetColorSpace();
  300. if (colorSpace == VIDEO_CS_DEFAULT) {
  301. const BMDDisplayModeFlags flags = mode_->GetDisplayModeFlags();
  302. /* 2020 wasn't set when testing but maybe it will be someday */
  303. if (flags & bmdDisplayModeColorspaceRec2020)
  304. activeColorSpace = VIDEO_CS_2100_PQ;
  305. else if (flags & bmdDisplayModeColorspaceRec709)
  306. activeColorSpace = VIDEO_CS_709;
  307. else if (flags & bmdDisplayModeColorspaceRec601)
  308. activeColorSpace = VIDEO_CS_601;
  309. else
  310. activeColorSpace = VIDEO_CS_DEFAULT;
  311. } else {
  312. activeColorSpace = colorSpace;
  313. }
  314. colorRange = static_cast<DeckLinkInput *>(decklink)->GetColorRange();
  315. currentFrame.range = colorRange;
  316. video_format_get_parameters_for_format(activeColorSpace, colorRange, format, currentFrame.color_matrix,
  317. currentFrame.color_range_min, currentFrame.color_range_max);
  318. delete convertFrame;
  319. BMDPixelFormat convertFormat;
  320. switch (pixelFormat) {
  321. case bmdFormat10BitYUV:
  322. case bmdFormat8BitBGRA:
  323. case bmdFormat10BitRGBXLE:
  324. convertFormat = pixelFormat;
  325. break;
  326. default:
  327. convertFormat = bmdFormat8BitYUV;
  328. break;
  329. }
  330. convertFrame = new OBSVideoFrame(mode_->GetWidth(), mode_->GetHeight(), convertFormat);
  331. #ifdef LOG_SETUP_VIDEO_FORMAT
  332. LOG(LOG_INFO, "Setup video format: %s, %s, %s", pixelFormat == bmdFormat8BitYUV ? "YUV" : "RGB",
  333. activeColorSpace == VIDEO_CS_601 ? "BT.601" : "BT.709",
  334. colorRange == VIDEO_RANGE_FULL ? "full" : "limited");
  335. #endif
  336. }
  337. bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_, bool allow10Bit_,
  338. BMDVideoConnection bmdVideoConnection, BMDAudioConnection bmdAudioConnection)
  339. {
  340. if (mode != nullptr)
  341. return false;
  342. if (mode_ == nullptr)
  343. return false;
  344. LOG(LOG_INFO, "Starting capture...");
  345. if (!device->GetInput(&input))
  346. return false;
  347. HRESULT result = input->QueryInterface(IID_IDeckLinkConfiguration, (void **)&deckLinkConfiguration);
  348. if (result != S_OK) {
  349. LOG(LOG_ERROR, "Could not obtain the IDeckLinkConfiguration interface: %08x\n", result);
  350. } else {
  351. if (bmdVideoConnection > 0) {
  352. result = deckLinkConfiguration->SetInt(bmdDeckLinkConfigVideoInputConnection,
  353. bmdVideoConnection);
  354. if (result != S_OK) {
  355. LOG(LOG_ERROR, "Couldn't set input video port to %d\n\n", bmdVideoConnection);
  356. }
  357. }
  358. if (bmdAudioConnection > 0) {
  359. result = deckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioInputConnection,
  360. bmdAudioConnection);
  361. if (result != S_OK) {
  362. LOG(LOG_ERROR, "Couldn't set input audio port to %d\n\n", bmdVideoConnection);
  363. }
  364. }
  365. }
  366. videoConnection = bmdVideoConnection;
  367. audioConnection = bmdAudioConnection;
  368. BMDVideoInputFlags flags;
  369. bool isauto = mode_->GetName() == "Auto";
  370. if (isauto) {
  371. displayMode = bmdModeNTSC;
  372. if (allow10Bit_) {
  373. pixelFormat = bmdFormat10BitYUV;
  374. } else {
  375. pixelFormat = bmdFormat8BitYUV;
  376. }
  377. flags = bmdVideoInputEnableFormatDetection;
  378. } else {
  379. displayMode = mode_->GetDisplayMode();
  380. pixelFormat = static_cast<DeckLinkInput *>(decklink)->GetPixelFormat();
  381. flags = bmdVideoInputFlagDefault;
  382. }
  383. allow10Bit = allow10Bit_;
  384. const HRESULT videoResult = input->EnableVideoInput(displayMode, pixelFormat, flags);
  385. if (videoResult != S_OK) {
  386. LOG(LOG_ERROR, "Failed to enable video input");
  387. return false;
  388. }
  389. SetupVideoFormat(mode_);
  390. channelFormat = static_cast<DeckLinkInput *>(decklink)->GetChannelFormat();
  391. currentPacket.speakers = channelFormat;
  392. swap = static_cast<DeckLinkInput *>(decklink)->swap;
  393. int maxdevicechannel = device->GetMaxChannel();
  394. if (channelFormat != SPEAKERS_UNKNOWN) {
  395. const int channel = ConvertChannelFormat(channelFormat);
  396. const HRESULT audioResult =
  397. input->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, channel);
  398. if (audioResult != S_OK)
  399. LOG(LOG_WARNING, "Failed to enable audio input; continuing...");
  400. if (channelFormat != SPEAKERS_UNKNOWN && channelFormat != SPEAKERS_MONO &&
  401. channelFormat != SPEAKERS_STEREO && (channelFormat != SPEAKERS_7POINT1 || swap) &&
  402. maxdevicechannel >= 8) {
  403. const audio_repack_mode_t repack_mode = ConvertRepackFormat(channelFormat, swap);
  404. audioRepacker = new AudioRepacker(repack_mode);
  405. }
  406. }
  407. if (input->SetCallback(this) != S_OK) {
  408. LOG(LOG_ERROR, "Failed to set callback");
  409. FinalizeStream();
  410. return false;
  411. }
  412. if (input->StartStreams() != S_OK) {
  413. LOG(LOG_ERROR, "Failed to start streams");
  414. FinalizeStream();
  415. return false;
  416. }
  417. mode = mode_;
  418. return true;
  419. }
  420. bool DeckLinkDeviceInstance::StopCapture(void)
  421. {
  422. if (mode == nullptr || input == nullptr)
  423. return false;
  424. LOG(LOG_INFO, "Stopping capture of '%s'...", GetDevice()->GetDisplayName().c_str());
  425. input->StopStreams();
  426. FinalizeStream();
  427. return true;
  428. }
  429. bool DeckLinkDeviceInstance::StartOutput(DeckLinkDeviceMode *mode_)
  430. {
  431. if (mode != nullptr)
  432. return false;
  433. if (mode_ == nullptr)
  434. return false;
  435. auto decklinkOutput = dynamic_cast<DeckLinkOutput *>(decklink);
  436. if (decklinkOutput == nullptr)
  437. return false;
  438. LOG(LOG_INFO, "Starting output...");
  439. ComPtr<IDeckLinkOutput> output_;
  440. if (!device->GetOutput(&output_))
  441. return false;
  442. const HRESULT videoResult = output_->EnableVideoOutput(mode_->GetDisplayMode(), bmdVideoOutputFlagDefault);
  443. if (videoResult != S_OK) {
  444. LOG(LOG_ERROR, "Failed to enable video output");
  445. return false;
  446. }
  447. const HRESULT audioResult = output_->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
  448. 2, bmdAudioOutputStreamTimestamped);
  449. if (audioResult != S_OK) {
  450. LOG(LOG_ERROR, "Failed to enable audio output");
  451. return false;
  452. }
  453. if (!mode_->GetFrameRate(&frameDuration, &frameTimescale)) {
  454. LOG(LOG_ERROR, "Failed to get frame rate");
  455. return false;
  456. }
  457. ComPtr<IDeckLinkKeyer> deckLinkKeyer;
  458. if (device->GetKeyer(&deckLinkKeyer)) {
  459. const int keyerMode = device->GetKeyerMode();
  460. if (keyerMode) {
  461. deckLinkKeyer->Enable(keyerMode == 1);
  462. deckLinkKeyer->SetLevel(255);
  463. } else {
  464. deckLinkKeyer->Disable();
  465. }
  466. }
  467. frameQueueDecklinkToObs.reset();
  468. frameQueueObsToDecklink.reset();
  469. const int rowSize = decklinkOutput->GetWidth() * 4;
  470. const int frameSize = rowSize * decklinkOutput->GetHeight();
  471. for (std::vector<uint8_t> &blob : frameBlobs) {
  472. blob.assign(frameSize, 0);
  473. frameQueueDecklinkToObs.push(blob.data());
  474. }
  475. activeBlob = nullptr;
  476. struct obs_video_info ovi;
  477. const enum video_colorspace colorspace = obs_get_video_info(&ovi) ? ovi.colorspace : VIDEO_CS_DEFAULT;
  478. const bool source_hdr = (colorspace == VIDEO_CS_2100_PQ) || (colorspace == VIDEO_CS_2100_HLG);
  479. const bool enable_hdr =
  480. source_hdr &&
  481. (obs_output_get_video_conversion(decklinkOutput->GetOutput())->colorspace == VIDEO_CS_2100_PQ);
  482. BMDPixelFormat pixelFormat = enable_hdr ? bmdFormat10BitRGBXLE : bmdFormat8BitBGRA;
  483. const int64_t minimumPrerollFrames = std::max(device->GetMinimumPrerollFrames(), INT64_C(3));
  484. for (int64_t i = 0; i < minimumPrerollFrames; ++i) {
  485. ComPtr<IDeckLinkMutableVideoFrame> decklinkOutputFrame;
  486. HRESULT result = output_->CreateVideoFrame(decklinkOutput->GetWidth(), decklinkOutput->GetHeight(),
  487. rowSize, pixelFormat, bmdFrameFlagDefault,
  488. &decklinkOutputFrame);
  489. if (result != S_OK) {
  490. blog(LOG_ERROR, "failed to create video frame 0x%X", result);
  491. return false;
  492. }
  493. IDeckLinkVideoFrame *theFrame = decklinkOutputFrame.Get();
  494. ComPtr<HDRVideoFrame> decklinkOutputHDRFrame;
  495. if (enable_hdr) {
  496. *decklinkOutputHDRFrame.Assign() = new HDRVideoFrame(decklinkOutputFrame);
  497. theFrame = decklinkOutputHDRFrame.Get();
  498. }
  499. result = output_->ScheduleVideoFrame(theFrame, i * frameDuration, frameDuration, frameTimescale);
  500. if (result != S_OK) {
  501. blog(LOG_ERROR, "failed to schedule video frame for preroll 0x%X", result);
  502. return false;
  503. }
  504. }
  505. totalFramesScheduled = minimumPrerollFrames;
  506. *renderDelegate.Assign() = new RenderDelegate<DeckLinkDeviceInstance>(this);
  507. output_->SetScheduledFrameCompletionCallback(renderDelegate);
  508. output_->StartScheduledPlayback(0, 100, 1.0);
  509. mode = mode_;
  510. output = std::move(output_);
  511. return true;
  512. }
  513. bool DeckLinkDeviceInstance::StopOutput()
  514. {
  515. if (mode == nullptr || output == nullptr)
  516. return false;
  517. LOG(LOG_INFO, "Stopping output of '%s'...", GetDevice()->GetDisplayName().c_str());
  518. output->SetScheduledFrameCompletionCallback(NULL);
  519. output->DisableVideoOutput();
  520. output->DisableAudioOutput();
  521. output.Clear();
  522. renderDelegate.Clear();
  523. frameQueueDecklinkToObs.reset();
  524. frameQueueObsToDecklink.reset();
  525. return true;
  526. }
  527. void DeckLinkDeviceInstance::UpdateVideoFrame(video_data *frame)
  528. {
  529. auto decklinkOutput = dynamic_cast<DeckLinkOutput *>(decklink);
  530. if (decklinkOutput == nullptr)
  531. return;
  532. uint8_t *const blob = frameQueueDecklinkToObs.pop();
  533. if (blob) {
  534. memcpy(blob, frame->data[0], frame->linesize[0] * decklinkOutput->GetHeight());
  535. frameQueueObsToDecklink.push(blob);
  536. }
  537. }
  538. void DeckLinkDeviceInstance::ScheduleVideoFrame(IDeckLinkVideoFrame *frame)
  539. {
  540. void *bytes;
  541. if (SUCCEEDED(frame->GetBytes(&bytes))) {
  542. uint8_t *blob = frameQueueObsToDecklink.pop();
  543. if (blob) {
  544. if (activeBlob)
  545. frameQueueDecklinkToObs.push(activeBlob);
  546. activeBlob = blob;
  547. } else {
  548. blob = activeBlob;
  549. }
  550. const int frameSize = frame->GetRowBytes() * frame->GetHeight();
  551. if (blob)
  552. memcpy(bytes, blob, frameSize);
  553. else
  554. memset(bytes, 0, frameSize);
  555. output->ScheduleVideoFrame(frame, totalFramesScheduled * frameDuration, frameDuration, frameTimescale);
  556. ++totalFramesScheduled;
  557. }
  558. }
  559. void DeckLinkDeviceInstance::WriteAudio(audio_data *frames)
  560. {
  561. uint32_t sampleFramesWritten;
  562. output->WriteAudioSamplesSync(frames->data[0], frames->frames, &sampleFramesWritten);
  563. }
  564. #define TIME_BASE 1000000000
  565. HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFrameArrived(IDeckLinkVideoInputFrame *videoFrame,
  566. IDeckLinkAudioInputPacket *audioPacket)
  567. {
  568. BMDTimeValue videoTS = 0;
  569. BMDTimeValue videoDur = 0;
  570. BMDTimeValue audioTS = 0;
  571. if (videoFrame) {
  572. videoFrame->GetStreamTime(&videoTS, &videoDur, TIME_BASE);
  573. lastVideoTS = (uint64_t)videoTS;
  574. }
  575. if (audioPacket) {
  576. BMDTimeValue newAudioTS = 0;
  577. int64_t diff;
  578. audioPacket->GetPacketTime(&newAudioTS, TIME_BASE);
  579. audioTS = newAudioTS + audioOffset;
  580. diff = (int64_t)audioTS - (int64_t)nextAudioTS;
  581. if (diff > 10000000LL) {
  582. audioOffset -= diff;
  583. audioTS = newAudioTS + audioOffset;
  584. } else if (diff < -1000000) {
  585. audioOffset = 0;
  586. audioTS = newAudioTS;
  587. }
  588. }
  589. if (videoFrame && videoTS >= 0)
  590. HandleVideoFrame(videoFrame, (uint64_t)videoTS);
  591. if (audioPacket && audioTS >= 0)
  592. HandleAudioPacket(audioPacket, (uint64_t)audioTS);
  593. return S_OK;
  594. }
  595. HRESULT STDMETHODCALLTYPE
  596. DeckLinkDeviceInstance::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *newMode,
  597. BMDDetectedVideoInputFormatFlags detectedSignalFlags)
  598. {
  599. bool formatChanged = false;
  600. if (events & bmdVideoInputColorspaceChanged) {
  601. constexpr BMDDetectedVideoInputFormatFlags highBitFlags =
  602. (bmdDetectedVideoInput12BitDepth | bmdDetectedVideoInput10BitDepth);
  603. if (detectedSignalFlags & bmdDetectedVideoInputRGB444) {
  604. const BMDPixelFormat nextFormat = ((detectedSignalFlags & highBitFlags) && allow10Bit)
  605. ? bmdFormat10BitRGBXLE
  606. : bmdFormat8BitBGRA;
  607. formatChanged = pixelFormat != nextFormat;
  608. pixelFormat = nextFormat;
  609. }
  610. if (detectedSignalFlags & bmdDetectedVideoInputYCbCr422) {
  611. const BMDPixelFormat nextFormat = ((detectedSignalFlags & highBitFlags) && allow10Bit)
  612. ? bmdFormat10BitYUV
  613. : bmdFormat8BitYUV;
  614. formatChanged = pixelFormat != nextFormat;
  615. pixelFormat = nextFormat;
  616. }
  617. }
  618. if (formatChanged || (events & bmdVideoInputDisplayModeChanged)) {
  619. input->PauseStreams();
  620. mode->SetMode(newMode);
  621. displayMode = mode->GetDisplayMode();
  622. const HRESULT videoResult =
  623. input->EnableVideoInput(displayMode, pixelFormat, bmdVideoInputEnableFormatDetection);
  624. if (videoResult != S_OK) {
  625. LOG(LOG_ERROR, "Failed to enable video input");
  626. input->StopStreams();
  627. FinalizeStream();
  628. return E_FAIL;
  629. }
  630. SetupVideoFormat(mode);
  631. input->FlushStreams();
  632. input->StartStreams();
  633. }
  634. return S_OK;
  635. }
  636. ULONG STDMETHODCALLTYPE DeckLinkDeviceInstance::AddRef(void)
  637. {
  638. return os_atomic_inc_long(&refCount);
  639. }
  640. HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::QueryInterface(REFIID iid, LPVOID *ppv)
  641. {
  642. HRESULT result = E_NOINTERFACE;
  643. *ppv = nullptr;
  644. CFUUIDBytes unknown = CFUUIDGetUUIDBytes(IUnknownUUID);
  645. if (memcmp(&iid, &unknown, sizeof(REFIID)) == 0) {
  646. *ppv = this;
  647. AddRef();
  648. result = S_OK;
  649. } else if (memcmp(&iid, &IID_IDeckLinkNotificationCallback, sizeof(REFIID)) == 0) {
  650. *ppv = (IDeckLinkNotificationCallback *)this;
  651. AddRef();
  652. result = S_OK;
  653. }
  654. return result;
  655. }
  656. ULONG STDMETHODCALLTYPE DeckLinkDeviceInstance::Release(void)
  657. {
  658. const long newRefCount = os_atomic_dec_long(&refCount);
  659. if (newRefCount == 0) {
  660. delete this;
  661. return 0;
  662. }
  663. return newRefCount;
  664. }