camera: Windows support, through the Media Foundation API!

This commit is contained in:
Ryan C. Gordon
2024-01-31 15:07:07 -05:00
parent 3dca8a03da
commit 7191a97fe3
11 changed files with 998 additions and 44 deletions
+1
View File
@@ -397,6 +397,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\camera\dummy\SDL_camera_dummy.c" /> <ClCompile Include="..\..\src\camera\dummy\SDL_camera_dummy.c" />
<ClCompile Include="..\..\src\camera\mediafoundation\SDL_camera_mediafoundation.c" />
<ClCompile Include="..\..\src\camera\SDL_camera.c" /> <ClCompile Include="..\..\src\camera\SDL_camera.c" />
<ClCompile Include="..\..\src\main\generic\SDL_sysmain_callbacks.c" /> <ClCompile Include="..\..\src\main\generic\SDL_sysmain_callbacks.c" />
<ClCompile Include="..\..\src\main\SDL_main_callbacks.c" /> <ClCompile Include="..\..\src\main\SDL_main_callbacks.c" />
+6
View File
@@ -184,6 +184,9 @@
<Filter Include="camera\dummy"> <Filter Include="camera\dummy">
<UniqueIdentifier>{0000fc2700d453b3c8d79fe81e1c0000}</UniqueIdentifier> <UniqueIdentifier>{0000fc2700d453b3c8d79fe81e1c0000}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="camera\mediafoundation">
<UniqueIdentifier>{0000fbfe2d21e4f451142e7d0e870000}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\include\SDL3\SDL_begin_code.h"> <ClInclude Include="..\..\include\SDL3\SDL_begin_code.h">
@@ -856,6 +859,9 @@
<ClCompile Include="..\..\src\camera\dummy\SDL_camera_dummy.c"> <ClCompile Include="..\..\src\camera\dummy\SDL_camera_dummy.c">
<Filter>camera\dummy</Filter> <Filter>camera\dummy</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\camera\mediafoundation\SDL_camera_mediafoundation.c">
<Filter>camera\mediafoundation</Filter>
</ClCompile>
<ClCompile Include="..\..\src\camera\SDL_camera.c"> <ClCompile Include="..\..\src\camera\SDL_camera.c">
<Filter>camera</Filter> <Filter>camera</Filter>
</ClCompile> </ClCompile>
+12
View File
@@ -499,6 +499,7 @@
F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1B2B59ACE000FEAD97 /* yuv_rgb_lsx.h */; }; F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1B2B59ACE000FEAD97 /* yuv_rgb_lsx.h */; };
F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1C2B59ACE000FEAD97 /* yuv_rgb_common.h */; }; F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1C2B59ACE000FEAD97 /* yuv_rgb_common.h */; };
FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; platformFilters = (ios, maccatalyst, macos, tvos, watchos, ); }; FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; platformFilters = (ios, maccatalyst, macos, tvos, watchos, ); };
00009F560664255CCB6C0000 /* SDL_camera_mediafoundation.c in Sources */ = {isa = PBXBuildFile; fileRef = 0000C61C247BAAAF757D0000 /* SDL_camera_mediafoundation.c */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -1027,6 +1028,7 @@
F59C710600D5CB5801000001 /* SDL.info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = SDL.info; sourceTree = "<group>"; }; F59C710600D5CB5801000001 /* SDL.info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = SDL.info; sourceTree = "<group>"; };
F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; }; F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; };
FA73671C19A540EF004122E4 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; FA73671C19A540EF004122E4 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
0000C61C247BAAAF757D0000 /* SDL_camera_mediafoundation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_camera_mediafoundation.c; path = SDL_camera_mediafoundation.c; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -1068,6 +1070,7 @@
0000035D38C3899C7EFD0000 /* SDL_camera.c */, 0000035D38C3899C7EFD0000 /* SDL_camera.c */,
00009003C7148E1126CA0000 /* SDL_camera_c.h */, 00009003C7148E1126CA0000 /* SDL_camera_c.h */,
00005D3EB902478835E20000 /* SDL_syscamera.h */, 00005D3EB902478835E20000 /* SDL_syscamera.h */,
0000926F2501CA0BDD650000 /* mediafoundation */,
); );
path = camera; path = camera;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -2175,6 +2178,14 @@
path = resources; path = resources;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
0000926F2501CA0BDD650000 /* mediafoundation */ = {
isa = PBXGroup;
children = (
0000C61C247BAAAF757D0000 /* SDL_camera_mediafoundation.c */,
);
path = mediafoundation;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */ /* Begin PBXHeadersBuildPhase section */
@@ -2754,6 +2765,7 @@
000098E9DAA43EF6FF7F0000 /* SDL_camera.c in Sources */, 000098E9DAA43EF6FF7F0000 /* SDL_camera.c in Sources */,
00001B2471F503DD3C1B0000 /* SDL_camera_dummy.c in Sources */, 00001B2471F503DD3C1B0000 /* SDL_camera_dummy.c in Sources */,
00002B20A48E055EB0350000 /* SDL_camera_coremedia.m in Sources */, 00002B20A48E055EB0350000 /* SDL_camera_coremedia.m in Sources */,
00009F560664255CCB6C0000 /* SDL_camera_mediafoundation.c in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -472,7 +472,8 @@
#cmakedefine SDL_CAMERA_DRIVER_V4L2 @SDL_CAMERA_DRIVER_V4L2@ #cmakedefine SDL_CAMERA_DRIVER_V4L2 @SDL_CAMERA_DRIVER_V4L2@
#cmakedefine SDL_CAMERA_DRIVER_COREMEDIA @SDL_CAMERA_DRIVER_COREMEDIA@ #cmakedefine SDL_CAMERA_DRIVER_COREMEDIA @SDL_CAMERA_DRIVER_COREMEDIA@
#cmakedefine SDL_CAMERA_DRIVER_ANDROID @SDL_CAMERA_DRIVER_ANDROID@ #cmakedefine SDL_CAMERA_DRIVER_ANDROID @SDL_CAMERA_DRIVER_ANDROID@
#cmakedefine SDL_CAMERA_DRIVER_EMSCRIPTEN @SDL_CAMERA_DRIVER_EMSCRIPTEND@ #cmakedefine SDL_CAMERA_DRIVER_EMSCRIPTEN @SDL_CAMERA_DRIVER_EMSCRIPTEN@
#cmakedefine SDL_CAMERA_DRIVER_MEDIAFOUNDATION @SDL_CAMERA_DRIVER_MEDIAFOUNDATION@
/* Enable misc subsystem */ /* Enable misc subsystem */
#cmakedefine SDL_MISC_DUMMY @SDL_MISC_DUMMY@ #cmakedefine SDL_MISC_DUMMY @SDL_MISC_DUMMY@
@@ -311,7 +311,8 @@ typedef unsigned int uintptr_t;
/* Enable filesystem support */ /* Enable filesystem support */
#define SDL_FILESYSTEM_WINDOWS 1 #define SDL_FILESYSTEM_WINDOWS 1
/* Enable the camera driver (src/camera/dummy/\*.c) */ /* !!! FIXME */ /* Enable the camera driver */
#define SDL_CAMERA_DRIVER_DUMMY 1 #define SDL_CAMERA_DRIVER_MEDIAFOUNDATION 1
#define SDL_CAMERA_DRIVER_DUMMY 1
#endif /* SDL_build_config_windows_h_ */ #endif /* SDL_build_config_windows_h_ */
+39 -1
View File
@@ -43,6 +43,9 @@ static const CameraBootStrap *const bootstrap[] = {
#ifdef SDL_CAMERA_DRIVER_EMSCRIPTEN #ifdef SDL_CAMERA_DRIVER_EMSCRIPTEN
&EMSCRIPTENCAMERA_bootstrap, &EMSCRIPTENCAMERA_bootstrap,
#endif #endif
#ifdef SDL_CAMERA_DRIVER_MEDIAFOUNDATION
&MEDIAFOUNDATION_bootstrap,
#endif
#ifdef SDL_CAMERA_DRIVER_DUMMY #ifdef SDL_CAMERA_DRIVER_DUMMY
&DUMMYCAMERA_bootstrap, &DUMMYCAMERA_bootstrap,
#endif #endif
@@ -70,6 +73,32 @@ const char *SDL_GetCurrentCameraDriver(void)
return camera_driver.name; return camera_driver.name;
} }
int SDL_AddCameraFormat(CameraFormatAddData *data, Uint32 fmt, int w, int h, int interval_numerator, int interval_denominator)
{
SDL_assert(data != NULL);
if (data->allocated_specs <= data->num_specs) {
const int newalloc = data->allocated_specs ? (data->allocated_specs * 2) : 16;
void *ptr = SDL_realloc(data->specs, sizeof (SDL_CameraSpec) * newalloc);
if (!ptr) {
return -1;
}
data->specs = (SDL_CameraSpec *) ptr;
data->allocated_specs = newalloc;
}
SDL_CameraSpec *spec = &data->specs[data->num_specs];
spec->format = fmt;
spec->width = w;
spec->height = h;
spec->interval_numerator = interval_numerator;
spec->interval_denominator = interval_denominator;
data->num_specs++;
return 0;
}
static void ClosePhysicalCameraDevice(SDL_CameraDevice *device) static void ClosePhysicalCameraDevice(SDL_CameraDevice *device)
{ {
if (!device) { if (!device) {
@@ -610,10 +639,13 @@ SDL_bool SDL_CameraThreadIterate(SDL_CameraDevice *device)
if (rc == 1) { // new frame acquired! if (rc == 1) { // new frame acquired!
#if DEBUG_CAMERA #if DEBUG_CAMERA
SDL_Log("CAMERA: New frame available!"); SDL_Log("CAMERA: New frame available! pixels=%p pitch=%d", device->acquire_surface->pixels, device->acquire_surface->pitch);
#endif #endif
if (device->drop_frames > 0) { if (device->drop_frames > 0) {
#if DEBUG_CAMERA
SDL_Log("CAMERA: Dropping an initial frame");
#endif
device->drop_frames--; device->drop_frames--;
camera_driver.impl.ReleaseFrame(device, device->acquire_surface); camera_driver.impl.ReleaseFrame(device, device->acquire_surface);
device->acquire_surface->pixels = NULL; device->acquire_surface->pixels = NULL;
@@ -662,9 +694,15 @@ SDL_bool SDL_CameraThreadIterate(SDL_CameraDevice *device)
} else if (acquired) { // we have a new frame, scale/convert if necessary and queue it for the app! } else if (acquired) { // we have a new frame, scale/convert if necessary and queue it for the app!
SDL_assert(slist != NULL); SDL_assert(slist != NULL);
if (!device->needs_scaling && !device->needs_conversion) { // no conversion needed? Just move the pointer/pitch into the output surface. if (!device->needs_scaling && !device->needs_conversion) { // no conversion needed? Just move the pointer/pitch into the output surface.
#if DEBUG_CAMERA
SDL_Log("CAMERA: Frame is going through without conversion!");
#endif
output_surface->pixels = acquired->pixels; output_surface->pixels = acquired->pixels;
output_surface->pitch = acquired->pitch; output_surface->pitch = acquired->pitch;
} else { // convert/scale into a different surface. } else { // convert/scale into a different surface.
#if DEBUG_CAMERA
SDL_Log("CAMERA: Frame is getting converted!");
#endif
SDL_Surface *srcsurf = acquired; SDL_Surface *srcsurf = acquired;
if (device->needs_scaling == -1) { // downscaling? Do it first. -1: downscale, 0: no scaling, 1: upscale if (device->needs_scaling == -1) { // downscaling? Do it first. -1: downscale, 0: no scaling, 1: upscale
SDL_Surface *dstsurf = device->needs_conversion ? device->conversion_surface : output_surface; SDL_Surface *dstsurf = device->needs_conversion ? device->conversion_surface : output_surface;
+11
View File
@@ -58,6 +58,16 @@ extern void SDL_CameraThreadSetup(SDL_CameraDevice *device);
extern SDL_bool SDL_CameraThreadIterate(SDL_CameraDevice *device); extern SDL_bool SDL_CameraThreadIterate(SDL_CameraDevice *device);
extern void SDL_CameraThreadShutdown(SDL_CameraDevice *device); extern void SDL_CameraThreadShutdown(SDL_CameraDevice *device);
// common utility functionality to gather up camera specs. Not required!
typedef struct CameraFormatAddData
{
SDL_CameraSpec *specs;
int num_specs;
int allocated_specs;
} CameraFormatAddData;
int SDL_AddCameraFormat(CameraFormatAddData *data, Uint32 fmt, int w, int h, int interval_numerator, int interval_denominator);
typedef struct SurfaceList typedef struct SurfaceList
{ {
SDL_Surface *surface; SDL_Surface *surface;
@@ -189,5 +199,6 @@ extern CameraBootStrap V4L2_bootstrap;
extern CameraBootStrap COREMEDIA_bootstrap; extern CameraBootStrap COREMEDIA_bootstrap;
extern CameraBootStrap ANDROIDCAMERA_bootstrap; extern CameraBootStrap ANDROIDCAMERA_bootstrap;
extern CameraBootStrap EMSCRIPTENCAMERA_bootstrap; extern CameraBootStrap EMSCRIPTENCAMERA_bootstrap;
extern CameraBootStrap MEDIAFOUNDATION_bootstrap;
#endif // SDL_syscamera_h_ #endif // SDL_syscamera_h_
+1 -1
View File
@@ -77,4 +77,4 @@ CameraBootStrap DUMMYCAMERA_bootstrap = {
"dummy", "SDL dummy camera driver", DUMMYCAMERA_Init, SDL_TRUE "dummy", "SDL dummy camera driver", DUMMYCAMERA_Init, SDL_TRUE
}; };
#endif #endif // SDL_CAMERA_DRIVER_DUMMY
@@ -79,8 +79,6 @@ static int EMSCRIPTENCAMERA_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *
static void EMSCRIPTENCAMERA_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame) static void EMSCRIPTENCAMERA_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{ {
SDL_free(frame->pixels); SDL_free(frame->pixels);
frame->pixels = NULL;
frame->pitch = 0;
} }
static void EMSCRIPTENCAMERA_CloseDevice(SDL_CameraDevice *device) static void EMSCRIPTENCAMERA_CloseDevice(SDL_CameraDevice *device)
File diff suppressed because it is too large Load Diff
+5 -37
View File
@@ -631,39 +631,7 @@ static SDL_bool FindV4L2CameraDeviceByBusInfoCallback(SDL_CameraDevice *device,
return (SDL_strcmp(handle->bus_info, (const char *) userdata) == 0); return (SDL_strcmp(handle->bus_info, (const char *) userdata) == 0);
} }
typedef struct FormatAddData static int AddCameraFormat(const int fd, CameraFormatAddData *data, Uint32 sdlfmt, Uint32 v4l2fmt, int w, int h)
{
SDL_CameraSpec *specs;
int num_specs;
int allocated_specs;
} FormatAddData;
static int AddCameraCompleteFormat(FormatAddData *data, Uint32 fmt, int w, int h, int interval_numerator, int interval_denominator)
{
SDL_assert(data != NULL);
if (data->allocated_specs <= data->num_specs) {
const int newalloc = data->allocated_specs ? (data->allocated_specs * 2) : 16;
void *ptr = SDL_realloc(data->specs, sizeof (SDL_CameraSpec) * newalloc);
if (!ptr) {
return -1;
}
data->specs = (SDL_CameraSpec *) ptr;
data->allocated_specs = newalloc;
}
SDL_CameraSpec *spec = &data->specs[data->num_specs];
spec->format = fmt;
spec->width = w;
spec->height = h;
spec->interval_numerator = interval_numerator;
spec->interval_denominator = interval_denominator;
data->num_specs++;
return 0;
}
static int AddCameraFormat(const int fd, FormatAddData *data, Uint32 sdlfmt, Uint32 v4l2fmt, int w, int h)
{ {
struct v4l2_frmivalenum frmivalenum; struct v4l2_frmivalenum frmivalenum;
SDL_zero(frmivalenum); SDL_zero(frmivalenum);
@@ -679,7 +647,7 @@ static int AddCameraFormat(const int fd, FormatAddData *data, Uint32 sdlfmt, Uin
const float fps = (float) denominator / (float) numerator; const float fps = (float) denominator / (float) numerator;
SDL_Log("CAMERA: * Has discrete frame interval (%d / %d), fps=%f", numerator, denominator, fps); SDL_Log("CAMERA: * Has discrete frame interval (%d / %d), fps=%f", numerator, denominator, fps);
#endif #endif
if (AddCameraCompleteFormat(data, sdlfmt, w, h, numerator, denominator) == -1) { if (SDL_AddCameraFormat(data, sdlfmt, w, h, numerator, denominator) == -1) {
return -1; // Probably out of memory; we'll go with what we have, if anything. return -1; // Probably out of memory; we'll go with what we have, if anything.
} }
frmivalenum.index++; // set up for the next one. frmivalenum.index++; // set up for the next one.
@@ -691,7 +659,7 @@ static int AddCameraFormat(const int fd, FormatAddData *data, Uint32 sdlfmt, Uin
const float fps = (float) d / (float) n; const float fps = (float) d / (float) n;
SDL_Log("CAMERA: * Has %s frame interval (%d / %d), fps=%f", (frmivalenum.type == V4L2_FRMIVAL_TYPE_STEPWISE) ? "stepwise" : "continuous", n, d, fps); SDL_Log("CAMERA: * Has %s frame interval (%d / %d), fps=%f", (frmivalenum.type == V4L2_FRMIVAL_TYPE_STEPWISE) ? "stepwise" : "continuous", n, d, fps);
#endif #endif
if (AddCameraCompleteFormat(data, sdlfmt, w, h, n, d) == -1) { if (SDL_AddCameraFormat(data, sdlfmt, w, h, n, d) == -1) {
return -1; // Probably out of memory; we'll go with what we have, if anything. return -1; // Probably out of memory; we'll go with what we have, if anything.
} }
d += (int) frmivalenum.stepwise.step.denominator; d += (int) frmivalenum.stepwise.step.denominator;
@@ -739,7 +707,7 @@ static void MaybeAddDevice(const char *path)
SDL_Log("CAMERA: V4L2 camera path='%s' bus_info='%s' name='%s'", path, (const char *) vcap.bus_info, vcap.card); SDL_Log("CAMERA: V4L2 camera path='%s' bus_info='%s' name='%s'", path, (const char *) vcap.bus_info, vcap.card);
#endif #endif
FormatAddData add_data; CameraFormatAddData add_data;
SDL_zero(add_data); SDL_zero(add_data);
struct v4l2_fmtdesc fmtdesc; struct v4l2_fmtdesc fmtdesc;
@@ -911,5 +879,5 @@ CameraBootStrap V4L2_bootstrap = {
"v4l2", "SDL Video4Linux2 camera driver", V4L2_Init, SDL_FALSE "v4l2", "SDL Video4Linux2 camera driver", V4L2_Init, SDL_FALSE
}; };
#endif // SDL_CAMERA_V4L2 #endif // SDL_CAMERA_DRIVER_V4L2