Skip to content

Commit 8c1e8b0

Browse files
committed
Fix frame orientation detection on Windows for all pixel formats (#37)
* Fix frame orientation detection on Windows based on biHeight sign - Use abs(biHeight) to get actual frame height - Check biHeight sign to determine orientation (negative=top-to-bottom, positive=bottom-to-top) - Remove incorrect pixel-format-based orientation detection - Add m_inputOrientation member variable to store orientation across frames - Reset m_firstFrameArrived when opening device Fixes #34 * Avoid divide by 0
1 parent 7925e9b commit 8c1e8b0

5 files changed

Lines changed: 29 additions & 9 deletions

File tree

BUILD_AND_INSTALL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,6 @@ git clean -fdx install/
250250

251251
## Version Information
252252

253-
Current version: 1.3.3
253+
Current version: 1.3.4
254254

255255
This is the first official release of the ccap project, including complete CMake configuration and cross-platform build support.

ccap.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "ccap"
3-
s.version = "1.3.3"
3+
s.version = "1.3.4"
44
s.summary = "CameraCapture And Player"
55
s.description = <<-DESC
66
Pod of https://github.com/wysaid/CameraCapture

include/ccap_config.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
#define CCAP_VERSION_MAJOR 1
1818
#define CCAP_VERSION_MINOR 3
19-
#define CCAP_VERSION_PATCH 3
20-
#define CCAP_VERSION_STRING "1.3.3"
19+
#define CCAP_VERSION_PATCH 4
20+
#define CCAP_VERSION_STRING "1.3.4"
2121

2222
/* ========== Export/Import Macro Definitions ========== */
2323

src/ccap_imp_windows.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ bool ProviderDirectShow::createStream() {
572572
VIDEOINFOHEADER* videoHeader = (VIDEOINFOHEADER*)mediaType->pbFormat;
573573
m_frameProp.width = videoHeader->bmiHeader.biWidth;
574574
m_frameProp.height = videoHeader->bmiHeader.biHeight;
575-
m_frameProp.fps = 10000000.0 / videoHeader->AvgTimePerFrame;
575+
m_frameProp.fps = videoHeader->AvgTimePerFrame != 0 ? 10000000.0 / videoHeader->AvgTimePerFrame : 0;
576576
auto pixFormatInfo = findPixelFormatInfo(mediaType->subtype);
577577
auto subtype = mediaType->subtype;
578578

@@ -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 = vih->AvgTimePerFrame != 0 ? 10000000.0 / vih->AvgTimePerFrame : 0;
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

src/ccap_imp_windows.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class ProviderDirectShow : public ProviderImp, public ISampleGrabberCB {
118118
std::vector<std::string> m_allDeviceNames;
119119

120120
std::chrono::steady_clock::time_point m_startTime{};
121+
FrameOrientation m_inputOrientation = FrameOrientation::TopToBottom;
122+
121123
bool m_firstFrameArrived = false;
122124

123125
// State variables

0 commit comments

Comments
 (0)