1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge pull request #24136 from komakai:visionos_support

Add experimental support for Apple VisionOS platform #24136

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch

This is dependent on cmake support for VisionOs which is currently in progress.
Creating PR now to test that there are no regressions in iOS and macOS builds
This commit is contained in:
Giles Payne
2023-12-20 21:35:10 +09:00
committed by GitHub
parent abbd878eb5
commit 3d9cb5329c
19 changed files with 325 additions and 100 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ ocv_add_dispatched_file_force_all(test_intrin512 TEST AVX512_SKX)
set(PARALLEL_ENABLE_PLUGINS_DEFAULT ON)
if(EMSCRIPTEN OR IOS OR WINRT)
if(EMSCRIPTEN OR IOS OR XROS OR WINRT)
set(PARALLEL_ENABLE_PLUGINS_DEFAULT OFF)
endif()
# parallel backends configuration
+2 -2
View File
@@ -137,11 +137,11 @@ if(APPLE OR APPLE_FRAMEWORK)
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/apple_conversions.h)
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/apple_conversions.mm)
endif()
if(IOS)
if(IOS OR XROS)
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/ios_conversions.mm)
list(APPEND IMGCODECS_LIBRARIES "-framework UIKit")
endif()
if(APPLE AND (NOT IOS))
if(APPLE AND (NOT IOS) AND (NOT XROS))
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/macosx_conversions.mm)
list(APPEND IMGCODECS_LIBRARIES "-framework AppKit")
endif()
@@ -0,0 +1,5 @@
{
"SourceMap" : {
"visionos" : "ios"
}
}
+5
View File
@@ -9,6 +9,8 @@ file(REMOVE_RECURSE "${OPENCV_OBJC_BINDINGS_DIR}/osx")
file(REMOVE "${OPENCV_DEPHELPER}/gen_opencv_objc_source_osx") # force re-run after CMake
file(REMOVE_RECURSE "${OPENCV_OBJC_BINDINGS_DIR}/ios")
file(REMOVE "${OPENCV_DEPHELPER}/gen_opencv_objc_source_ios") # force re-run after CMake
file(REMOVE_RECURSE "${OPENCV_OBJC_BINDINGS_DIR}/visionos")
file(REMOVE "${OPENCV_DEPHELPER}/gen_opencv_objc_source_visionos") # force re-run after CMake
# This file is included from a subdirectory
set(OBJC_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
@@ -67,6 +69,8 @@ string(REPLACE "opencv_" "" MODULES "${OPENCV_OBJC_MODULES}")
if(NOT DEFINED OPENCV_OBJC_TARGET AND APPLE_FRAMEWORK)
if(IOS)
set(OPENCV_OBJC_TARGET "ios")
elseif(XROS)
set(OPENCV_OBJC_TARGET "visionos")
else()
set(OPENCV_OBJC_TARGET "osx")
endif()
@@ -117,6 +121,7 @@ if(OPENCV_OBJC_TARGET)
else()
ocv_add_objc_generated_target(osx)
ocv_add_objc_generated_target(ios)
ocv_add_objc_generated_target(visionos)
endif()
add_custom_target(gen_opencv_objc_source
+7 -10
View File
@@ -1600,7 +1600,7 @@ if __name__ == "__main__":
arg_parser = argparse.ArgumentParser(description='OpenCV Objective-C Wrapper Generator')
arg_parser.add_argument('-p', '--parser', required=True, help='OpenCV header parser')
arg_parser.add_argument('-c', '--config', required=True, help='OpenCV modules config')
arg_parser.add_argument('-t', '--target', required=True, help='Target (either ios or osx)')
arg_parser.add_argument('-t', '--target', required=True, help='Target (either ios or osx or visionos)')
arg_parser.add_argument('-f', '--framework', required=True, help='Framework name')
args=arg_parser.parse_args()
@@ -1671,6 +1671,7 @@ if __name__ == "__main__":
logging.info("\nCommon headers (%d):\n%s", len(common_headers), pformat(common_headers))
gendict_fname = os.path.join(misc_location, 'gen_dict.json')
module_source_map = {}
if os.path.exists(gendict_fname):
with open(gendict_fname) as f:
gen_type_dict = json.load(f)
@@ -1687,6 +1688,7 @@ if __name__ == "__main__":
header_fix.update(gen_type_dict.get("header_fix", {}))
enum_fix.update(gen_type_dict.get("enum_fix", {}))
const_fix.update(gen_type_dict.get("const_fix", {}))
module_source_map = gen_type_dict.get("SourceMap", {})
namespaces_dict.update(gen_type_dict.get("namespaces_dict", {}))
module_imports += gen_type_dict.get("module_imports", [])
@@ -1695,15 +1697,10 @@ if __name__ == "__main__":
if os.path.exists(objc_files_dir):
copied_files += copy_objc_files(objc_files_dir, objc_base_path, module, True)
if args.target == 'ios':
ios_files_dir = os.path.join(misc_location, 'ios')
if os.path.exists(ios_files_dir):
copied_files += copy_objc_files(ios_files_dir, objc_base_path, module, True)
if args.target == 'osx':
osx_files_dir = os.path.join(misc_location, 'macosx')
if os.path.exists(osx_files_dir):
copied_files += copy_objc_files(osx_files_dir, objc_base_path, module, True)
target_path = 'macosx' if args.target == 'osx' else module_source_map.get(args.target, args.target)
target_files_dir = os.path.join(misc_location, target_path)
if os.path.exists(target_files_dir):
copied_files += copy_objc_files(target_files_dir, objc_base_path, module, True)
objc_test_files_dir = os.path.join(misc_location, 'test')
if os.path.exists(objc_test_files_dir):
+2 -2
View File
@@ -1,5 +1,5 @@
set(VIDEOIO_ENABLE_PLUGINS_DEFAULT ON)
if(EMSCRIPTEN OR IOS OR WINRT)
if(EMSCRIPTEN OR IOS OR XROS OR WINRT)
set(VIDEOIO_ENABLE_PLUGINS_DEFAULT OFF)
endif()
@@ -197,7 +197,7 @@ if(TARGET ocv.3rdparty.aravis)
endif()
if(TARGET ocv.3rdparty.avfoundation)
if(IOS)
if(IOS OR XROS)
list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_avfoundation.mm)
else()
list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_avfoundation_mac.mm)
+65 -34
View File
@@ -61,6 +61,8 @@
#define DISABLE_AUTO_RESTART 999
#if !TARGET_OS_VISION
@interface CaptureDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
{
int newFrame;
@@ -125,6 +127,7 @@ class CvCaptureCAM : public CvCapture {
int disableAutoRestart;
};
#endif
/*****************************************************************************
*
@@ -160,6 +163,7 @@ private:
uint32_t mMode;
int mFormat;
void handleTracks(NSArray<AVAssetTrack *>* tracks, const char* filename);
bool setupReadingAt(CMTime position);
IplImage* retrieveFramePixelBuffer();
int getPreferredOrientationDegrees() const;
@@ -217,6 +221,8 @@ cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_file(const std::strin
}
#if !TARGET_OS_VISION
cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_cam(int index)
{
CvCaptureCAM* retval = new CvCaptureCAM(index);
@@ -226,6 +232,8 @@ cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_cam(int index)
return 0;
}
#endif
cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& filename, int fourcc,
double fps, const cv::Size &frameSize,
const cv::VideoWriterParameters& params)
@@ -245,6 +253,8 @@ cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& file
*
*****************************************************************************/
#if !TARGET_OS_VISION
CvCaptureCAM::CvCaptureCAM(int cameraNum) {
mCaptureSession = nil;
mCaptureDeviceInput = nil;
@@ -773,6 +783,7 @@ fromConnection:(AVCaptureConnection *)connection{
@end
#endif
/*****************************************************************************
*
@@ -811,24 +822,26 @@ CvCaptureFile::CvCaptureFile(const char* filename) {
return;
}
// Available since iOS 15
#if TARGET_OS_VISION || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 150000)
if (@available(iOS 15, visionOS 1, *)) {
[mAsset loadTracksWithMediaType:AVMediaTypeVideo completionHandler:^(NSArray<AVAssetTrack *>* tracks, NSError* err) {
if (err != nil) {
handleTracks(tracks, filename);
}
[localpool drain];
}];
return;
} else {
#if !TARGET_OS_VISION
NSArray *tracks = [mAsset tracksWithMediaType:AVMediaTypeVideo];
handleTracks(tracks, filename);
#endif
}
#else
NSArray *tracks = [mAsset tracksWithMediaType:AVMediaTypeVideo];
if ([tracks count] == 0) {
fprintf(stderr, "OpenCV: Couldn't read video stream from file \"%s\"\n", filename);
[localpool drain];
started = 0;
return;
}
mAssetTrack = [tracks[0] retain];
if ( ! setupReadingAt(kCMTimeZero) ) {
fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename);
[localpool drain];
started = 0;
return;
}
started = 1;
handleTracks(tracks, filename);
#endif
[localpool drain];
}
@@ -850,6 +863,24 @@ CvCaptureFile::~CvCaptureFile() {
[localpool drain];
}
void CvCaptureFile::handleTracks(NSArray<AVAssetTrack *>* tracks, const char* filename) {
if ([tracks count] == 0) {
fprintf(stderr, "OpenCV: Couldn't read video stream from file \"%s\"\n", filename);
started = 0;
return;
}
mAssetTrack = [tracks[0] retain];
if ( ! setupReadingAt(kCMTimeZero) ) {
fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename);
started = 0;
return;
}
started = 1;
}
bool CvCaptureFile::setupReadingAt(CMTime position) {
if (mAssetReader) {
if (mAssetReader.status == AVAssetReaderStatusReading) {
@@ -1269,25 +1300,25 @@ CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int
//exception;
}
// Three codec supported AVVideoCodecH264 AVVideoCodecJPEG AVVideoCodecTypeHEVC
// Three codec supported AVVideoCodecTypeH264 AVVideoCodecTypeJPEG AVVideoCodecTypeHEVC
// On iPhone 3G H264 is not supported.
if (fourcc == CV_FOURCC('J','P','E','G') || fourcc == CV_FOURCC('j','p','e','g') ||
fourcc == CV_FOURCC('M','J','P','G') || fourcc == CV_FOURCC('m','j','p','g')){
codec = [AVVideoCodecJPEG copy]; // Use JPEG codec if specified, otherwise H264
codec = [AVVideoCodecTypeJPEG copy]; // Use JPEG codec if specified, otherwise H264
}else if(fourcc == CV_FOURCC('H','2','6','4') || fourcc == CV_FOURCC('a','v','c','1')){
codec = [AVVideoCodecH264 copy];
codec = [AVVideoCodecTypeH264 copy];
// Available since iOS 11
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
#if TARGET_OS_VISION || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000)
}else if(fourcc == CV_FOURCC('H','2','6','5') || fourcc == CV_FOURCC('h','v','c','1') ||
fourcc == CV_FOURCC('H','E','V','C') || fourcc == CV_FOURCC('h','e','v','c')){
if (@available(iOS 11, *)) {
if (@available(iOS 11, visionOS 1, *)) {
codec = [AVVideoCodecTypeHEVC copy];
} else {
codec = [AVVideoCodecH264 copy];
codec = [AVVideoCodecTypeH264 copy];
}
#endif
}else{
codec = [AVVideoCodecH264 copy]; // default canonical H264.
codec = [AVVideoCodecTypeH264 copy]; // default canonical H264.
}
//NSLog(@"Path: %@", path);
@@ -1349,17 +1380,17 @@ CvVideoWriter_AVFoundation::~CvVideoWriter_AVFoundation() {
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
[mMovieWriterInput markAsFinished];
[mMovieWriter finishWriting];
[mMovieWriter release];
[mMovieWriterInput release];
[mMovieWriterAdaptor release];
[path release];
[codec release];
[fileType release];
cvReleaseImage(&argbimage);
[localpool drain];
[mMovieWriter finishWritingWithCompletionHandler:^() {
[mMovieWriter release];
[mMovieWriterInput release];
[mMovieWriterAdaptor release];
[path release];
[codec release];
[fileType release];
cvReleaseImage(&argbimage);
[localpool drain];
}];
}
bool CvVideoWriter_AVFoundation::writeFrame(const IplImage* iplimage) {