@@ -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)
196280done :
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