Skip to content

Commit a1de9d2

Browse files
authored
apple: fix ffmpeg camera driver (#18203)
1 parent a5b06a3 commit a1de9d2

1 file changed

Lines changed: 110 additions & 3 deletions

File tree

camera/drivers/ffmpeg.c

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ static int ffmpeg_camera_get_initial_options(
9797
{
9898
int result = 0;
9999
char dimensions[128];
100+
101+
#ifdef __APPLE__
102+
/* For AVFoundation, we need to handle options differently */
103+
if (backend && string_is_equal(backend->name, "avfoundation"))
104+
{
105+
/* AVFoundation expects these options to be passed to avformat_open_input */
106+
/* We'll set them later in ffmpeg_camera_open_device */
107+
return 0;
108+
}
109+
#endif
110+
100111
if (width != 0 && height != 0)
101112
{ /* If the core is letting the frontend pick the size... */
102113
snprintf(dimensions, sizeof(dimensions), "%ux%u", width, height);
@@ -143,7 +154,8 @@ static void ffmpeg_camera_get_source_url(ffmpeg_camera_t *ffmpeg, const AVDevice
143154
if (string_is_equal(ffmpeg->input_format->name, "avfoundation"))
144155
{
145156
/* we only want video, not audio */
146-
snprintf(ffmpeg->url, sizeof(ffmpeg->url), "%s:none", device->device_description);
157+
/* Use "0:none" for the first video device, no audio */
158+
snprintf(ffmpeg->url, sizeof(ffmpeg->url), "0:none");
147159
return;
148160
}
149161
#endif
@@ -172,13 +184,85 @@ static int ffmpeg_camera_open_device(ffmpeg_camera_t *ffmpeg)
172184
goto done;
173185
}
174186

187+
#ifdef __APPLE__
188+
/* For AVFoundation, set the options that the device expects */
189+
if (ffmpeg->input_format && string_is_equal(ffmpeg->input_format->name, "avfoundation"))
190+
{
191+
char dimensions[128];
192+
193+
/* Set video size if requested */
194+
if (ffmpeg->requested_width != 0 && ffmpeg->requested_height != 0)
195+
{
196+
/* Use a resolution that the device likely supports */
197+
/* Common resolutions: 640x480, 1280x720, 1920x1080 */
198+
unsigned width = ffmpeg->requested_width;
199+
unsigned height = ffmpeg->requested_height;
200+
201+
/* If the requested resolution is too small, use a minimum supported size */
202+
if (width < 640 || height < 480)
203+
{
204+
width = 640;
205+
height = 480;
206+
RARCH_LOG("[FFMPEG] Requested resolution %ux%u too small, using %ux%u instead.\n",
207+
ffmpeg->requested_width, ffmpeg->requested_height, width, height);
208+
}
209+
210+
snprintf(dimensions, sizeof(dimensions), "%ux%u", width, height);
211+
av_dict_set(&options, "video_size", dimensions, 0);
212+
}
213+
214+
/* Set framerate */
215+
av_dict_set(&options, "framerate", "30", 0);
216+
217+
/* Set pixel format to a widely supported format */
218+
av_dict_set(&options, "pixel_format", "uyvy422", 0);
219+
}
220+
#endif
221+
175222
result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &options);
176223
if (result < 0)
177224
{
178225
char msg[AV_ERROR_MAX_STRING_SIZE];
179226
av_make_error_string(msg, AV_ERROR_MAX_STRING_SIZE, result);
180227
RARCH_WARN("[FFMPEG] Failed to open video input device \"%s\": %s.\n", ffmpeg->url, msg);
181228

229+
#ifdef __APPLE__
230+
/* For AVFoundation, try with default settings if custom settings fail */
231+
if (ffmpeg->input_format && string_is_equal(ffmpeg->input_format->name, "avfoundation"))
232+
{
233+
RARCH_LOG("[FFMPEG] Trying with default AVFoundation settings...\n");
234+
av_dict_free(&options);
235+
236+
/* Try with just the basic framerate option */
237+
av_dict_set(&options, "framerate", "30", 0);
238+
239+
result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &options);
240+
if (result < 0)
241+
{
242+
av_make_error_string(msg, AV_ERROR_MAX_STRING_SIZE, result);
243+
RARCH_WARN("[FFMPEG] Failed with basic options, trying with no options: %s.\n", msg);
244+
av_dict_free(&options);
245+
246+
/* Last resort: try with no options at all */
247+
result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, NULL);
248+
if (result < 0)
249+
{
250+
av_make_error_string(msg, AV_ERROR_MAX_STRING_SIZE, result);
251+
RARCH_ERR("[FFMPEG] Failed to open device even with default settings: %s.\n", msg);
252+
goto done;
253+
}
254+
else
255+
{
256+
RARCH_LOG("[FFMPEG] Successfully opened device with default settings.\n");
257+
}
258+
}
259+
else
260+
{
261+
RARCH_LOG("[FFMPEG] Successfully opened device with basic settings.\n");
262+
}
263+
}
264+
else
265+
#endif
182266
if (ffmpeg->options)
183267
{ /* If we're not already requesting the default format... */
184268

@@ -196,8 +280,8 @@ static int ffmpeg_camera_open_device(ffmpeg_camera_t *ffmpeg)
196280
done:
197281
if (options)
198282
{
199-
const AVDictionaryEntry *prev = NULL;
200-
while ((e = av_dict_get(options, "", prev, AV_DICT_IGNORE_SUFFIX)))
283+
e = NULL;
284+
while ((e = av_dict_get(options, "", e, AV_DICT_IGNORE_SUFFIX)))
201285
{
202286
/* av_dict_iterate isn't always available, so we use av_dict_get's legacy behavior instead */
203287
RARCH_WARN("[FFMPEG] Unrecognized option on video input device: %s=%s.\n", e->key, e->value);
@@ -258,6 +342,28 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt
258342
}
259343

260344
num_sources = avdevice_list_input_sources(ffmpeg->input_format, NULL, ffmpeg->options, &device_list);
345+
346+
#ifdef __APPLE__
347+
/* AVFoundation device listing may fail or return -38 (function not implemented) */
348+
/* but we can still use the device with index 0 */
349+
if (num_sources < 0)
350+
{
351+
char msg[AV_ERROR_MAX_STRING_SIZE];
352+
av_make_error_string(msg, AV_ERROR_MAX_STRING_SIZE, num_sources);
353+
RARCH_WARN("[FFMPEG] Device enumeration not fully supported on AVFoundation: %s. Using default device.\n", msg);
354+
/* Continue with default device */
355+
ffmpeg_camera_get_source_url(ffmpeg, NULL);
356+
}
357+
else if (num_sources == 0)
358+
{
359+
RARCH_ERR("[FFMPEG] No video input sources found.\n");
360+
goto error;
361+
}
362+
else
363+
{
364+
ffmpeg_camera_get_source_url(ffmpeg, device_list->devices[0]);
365+
}
366+
#else
261367
if (num_sources == 0)
262368
{
263369
RARCH_ERR("[FFMPEG] No video input sources found.\n");
@@ -273,6 +379,7 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt
273379
}
274380

275381
ffmpeg_camera_get_source_url(ffmpeg, device_list->devices[0]);
382+
#endif
276383
RARCH_LOG("[FFMPEG] Using video input device: %s (%s, flags=0x%x).\n", ffmpeg->input_format->name, ffmpeg->input_format->long_name, ffmpeg->input_format->flags);
277384

278385
avdevice_free_list_devices(&device_list);

0 commit comments

Comments
 (0)