@@ -727,6 +727,7 @@ bool ProviderDirectShow::open(std::string_view deviceName) {
727727 m_isOpened = true ;
728728 m_isRunning = false ;
729729 m_frameIndex = 0 ;
730+ m_firstFrameArrived = false ;
730731 return true ;
731732}
732733
@@ -757,9 +758,27 @@ HRESULT STDMETHODCALLTYPE ProviderDirectShow::SampleCB(double sampleTime, IMedia
757758 if (SUCCEEDED (hr)) {
758759 VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *)mt.pbFormat ;
759760 m_frameProp.width = vih->bmiHeader .biWidth ;
760- m_frameProp.height = vih->bmiHeader .biHeight ;
761- m_frameProp.fps = 10000000.0 / vih->AvgTimePerFrame ;
761+ // biHeight may be negative. Negative height indicates top-to-bottom orientation.
762+ // Positive height indicates bottom-to-top orientation (standard Windows DIB format).
763+ m_frameProp.height = abs (vih->bmiHeader .biHeight );
764+
765+ // For YUV formats, always assume TopToBottom orientation regardless of biHeight
766+ // This fixes issues with some virtual cameras (like OBS) that report positive biHeight
767+ // but actually deliver TopToBottom data
762768 auto info = findPixelFormatInfo (mt.subtype );
769+ bool isYUVFormat = (info.pixelFormat & kPixelFormatYUVColorBit ) != 0 ;
770+
771+ if (isYUVFormat) {
772+ // YUV data is typically TopToBottom, ignore biHeight sign
773+ m_inputOrientation = FrameOrientation::TopToBottom;
774+ CCAP_LOG_V (" ccap: YUV format detected, using TopToBottom orientation (biHeight=%d)\n " , vih->bmiHeader .biHeight );
775+ } else if (vih->bmiHeader .biHeight < 0 ) {
776+ m_inputOrientation = FrameOrientation::TopToBottom;
777+ } else {
778+ m_inputOrientation = FrameOrientation::BottomToTop;
779+ }
780+
781+ m_frameProp.fps = 10000000.0 / vih->AvgTimePerFrame ;
763782 if (info.pixelFormat != PixelFormat::Unknown) {
764783 m_frameProp.cameraPixelFormat = info.pixelFormat ;
765784 }
@@ -781,15 +800,14 @@ HRESULT STDMETHODCALLTYPE ProviderDirectShow::SampleCB(double sampleTime, IMedia
781800 uint32_t bufferLen = mediaSample->GetActualDataLength ();
782801 bool isInputYUV = (m_frameProp.cameraPixelFormat & kPixelFormatYUVColorBit );
783802 bool isOutputYUV = (m_frameProp.outputPixelFormat & kPixelFormatYUVColorBit );
784- auto inputOrientation = isInputYUV ? FrameOrientation::TopToBottom : FrameOrientation::BottomToTop;
785803
786804 newFrame->pixelFormat = m_frameProp.cameraPixelFormat ;
787805 newFrame->width = m_frameProp.width ;
788806 newFrame->height = m_frameProp.height ;
789807 newFrame->orientation = isOutputYUV ? FrameOrientation::TopToBottom : m_frameOrientation;
790808 newFrame->nativeHandle = mediaSample;
791809
792- bool shouldFlip = newFrame->orientation != inputOrientation && !isOutputYUV;
810+ bool shouldFlip = newFrame->orientation != m_inputOrientation && !isOutputYUV;
793811 bool shouldConvert = m_frameProp.cameraPixelFormat != m_frameProp.outputPixelFormat ;
794812 bool zeroCopy = !shouldConvert && !shouldFlip;
795813
0 commit comments