#pragma once #include "aja-props.hpp" #include #include #include // #define AJA_WRITE_DEBUG_WAV #ifdef AJA_WRITE_DEBUG_WAV #include #endif #include #include #include struct VideoFrame { struct video_data frame; int64_t frameNum; size_t size; }; struct AudioFrames { struct audio_data frames; size_t offset; size_t size; }; //TODO(paulh): Refactor me into OutputProps struct FrameTimes { double obsFps; uint64_t obsFrameTime; double cardFps; uint64_t cardFrameTime; }; using VideoQueue = std::deque; using AudioQueue = std::deque; class CNTV2Card; // forward decl class AJAOutput { public: enum { // min queue sizes computed in AJAOutput kVideoQueueMaxSize = 15, kAudioQueueMaxSize = 96, // ~(48000 / 1024 samples per audio_frame) * 2sec }; AJAOutput(CNTV2Card *card, const std::string &cardID, const std::string &outputID, UWord deviceIndex, const NTV2DeviceID deviceID); ~AJAOutput(); CNTV2Card *GetCard(); void Initialize(const OutputProps &props); void SetOBSOutput(obs_output_t *output); obs_output_t *GetOBSOutput(); void SetOutputProps(const OutputProps &props); OutputProps GetOutputProps() const; void GenerateTestPattern(NTV2VideoFormat vf, NTV2PixelFormat pf, NTV2TestPatternSelect pattern); void QueueVideoFrame(struct video_data *frame, size_t size); void QueueAudioFrames(struct audio_data *frames, size_t size); void ClearVideoQueue(); void ClearAudioQueue(); size_t VideoQueueSize(); size_t AudioQueueSize(); bool HaveEnoughAudio(size_t needAudioSize); void DMAAudioFromQueue(NTV2AudioSystem audioSys); void DMAVideoFromQueue(); void CreateThread(bool enable = false); void StopThread(); bool ThreadRunning(); static void OutputThread(AJAThread *thread, void *ctx); std::string mCardID; std::string mOutputID; UWord mDeviceIndex; NTV2DeviceID mDeviceID; FrameTimes mFrameTimes; uint32_t mAudioPlayCursor; uint32_t mAudioWriteCursor; uint32_t mAudioWrapAddress; uint32_t mAudioRate; uint64_t mAudioQueueSamples; uint64_t mAudioWriteSamples; uint64_t mAudioPlaySamples; uint32_t mNumCardFrames; uint32_t mFirstCardFrame; uint32_t mLastCardFrame; uint32_t mWriteCardFrame; uint32_t mPlayCardFrame; uint32_t mPlayCardNext; uint32_t mFrameRateNum; uint32_t mFrameRateDen; uint64_t mVideoQueueFrames; uint64_t mVideoWriteFrames; uint64_t mVideoPlayFrames; uint64_t mFirstVideoTS; uint64_t mFirstAudioTS; uint64_t mLastVideoTS; uint64_t mLastAudioTS; int64_t mVideoDelay; int64_t mAudioDelay; int64_t mAudioVideoSync; int64_t mAudioAdjust; int64_t mLastStatTime; #ifdef AJA_WRITE_DEBUG_WAV AJAWavWriter *mWaveWriter; #endif private: void calculate_card_frame_indices(uint32_t numFrames, NTV2DeviceID id, NTV2Channel channel, NTV2VideoFormat vf, NTV2PixelFormat pf); uint32_t get_frame_count(); void dma_audio_samples(NTV2AudioSystem audioSys, uint32_t *data, size_t size); CNTV2Card *mCard; OutputProps mOutputProps; NTV2TestPatternBuffer mTestPattern; bool mIsRunning; bool mAudioStarted; AJAThread mRunThread; mutable std::mutex mVideoLock; mutable std::mutex mAudioLock; mutable std::mutex mRunThreadLock; std::unique_ptr mVideoQueue; std::unique_ptr mAudioQueue; obs_output_t *mOBSOutput; };