FFmpeg
Loading...
Searching...
No Matches
avfoundation.m
Go to the documentation of this file.
1/*
2 * AVFoundation input device
3 * Copyright (c) 2014 Thilo Borgmann <thilo.borgmann@mail.de>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * AVFoundation input device
25 * @author Thilo Borgmann <thilo.borgmann@mail.de>
26 */
27
28#include "config.h"
29
30#import <AVFoundation/AVFoundation.h>
31#if HAVE_IOKIT
32# import <IOKit/IOKitLib.h>
33 /* kIOMainPortDefault is only available since macOS 12 or iOS 15; fall back
34 * to the equivalent kIOMasterPortDefault on macOS when targeting older
35 * releases. */
36# if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 150000)
37# define AVF_IO_MAIN_PORT_DEFAULT kIOMainPortDefault
38# elif TARGET_OS_OSX
39# define AVF_IO_MAIN_PORT_DEFAULT kIOMasterPortDefault
40# endif
41#endif
42
43#include <pthread.h>
44
46#include "libavutil/mem.h"
47#include "libavutil/pixdesc.h"
48#include "libavutil/opt.h"
49#include "libavutil/avstring.h"
50#include "libavformat/demux.h"
52#include "libavutil/internal.h"
54#include "libavutil/time.h"
55#include "libavutil/imgutils.h"
56#include "avdevice.h"
57
58static const int avf_time_base = 1000000;
59
61 .num = 1,
62 .den = avf_time_base
63};
64
69
70static const struct AVFPixelFormatSpec avf_pixel_formats[] = {
71 { AV_PIX_FMT_MONOBLACK, kCVPixelFormatType_1Monochrome },
72 { AV_PIX_FMT_RGB555BE, kCVPixelFormatType_16BE555 },
73 { AV_PIX_FMT_RGB555LE, kCVPixelFormatType_16LE555 },
74 { AV_PIX_FMT_RGB565BE, kCVPixelFormatType_16BE565 },
75 { AV_PIX_FMT_RGB565LE, kCVPixelFormatType_16LE565 },
76 { AV_PIX_FMT_RGB24, kCVPixelFormatType_24RGB },
77 { AV_PIX_FMT_BGR24, kCVPixelFormatType_24BGR },
78 { AV_PIX_FMT_0RGB, kCVPixelFormatType_32ARGB },
79 { AV_PIX_FMT_BGR0, kCVPixelFormatType_32BGRA },
80 { AV_PIX_FMT_0BGR, kCVPixelFormatType_32ABGR },
81 { AV_PIX_FMT_RGB0, kCVPixelFormatType_32RGBA },
82 { AV_PIX_FMT_BGR48BE, kCVPixelFormatType_48RGB },
83 { AV_PIX_FMT_UYVY422, kCVPixelFormatType_422YpCbCr8 },
84 { AV_PIX_FMT_YUVA444P, kCVPixelFormatType_4444YpCbCrA8R },
85 { AV_PIX_FMT_YUVA444P16LE, kCVPixelFormatType_4444AYpCbCr16 },
86 { AV_PIX_FMT_YUV444P, kCVPixelFormatType_444YpCbCr8 },
87 { AV_PIX_FMT_YUV422P16, kCVPixelFormatType_422YpCbCr16 },
88 { AV_PIX_FMT_YUV422P10, kCVPixelFormatType_422YpCbCr10 },
89 { AV_PIX_FMT_YUV444P10, kCVPixelFormatType_444YpCbCr10 },
90 { AV_PIX_FMT_YUV420P, kCVPixelFormatType_420YpCbCr8Planar },
91 { AV_PIX_FMT_NV12, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange },
92 { AV_PIX_FMT_YUYV422, kCVPixelFormatType_422YpCbCr8_yuvs },
93#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
94 { AV_PIX_FMT_GRAY8, kCVPixelFormatType_OneComponent8 },
95#endif
96 { AV_PIX_FMT_NONE, 0 }
97};
98
160
162{
163 pthread_mutex_lock(&ctx->frame_lock);
164}
165
167{
168 pthread_cond_broadcast(&ctx->frame_wait_cond);
169 pthread_mutex_unlock(&ctx->frame_lock);
170}
171
172/** FrameReceiver class - delegate for AVCaptureSession
173 */
174@interface AVFFrameReceiver : NSObject
175{
177}
178
179- (id)initWithContext:(AVFContext*)context;
180
181- (void) captureOutput:(AVCaptureOutput *)captureOutput
182 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
183 fromConnection:(AVCaptureConnection *)connection;
184
185@end
186
187@implementation AVFFrameReceiver
188
189- (id)initWithContext:(AVFContext*)context
190{
191 if (self = [super init]) {
192 _context = context;
193
194 // start observing if a device is set for it
195#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
196 if (_context->observed_device) {
197 NSString *keyPath = NSStringFromSelector(@selector(transportControlsPlaybackMode));
198 NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew;
199
200 [_context->observed_device addObserver: self
201 forKeyPath: keyPath
202 options: options
203 context: _context];
204 }
205#endif
206 }
207 return self;
208}
209
210- (void)dealloc {
211 // stop observing if a device is set for it
212#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
214 NSString *keyPath = NSStringFromSelector(@selector(transportControlsPlaybackMode));
215 [_context->observed_device removeObserver: self forKeyPath: keyPath];
216 }
217#endif
218 [super dealloc];
219}
220
221- (void)observeValueForKeyPath:(NSString *)keyPath
222 ofObject:(id)object
223 change:(NSDictionary *)change
224 context:(void *)context {
225 if (context == _context) {
226#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
227 AVCaptureDeviceTransportControlsPlaybackMode mode =
228 [change[NSKeyValueChangeNewKey] integerValue];
229
230 if (mode != _context->observed_mode) {
231 if (mode == AVCaptureDeviceTransportControlsNotPlayingMode) {
232 // Set under the lock and broadcast so a reader blocked in
233 // avf_read_packet() wakes up and returns EOF instead of
234 // hanging once the device stops delivering frames.
236 _context->observed_quit = 1;
238 }
239 _context->observed_mode = mode;
240 }
241#endif
242 } else {
243 [super observeValueForKeyPath: keyPath
244 ofObject: object
245 change: change
246 context: context];
247 }
248}
249
250- (void) captureOutput:(AVCaptureOutput *)captureOutput
251 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
252 fromConnection:(AVCaptureConnection *)connection
253{
255
256 while ((_context->current_frame != nil) && !_context->is_stopping) {
257 pthread_cond_wait(&_context->frame_wait_cond, &_context->frame_lock);
258 }
259
260 if (_context->is_stopping) {
262 return;
263 }
264
265 _context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame);
266
268
269 ++_context->frames_captured;
270}
271
272@end
273
274/** AudioReceiver class - delegate for AVCaptureSession
275 */
276@interface AVFAudioReceiver : NSObject
277{
279}
280
281- (id)initWithContext:(AVFContext*)context;
282
283- (void) captureOutput:(AVCaptureOutput *)captureOutput
284 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
285 fromConnection:(AVCaptureConnection *)connection;
286
287@end
288
289@implementation AVFAudioReceiver
290
291- (id)initWithContext:(AVFContext*)context
292{
293 if (self = [super init]) {
294 _context = context;
295 }
296 return self;
297}
298
299- (void) captureOutput:(AVCaptureOutput *)captureOutput
300 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
301 fromConnection:(AVCaptureConnection *)connection
302{
304
305 while ((_context->current_audio_frame != nil) && !_context->is_stopping) {
306 pthread_cond_wait(&_context->frame_wait_cond, &_context->frame_lock);
307 }
308
309 if (_context->is_stopping) {
311 return;
312 }
313
314 _context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame);
315
317
318 ++_context->audio_frames_captured;
319}
320
321@end
322
324{
325 // Wake any capture callback blocked waiting for the consumer and make it
326 // bail out, so stopRunning() can drain the session without a deadlock.
328 ctx->is_stopping = 1;
330
331 [ctx->capture_session stopRunning];
332
333 [ctx->capture_session release];
334 [ctx->video_output release];
335 [ctx->audio_output release];
336 [ctx->avf_delegate release];
337 [ctx->avf_audio_delegate release];
338
339 ctx->capture_session = NULL;
340 ctx->video_output = NULL;
341 ctx->audio_output = NULL;
342 ctx->avf_delegate = NULL;
343 ctx->avf_audio_delegate = NULL;
344
345 av_freep(&ctx->url);
346 av_freep(&ctx->audio_buffer);
347
348 pthread_cond_destroy(&ctx->frame_wait_cond);
349 pthread_mutex_destroy(&ctx->frame_lock);
350
351 if (ctx->current_frame) {
352 CFRelease(ctx->current_frame);
353 ctx->current_frame = nil;
354 }
355
356 if (ctx->current_audio_frame) {
357 CFRelease(ctx->current_audio_frame);
358 ctx->current_audio_frame = nil;
359 }
360}
361
363{
364 AVFContext *ctx = (AVFContext*)s->priv_data;
365 char *save;
366
367 ctx->url = av_strdup(s->url);
368
369 if (!ctx->url)
370 return AVERROR(ENOMEM);
371 if (ctx->url[0] != ':') {
372 ctx->video_filename = av_strtok(ctx->url, ":", &save);
373 ctx->audio_filename = av_strtok(NULL, ":", &save);
374 } else {
375 ctx->audio_filename = av_strtok(ctx->url, ":", &save);
376 }
377 return 0;
378}
379
380/**
381 * Configure the video device.
382 *
383 * Configure the video device using a run-time approach to access properties
384 * since formats, activeFormat are available since iOS >= 7.0 or OSX >= 10.7
385 * and activeVideoMaxFrameDuration is available since i0S >= 7.0 and OSX >= 10.9.
386 *
387 * The NSUndefinedKeyException must be handled by the caller of this function.
388 *
389 */
390static int configure_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
391{
392 AVFContext *ctx = (AVFContext*)s->priv_data;
393
394 double framerate = av_q2d(ctx->framerate);
395 NSObject *range = nil;
396 NSObject *format = nil;
397 NSObject *matching_size_format = nil;
398 NSObject *selected_range = nil;
399 NSObject *selected_format = nil;
400
401 // try to configure format by formats list
402 // might raise an exception if no format list is given
403 // (then fallback to default, no configuration)
404 @try {
405 for (format in [video_device valueForKey:@"formats"]) {
406 CMFormatDescriptionRef formatDescription;
407 CMVideoDimensions dimensions;
408
409 formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)];
410 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
411
412 if ((ctx->width == 0 && ctx->height == 0) ||
413 (dimensions.width == ctx->width && dimensions.height == ctx->height)) {
414
415 matching_size_format = format;
416
417 for (range in [format valueForKey:@"videoSupportedFrameRateRanges"]) {
418 double max_framerate;
419
420 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
421 if (fabs (framerate - max_framerate) < 0.01) {
422 selected_format = format;
423 selected_range = range;
424 break;
425 }
426 }
427 }
428 }
429
430 if (!matching_size_format) {
431 av_log(s, AV_LOG_ERROR, "Selected video size (%dx%d) is not supported by the device.\n",
432 ctx->width, ctx->height);
433 goto unsupported_format;
434 }
435
436 if (!selected_range) {
437 av_log(s, AV_LOG_ERROR, "Selected framerate (%f) is not supported by the device.\n",
438 framerate);
439 if (ctx->video_is_muxed) {
440 selected_format = matching_size_format;
441 av_log(s, AV_LOG_ERROR, "Falling back to default.\n");
442 } else {
443 goto unsupported_format;
444 }
445 }
446
447 if ([video_device lockForConfiguration:NULL] == YES) {
448 if (selected_format) {
449 [video_device setValue:selected_format forKey:@"activeFormat"];
450 }
451 if (selected_range) {
452 NSValue *min_frame_duration = [selected_range valueForKey:@"minFrameDuration"];
453 [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"];
454 [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"];
455 }
456 } else {
457 av_log(s, AV_LOG_ERROR, "Could not lock device for configuration.\n");
458 return AVERROR(EINVAL);
459 }
460 } @catch(NSException *e) {
461 av_log(ctx, AV_LOG_WARNING, "Configuration of video device failed, falling back to default.\n");
462 }
463
464 return 0;
465
466unsupported_format:
467
468 av_log(s, AV_LOG_ERROR, "Supported modes:\n");
469 for (format in [video_device valueForKey:@"formats"]) {
470 CMFormatDescriptionRef formatDescription;
471 CMVideoDimensions dimensions;
472
473 formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)];
474 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
475
476 for (range in [format valueForKey:@"videoSupportedFrameRateRanges"]) {
477 double min_framerate;
478 double max_framerate;
479
480 [[range valueForKey:@"minFrameRate"] getValue:&min_framerate];
481 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
482 av_log(s, AV_LOG_ERROR, " %dx%d@[%f %f]fps\n",
483 dimensions.width, dimensions.height,
484 min_framerate, max_framerate);
485 }
486 }
487 return AVERROR(EINVAL);
488}
489
490static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
491{
492 AVFContext *ctx = (AVFContext*)s->priv_data;
493 int ret;
494 NSError *error = nil;
495 AVCaptureInput* capture_input = nil;
496 struct AVFPixelFormatSpec pxl_fmt_spec;
497 NSNumber *pixel_format;
498 NSDictionary *capture_dict;
499 dispatch_queue_t queue;
500
501 if (!ctx->video_is_screen) {
502 capture_input = (AVCaptureInput*) [[[AVCaptureDeviceInput alloc] initWithDevice:video_device error:&error] autorelease];
503 } else {
504 capture_input = (AVCaptureInput*) video_device;
505 }
506
507 if (!capture_input) {
508 av_log(s, AV_LOG_ERROR, "Failed to create AV capture input device: %s\n",
509 [[error localizedDescription] UTF8String]);
510 return 1;
511 }
512
513 if ([ctx->capture_session canAddInput:capture_input]) {
514 [ctx->capture_session addInput:capture_input];
515 } else {
516 av_log(s, AV_LOG_ERROR, "can't add video input to capture session\n");
517 return 1;
518 }
519
520 // Attaching output
521 ctx->video_output = [[AVCaptureVideoDataOutput alloc] init];
522
523 if (!ctx->video_output) {
524 av_log(s, AV_LOG_ERROR, "Failed to init AV video output\n");
525 return 1;
526 }
527
528 // Configure device framerate and video size
529 @try {
530 if ((ret = configure_video_device(s, video_device)) < 0) {
531 return ret;
532 }
533 } @catch (NSException *exception) {
534 if (![[exception name] isEqualToString:NSUndefinedKeyException]) {
535 av_log (s, AV_LOG_ERROR, "An error occurred: %s", [exception.reason UTF8String]);
536 return AVERROR_EXTERNAL;
537 }
538 }
539
540 // select pixel format
541 pxl_fmt_spec.ff_id = AV_PIX_FMT_NONE;
542
543 for (int i = 0; avf_pixel_formats[i].ff_id != AV_PIX_FMT_NONE; i++) {
544 if (ctx->pixel_format == avf_pixel_formats[i].ff_id) {
545 pxl_fmt_spec = avf_pixel_formats[i];
546 break;
547 }
548 }
549
550 // check if selected pixel format is supported by AVFoundation
551 if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) {
552 av_log(s, AV_LOG_ERROR, "Selected pixel format (%s) is not supported by AVFoundation.\n",
553 av_get_pix_fmt_name(pxl_fmt_spec.ff_id));
554 return 1;
555 }
556
557 // check if the pixel format is available for this device
558 if ([[ctx->video_output availableVideoCVPixelFormatTypes] indexOfObject:[NSNumber numberWithInt:pxl_fmt_spec.avf_id]] == NSNotFound) {
559 av_log(s, AV_LOG_ERROR, "Selected pixel format (%s) is not supported by the input device.\n",
560 av_get_pix_fmt_name(pxl_fmt_spec.ff_id));
561
562 pxl_fmt_spec.ff_id = AV_PIX_FMT_NONE;
563
564 av_log(s, AV_LOG_ERROR, "Supported pixel formats:\n");
565 for (NSNumber *pxl_fmt in [ctx->video_output availableVideoCVPixelFormatTypes]) {
566 struct AVFPixelFormatSpec pxl_fmt_dummy;
567 pxl_fmt_dummy.ff_id = AV_PIX_FMT_NONE;
568 for (int i = 0; avf_pixel_formats[i].ff_id != AV_PIX_FMT_NONE; i++) {
569 if ([pxl_fmt intValue] == avf_pixel_formats[i].avf_id) {
570 pxl_fmt_dummy = avf_pixel_formats[i];
571 break;
572 }
573 }
574
575 if (pxl_fmt_dummy.ff_id != AV_PIX_FMT_NONE) {
576 av_log(s, AV_LOG_ERROR, " %s\n", av_get_pix_fmt_name(pxl_fmt_dummy.ff_id));
577
578 // select first supported pixel format instead of user selected (or default) pixel format
579 if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) {
580 pxl_fmt_spec = pxl_fmt_dummy;
581 }
582 }
583 }
584
585 // fail if there is no appropriate pixel format or print a warning about overriding the pixel format
586 if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) {
587 return 1;
588 } else {
589 av_log(s, AV_LOG_WARNING, "Overriding selected pixel format to use %s instead.\n",
590 av_get_pix_fmt_name(pxl_fmt_spec.ff_id));
591 }
592 }
593
594 // set videoSettings to an empty dict for receiving raw data of muxed devices
595 if (ctx->capture_raw_data) {
596 ctx->pixel_format = pxl_fmt_spec.ff_id;
597 ctx->video_output.videoSettings = @{ };
598 } else {
599 ctx->pixel_format = pxl_fmt_spec.ff_id;
600 pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id];
601 capture_dict = [NSDictionary dictionaryWithObject:pixel_format
602 forKey:(id)kCVPixelBufferPixelFormatTypeKey];
603
604 [ctx->video_output setVideoSettings:capture_dict];
605 }
606 [ctx->video_output setAlwaysDiscardsLateVideoFrames:ctx->drop_late_frames];
607
608#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
609 // check for transport control support and set observer device if supported
610 if (!ctx->video_is_screen) {
611 int trans_ctrl = [video_device transportControlsSupported];
612 AVCaptureDeviceTransportControlsPlaybackMode trans_mode = [video_device transportControlsPlaybackMode];
613
614 if (trans_ctrl) {
615 ctx->observed_mode = trans_mode;
616 ctx->observed_device = video_device;
617 }
618 }
619#endif
620
621 ctx->avf_delegate = [[AVFFrameReceiver alloc] initWithContext:ctx];
622
623 queue = dispatch_queue_create("avf_queue", NULL);
624 [ctx->video_output setSampleBufferDelegate:ctx->avf_delegate queue:queue];
625 dispatch_release(queue);
626
627 if ([ctx->capture_session canAddOutput:ctx->video_output]) {
628 [ctx->capture_session addOutput:ctx->video_output];
629 } else {
630 av_log(s, AV_LOG_ERROR, "can't add video output to capture session\n");
631 return 1;
632 }
633
634 return 0;
635}
636
637static int add_audio_device(AVFormatContext *s, AVCaptureDevice *audio_device)
638{
639 AVFContext *ctx = (AVFContext*)s->priv_data;
640 NSError *error = nil;
641 AVCaptureDeviceInput* audio_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:audio_device error:&error] autorelease];
642 dispatch_queue_t queue;
643
644 if (!audio_dev_input) {
645 av_log(s, AV_LOG_ERROR, "Failed to create AV capture input device: %s\n",
646 [[error localizedDescription] UTF8String]);
647 return 1;
648 }
649
650 if ([ctx->capture_session canAddInput:audio_dev_input]) {
651 [ctx->capture_session addInput:audio_dev_input];
652 } else {
653 av_log(s, AV_LOG_ERROR, "can't add audio input to capture session\n");
654 return 1;
655 }
656
657 // Attaching output
658 ctx->audio_output = [[AVCaptureAudioDataOutput alloc] init];
659
660 if (!ctx->audio_output) {
661 av_log(s, AV_LOG_ERROR, "Failed to init AV audio output\n");
662 return 1;
663 }
664
665 ctx->avf_audio_delegate = [[AVFAudioReceiver alloc] initWithContext:ctx];
666
667 queue = dispatch_queue_create("avf_audio_queue", NULL);
668 [ctx->audio_output setSampleBufferDelegate:ctx->avf_audio_delegate queue:queue];
669 dispatch_release(queue);
670
671 if ([ctx->capture_session canAddOutput:ctx->audio_output]) {
672 [ctx->capture_session addOutput:ctx->audio_output];
673 } else {
674 av_log(s, AV_LOG_ERROR, "adding audio output to capture session failed\n");
675 return 1;
676 }
677
678 return 0;
679}
680
682{
683 AVFContext *ctx = (AVFContext*)s->priv_data;
684 CVImageBufferRef image_buffer;
685 CGSize image_buffer_size;
687
688 if (!stream) {
689 return 1;
690 }
691
692 // Take stream info from the first frame.
693 while (ctx->frames_captured < 1) {
694 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
695 }
696
698
699 ctx->video_stream_index = stream->index;
700
701 avpriv_set_pts_info(stream, 64, 1, avf_time_base);
702
703 image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame);
704
705 if (image_buffer) {
706 image_buffer_size = CVImageBufferGetEncodedSize(image_buffer);
707
710 stream->codecpar->width = (int)image_buffer_size.width;
711 stream->codecpar->height = (int)image_buffer_size.height;
712 stream->codecpar->format = ctx->pixel_format;
713 } else {
716 stream->codecpar->format = ctx->pixel_format;
717 }
718
719 CFRelease(ctx->current_frame);
720 ctx->current_frame = nil;
721
723
724 return 0;
725}
726
728{
729 AVFContext *ctx = (AVFContext*)s->priv_data;
730 CMFormatDescriptionRef format_desc;
732
733 if (!stream) {
734 return 1;
735 }
736
737 // Take stream info from the first frame.
738 while (ctx->audio_frames_captured < 1) {
739 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
740 }
741
743
744 ctx->audio_stream_index = stream->index;
745
746 avpriv_set_pts_info(stream, 64, 1, avf_time_base);
747
748 format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame);
749 const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc);
750
751 if (!basic_desc) {
753 av_log(s, AV_LOG_ERROR, "audio format not available\n");
754 return 1;
755 }
756
758 stream->codecpar->sample_rate = basic_desc->mSampleRate;
759 av_channel_layout_default(&stream->codecpar->ch_layout, basic_desc->mChannelsPerFrame);
760
761 ctx->audio_channels = basic_desc->mChannelsPerFrame;
762 ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel;
763 ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat;
764 ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
765 ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
766 ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked;
767 ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved;
768
769 if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
770 ctx->audio_float &&
771 ctx->audio_bits_per_sample == 32 &&
772 ctx->audio_packed) {
774 } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
775 ctx->audio_signed_integer &&
776 ctx->audio_bits_per_sample == 16 &&
777 ctx->audio_packed) {
779 } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
780 ctx->audio_signed_integer &&
781 ctx->audio_bits_per_sample == 24 &&
782 ctx->audio_packed) {
784 } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
785 ctx->audio_signed_integer &&
786 ctx->audio_bits_per_sample == 32 &&
787 ctx->audio_packed) {
789 } else {
791 av_log(s, AV_LOG_ERROR, "audio format is not supported\n");
792 return 1;
793 }
794
795 if (ctx->audio_non_interleaved) {
796 CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame);
797 ctx->audio_buffer_size = CMBlockBufferGetDataLength(block_buffer);
798 ctx->audio_buffer = av_malloc(ctx->audio_buffer_size);
799 if (!ctx->audio_buffer) {
801 av_log(s, AV_LOG_ERROR, "error allocating audio buffer\n");
802 return 1;
803 }
804 }
805
806 CFRelease(ctx->current_audio_frame);
807 ctx->current_audio_frame = nil;
808
810
811 return 0;
812}
813
814static NSArray* getDevicesWithMediaType(AVMediaType mediaType) {
815#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500))
816 NSMutableArray *deviceTypes = nil;
817 if (mediaType == AVMediaTypeVideo) {
818 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInWideAngleCamera]];
819 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
820 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualCamera];
821 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTelephotoCamera];
822 #endif
823 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110100)
824 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTrueDepthCamera];
825 #endif
826 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000)
827 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTripleCamera];
828 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualWideCamera];
829 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInUltraWideCamera];
830 #endif
831 #if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000)
832 [deviceTypes addObject: AVCaptureDeviceTypeDeskViewCamera];
833 #endif
834 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 150400)
835 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInLiDARDepthCamera];
836 #endif
837 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
838 [deviceTypes addObject: AVCaptureDeviceTypeContinuityCamera];
839 [deviceTypes addObject: AVCaptureDeviceTypeExternal];
840 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
841 [deviceTypes addObject: AVCaptureDeviceTypeExternalUnknown];
842 #endif
843 } else if (mediaType == AVMediaTypeAudio) {
844 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
845 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeMicrophone]];
846 #else
847 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInMicrophone]];
848 #endif
849 } else if (mediaType == AVMediaTypeMuxed) {
850 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
851 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternal]];
852 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
853 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternalUnknown]];
854 #else
855 return nil;
856 #endif
857 } else {
858 return nil;
859 }
860
861 AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession =
862 [AVCaptureDeviceDiscoverySession
863 discoverySessionWithDeviceTypes:deviceTypes
864 mediaType:mediaType
865 position:AVCaptureDevicePositionUnspecified];
866 return [captureDeviceDiscoverySession devices];
867#elif TARGET_OS_OSX
868 return [AVCaptureDevice devicesWithMediaType:mediaType];
869#else
870 return nil;
871#endif
872}
873
874#if HAVE_IOKIT && defined(AVF_IO_MAIN_PORT_DEFAULT)
875static int avf_io_get_string(io_service_t service, CFStringRef key, char *buf, size_t size)
876{
877 CFTypeRef ref = IORegistryEntryCreateCFProperty(service, key, kCFAllocatorDefault, 0);
878 int ok = ref && CFGetTypeID(ref) == CFStringGetTypeID() && CFStringGetCString(ref, buf, size, kCFStringEncodingUTF8);
879 if (ref)
880 CFRelease(ref);
881 return ok;
882}
883
884static int avf_io_get_uint32(io_service_t service, CFStringRef key, uint32_t *out)
885{
886 CFTypeRef ref = IORegistryEntryCreateCFProperty(service, key, kCFAllocatorDefault, 0);
887 int ok = ref && CFGetTypeID(ref) == CFNumberGetTypeID() && CFNumberGetValue(ref, kCFNumberSInt32Type, out);
888 if (ref)
889 CFRelease(ref);
890 return ok;
891}
892
893static int64_t avf_usb_location_for_serial(const char *serial)
894{
895 int64_t location = -1;
896 io_iterator_t iterator = 0;
897 io_service_t service;
898
899 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
900 IOServiceMatching("IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
901 return -1;
902
903 while (location < 0 && (service = IOIteratorNext(iterator))) {
904 char found[512];
905 uint32_t loc;
906 if (avf_io_get_string(service, CFSTR("USB Serial Number"), found, sizeof(found)) &&
907 !strcmp(found, serial) &&
908 avf_io_get_uint32(service, CFSTR("locationID"), &loc))
909 location = loc;
910 IOObjectRelease(service);
911 }
912 IOObjectRelease(iterator);
913
914 return location;
915}
916
917static NSString *avf_usb_serial_for_location(uint32_t location)
918{
919 NSString *serial = nil;
920 io_iterator_t iterator = 0;
921 io_service_t service;
922
923 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
924 IOServiceMatching("IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
925 return nil;
926
927 while (!serial && (service = IOIteratorNext(iterator))) {
928 char found[512];
929 uint32_t loc;
930 if (avf_io_get_uint32(service, CFSTR("locationID"), &loc) && loc == location &&
931 avf_io_get_string(service, CFSTR("USB Serial Number"), found, sizeof(found)))
932 serial = [NSString stringWithUTF8String:found];
933 IOObjectRelease(service);
934 }
935 IOObjectRelease(iterator);
936
937 return serial;
938}
939
940// USB video uniqueID = locationID<<32 | VID<<16 | PID; match on the locationID.
941static AVCaptureDevice *avf_video_device_with_serial(const char *serial,
942 NSArray *devices, NSArray *devices_muxed, int *is_muxed)
943{
944 int64_t location = avf_usb_location_for_serial(serial);
945 NSArray *lists[2] = { devices, devices_muxed };
946
947 if (location < 0)
948 return nil;
949
950 for (int i = 0; i < 2; i++) {
951 for (AVCaptureDevice *device in lists[i]) {
952 NSString *uid = [device uniqueID];
953 if ([uid hasPrefix:@"0x"] &&
954 (uint32_t)(strtoull([uid UTF8String], NULL, 16) >> 32) == (uint32_t)location) {
955 *is_muxed = (i == 1);
956 return device;
957 }
958 }
959 }
960
961 return nil;
962}
963
964// CoreAudio USB-audio UID: AppleUSBAudioEngine:manufacturer:device:serial:interfaces
965static NSString *avf_audio_serial_for_uid(NSString *uid)
966{
967 if (![uid hasPrefix:@"AppleUSBAudioEngine:"])
968 return nil;
969 NSArray<NSString *> *fields = [uid componentsSeparatedByString:@":"];
970 if (fields.count < 5)
971 return nil;
972 NSString *serial = fields[fields.count - 2];
973 if (serial.length && avf_usb_location_for_serial([serial UTF8String]) >= 0)
974 return serial;
975 return nil;
976}
977
978#else
979
980static NSString *avf_usb_serial_for_location(uint32_t location)
981{
982 return nil;
983}
984static AVCaptureDevice *avf_video_device_with_serial(const char *serial,
985 NSArray *devices, NSArray *devices_muxed, int *is_muxed)
986{
987 return nil;
988}
989static NSString *avf_audio_serial_for_uid(NSString *uid)
990{
991 return nil;
992}
993#endif
994
995static AVCaptureDevice *avf_audio_device_with_serial(const char *serial, NSArray *devices)
996{
997 NSString *want = [NSString stringWithUTF8String:serial];
998
999 for (AVCaptureDevice *device in devices)
1000 if ([avf_audio_serial_for_uid([device uniqueID]) isEqualToString:want])
1001 return device;
1002
1003 return nil;
1004}
1005
1006static AVCaptureDevice *avf_device_with_uid(const char *uid,
1007 NSArray *devices, NSArray *devices_muxed, int *is_muxed)
1008{
1009 NSString *want = [NSString stringWithUTF8String:uid];
1010 NSArray *lists[2] = { devices, devices_muxed };
1011
1012 for (int i = 0; i < 2; i++) {
1013 for (AVCaptureDevice *device in lists[i]) {
1014 if ([[device uniqueID] isEqualToString:want]) {
1015 if (is_muxed)
1016 *is_muxed = (i == 1);
1017 return device;
1018 }
1019 }
1020 }
1021
1022 return nil;
1023}
1024
1025// Best-effort serial string for -list_devices, or nil.
1026static NSString *avf_device_listing_serial(AVCaptureDevice *device)
1027{
1028 NSString *uid = [device uniqueID];
1029
1030 if ([uid hasPrefix:@"0x"]) {
1031 unsigned long long value = strtoull([uid UTF8String], NULL, 16);
1032 NSString *serial = avf_usb_serial_for_location((uint32_t)(value >> 32));
1033 return serial.length ? serial : nil;
1034 }
1036}
1037
1038static void avf_log_device_entry(AVFContext *ctx, int index, AVCaptureDevice *device)
1039{
1040 NSString *serial = avf_device_listing_serial(device);
1041
1042 if (serial)
1043 av_log(ctx, AV_LOG_INFO, "[%d] %s [uid:%s] [serial:%s]\n", index,
1044 [[device localizedName] UTF8String], [[device uniqueID] UTF8String],
1045 [serial UTF8String]);
1046 else
1047 av_log(ctx, AV_LOG_INFO, "[%d] %s [uid:%s]\n", index,
1048 [[device localizedName] UTF8String], [[device uniqueID] UTF8String]);
1049}
1050
1051// Returns 1 if a device id was set (*device = match, or nil after logging on miss), else 0.
1053 NSArray *devices, NSArray *devices_muxed,
1054 const char *id, AVCaptureDevice **device, int *is_muxed)
1055{
1056 BOOL is_audio = [media_type isEqualToString:AVMediaTypeAudio];
1057 const char *kind = is_audio ? "Audio" : "Video";
1058 const char *value = NULL;
1059
1060 if (!id)
1061 return 0;
1062
1063 if (av_strstart(id, "serial:", &value)) {
1064 if (is_audio)
1065 *device = avf_audio_device_with_serial(value, devices);
1066 else
1067 *device = avf_video_device_with_serial(value, devices, devices_muxed, is_muxed);
1068 if (!*device)
1070 "%s capture device with serial number '%s' not found\n", kind, value);
1071 } else if (av_strstart(id, "uid:", &value)) {
1072 *device = avf_device_with_uid(value, devices, devices_muxed, is_muxed);
1073 if (!*device)
1075 "%s capture device with unique ID '%s' not found\n", kind, value);
1076 } else {
1078 "Invalid %s device id '%s': expected 'uid:<unique ID>' or 'serial:<serial number>'\n",
1079 is_audio ? "audio" : "video", id);
1080 }
1081 return 1;
1082}
1083
1085{
1086 int ret = 0;
1087 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1088 uint32_t num_screens = 0;
1089 AVFContext *ctx = (AVFContext*)s->priv_data;
1090 AVCaptureDevice *video_device = nil;
1091 AVCaptureDevice *audio_device = nil;
1092 // Find capture device
1093 NSArray *devices = getDevicesWithMediaType(AVMediaTypeVideo);
1094 NSArray *devices_muxed = getDevicesWithMediaType(AVMediaTypeMuxed);
1095 NSArray *audio_devices = getDevicesWithMediaType(AVMediaTypeAudio);
1096
1097 ctx->num_video_devices = [devices count] + [devices_muxed count];
1098
1099 pthread_mutex_init(&ctx->frame_lock, NULL);
1100 pthread_cond_init(&ctx->frame_wait_cond, NULL);
1101 ctx->is_stopping = 0;
1102
1103#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1104 CGGetActiveDisplayList(0, NULL, &num_screens);
1105#endif
1106
1107 // List devices if requested
1108 if (ctx->list_devices) {
1109 int index = 0;
1110 av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n");
1111 for (AVCaptureDevice *device in devices) {
1112 index = [devices indexOfObject:device];
1113 avf_log_device_entry(ctx, index, device);
1114 }
1115 for (AVCaptureDevice *device in devices_muxed) {
1116 index = [devices count] + [devices_muxed indexOfObject:device];
1117 avf_log_device_entry(ctx, index, device);
1118 }
1119#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1120 if (num_screens > 0) {
1121 CGDirectDisplayID screens[num_screens];
1122 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1123 for (int i = 0; i < num_screens; i++) {
1124 av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", ctx->num_video_devices + i, i);
1125 }
1126 }
1127#endif
1128
1129 av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n");
1130 devices = getDevicesWithMediaType(AVMediaTypeAudio);
1131 for (AVCaptureDevice *device in devices) {
1132 int index = [devices indexOfObject:device];
1133 avf_log_device_entry(ctx, index, device);
1134 }
1135 goto fail;
1136 }
1137
1138 // parse input filename for video and audio device
1139 ret = parse_device_name(s);
1140 if (ret)
1141 goto fail;
1142
1143 // check for device index given in filename
1144 if (ctx->video_device_index == -1 && ctx->video_filename) {
1145 sscanf(ctx->video_filename, "%d", &ctx->video_device_index);
1146 }
1147 if (ctx->audio_device_index == -1 && ctx->audio_filename) {
1148 sscanf(ctx->audio_filename, "%d", &ctx->audio_device_index);
1149 }
1150
1151 if (avf_device_from_id(ctx, AVMediaTypeVideo, devices, devices_muxed,
1152 ctx->video_device_id, &video_device, &ctx->video_is_muxed)) {
1153 if (!video_device)
1154 goto fail;
1155 } else if (ctx->video_device_index >= 0) {
1156 if (ctx->video_device_index < ctx->num_video_devices) {
1157 if (ctx->video_device_index < [devices count]) {
1158 video_device = [devices objectAtIndex:ctx->video_device_index];
1159 } else {
1160 video_device = [devices_muxed objectAtIndex:(ctx->video_device_index - [devices count])];
1161 ctx->video_is_muxed = 1;
1162 }
1163 } else if (ctx->video_device_index < ctx->num_video_devices + num_screens) {
1164#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1165 CGDirectDisplayID screens[num_screens];
1166 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1167 AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[ctx->video_device_index - ctx->num_video_devices]] autorelease];
1168
1169 if (ctx->framerate.num > 0) {
1170 capture_screen_input.minFrameDuration = CMTimeMake(ctx->framerate.den, ctx->framerate.num);
1171 }
1172
1173#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
1174 if (ctx->capture_cursor) {
1175 capture_screen_input.capturesCursor = YES;
1176 } else {
1177 capture_screen_input.capturesCursor = NO;
1178 }
1179#endif
1180
1181 if (ctx->capture_mouse_clicks) {
1182 capture_screen_input.capturesMouseClicks = YES;
1183 } else {
1184 capture_screen_input.capturesMouseClicks = NO;
1185 }
1186
1187 video_device = (AVCaptureDevice*) capture_screen_input;
1188 ctx->video_is_screen = 1;
1189#endif
1190 } else {
1191 av_log(ctx, AV_LOG_ERROR, "Invalid device index\n");
1192 goto fail;
1193 }
1194 } else if (ctx->video_filename &&
1195 strncmp(ctx->video_filename, "none", 4)) {
1196 if (!strncmp(ctx->video_filename, "default", 7)) {
1197 video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
1198 } else {
1199 // looking for video inputs
1200 for (AVCaptureDevice *device in devices) {
1201 if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) {
1202 video_device = device;
1203 break;
1204 }
1205 }
1206 // looking for muxed inputs
1207 for (AVCaptureDevice *device in devices_muxed) {
1208 if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) {
1209 video_device = device;
1210 ctx->video_is_muxed = 1;
1211 break;
1212 }
1213 }
1214
1215#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1216 // looking for screen inputs
1217 if (!video_device) {
1218 int idx;
1219 if(sscanf(ctx->video_filename, "Capture screen %d", &idx) && idx < num_screens) {
1220 CGDirectDisplayID screens[num_screens];
1221 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1222 AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[idx]] autorelease];
1223 video_device = (AVCaptureDevice*) capture_screen_input;
1224 ctx->video_device_index = ctx->num_video_devices + idx;
1225 ctx->video_is_screen = 1;
1226
1227 if (ctx->framerate.num > 0) {
1228 capture_screen_input.minFrameDuration = CMTimeMake(ctx->framerate.den, ctx->framerate.num);
1229 }
1230
1231#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
1232 if (ctx->capture_cursor) {
1233 capture_screen_input.capturesCursor = YES;
1234 } else {
1235 capture_screen_input.capturesCursor = NO;
1236 }
1237#endif
1238
1239 if (ctx->capture_mouse_clicks) {
1240 capture_screen_input.capturesMouseClicks = YES;
1241 } else {
1242 capture_screen_input.capturesMouseClicks = NO;
1243 }
1244 }
1245 }
1246#endif
1247 }
1248
1249 if (!video_device) {
1250 av_log(ctx, AV_LOG_ERROR, "Video device not found\n");
1251 goto fail;
1252 }
1253 }
1254
1255 // get audio device
1256 if (avf_device_from_id(ctx, AVMediaTypeAudio, audio_devices, nil,
1257 ctx->audio_device_id, &audio_device, NULL)) {
1258 if (!audio_device)
1259 goto fail;
1260 } else if (ctx->audio_device_index >= 0) {
1261 if (ctx->audio_device_index >= [audio_devices count]) {
1262 av_log(ctx, AV_LOG_ERROR, "Invalid audio device index\n");
1263 goto fail;
1264 }
1265
1266 audio_device = [audio_devices objectAtIndex:ctx->audio_device_index];
1267 } else if (ctx->audio_filename &&
1268 strncmp(ctx->audio_filename, "none", 4)) {
1269 if (!strncmp(ctx->audio_filename, "default", 7)) {
1270 audio_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
1271 } else {
1272 for (AVCaptureDevice *device in audio_devices) {
1273 if (!strncmp(ctx->audio_filename, [[device localizedName] UTF8String], strlen(ctx->audio_filename))) {
1274 audio_device = device;
1275 break;
1276 }
1277 }
1278 }
1279
1280 if (!audio_device) {
1281 av_log(ctx, AV_LOG_ERROR, "Audio device not found\n");
1282 goto fail;
1283 }
1284 }
1285
1286 // Video nor Audio capture device not found, looking for AVMediaTypeVideo/Audio
1287 if (!video_device && !audio_device) {
1288 av_log(s, AV_LOG_ERROR, "No AV capture device found\n");
1289 goto fail;
1290 }
1291
1292 if (video_device) {
1293 if (!ctx->video_is_screen) {
1294 av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [[video_device localizedName] UTF8String]);
1295 } else {
1296 av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [[video_device description] UTF8String]);
1297 }
1298 }
1299 if (audio_device) {
1300 av_log(s, AV_LOG_DEBUG, "audio device '%s' opened\n", [[audio_device localizedName] UTF8String]);
1301 }
1302
1303 // Initialize capture session
1304 ctx->capture_session = [[AVCaptureSession alloc] init];
1305
1306 if (video_device && add_video_device(s, video_device)) {
1307 goto fail;
1308 }
1309 if (audio_device && add_audio_device(s, audio_device)) {
1310 }
1311
1312 [ctx->capture_session startRunning];
1313
1314 /* Unlock device configuration only after the session is started so it
1315 * does not reset the capture formats */
1316 if (!ctx->video_is_screen) {
1317 [video_device unlockForConfiguration];
1318 }
1319
1320 if (video_device && get_video_config(s)) {
1321 goto fail;
1322 }
1323
1324 // set audio stream
1325 if (audio_device && get_audio_config(s)) {
1326 goto fail;
1327 }
1328
1329 [pool release];
1330 return 0;
1331
1332fail:
1333 [pool release];
1335 if (ret)
1336 return ret;
1337 return AVERROR(EIO);
1338}
1339
1341 CVPixelBufferRef image_buffer,
1342 AVPacket *pkt)
1343{
1344 AVFContext *ctx = s->priv_data;
1345 int src_linesize[4];
1346 const uint8_t *src_data[4];
1347 int width = CVPixelBufferGetWidth(image_buffer);
1348 int height = CVPixelBufferGetHeight(image_buffer);
1349 int status;
1350
1351 memset(src_linesize, 0, sizeof(src_linesize));
1352 memset(src_data, 0, sizeof(src_data));
1353
1354 status = CVPixelBufferLockBaseAddress(image_buffer, 0);
1355 if (status != kCVReturnSuccess) {
1356 av_log(s, AV_LOG_ERROR, "Could not lock base address: %d (%dx%d)\n", status, width, height);
1357 return AVERROR_EXTERNAL;
1358 }
1359
1360 if (CVPixelBufferIsPlanar(image_buffer)) {
1361 size_t plane_count = CVPixelBufferGetPlaneCount(image_buffer);
1362 int i;
1363 for(i = 0; i < plane_count; i++){
1364 src_linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(image_buffer, i);
1365 src_data[i] = CVPixelBufferGetBaseAddressOfPlane(image_buffer, i);
1366 }
1367 } else {
1368 src_linesize[0] = CVPixelBufferGetBytesPerRow(image_buffer);
1369 src_data[0] = CVPixelBufferGetBaseAddress(image_buffer);
1370 }
1371
1372 status = av_image_copy_to_buffer(pkt->data, pkt->size,
1373 src_data, src_linesize,
1374 ctx->pixel_format, width, height, 1);
1375
1376
1377
1378 CVPixelBufferUnlockBaseAddress(image_buffer, 0);
1379
1380 return status;
1381}
1382
1384{
1385 AVFContext* ctx = (AVFContext*)s->priv_data;
1386
1388 do {
1389 CVImageBufferRef image_buffer;
1390 CMBlockBufferRef block_buffer;
1391
1392 if (ctx->current_frame != nil) {
1393 int status;
1394 int length = 0;
1395
1396 image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame);
1397 block_buffer = CMSampleBufferGetDataBuffer(ctx->current_frame);
1398
1399 if (image_buffer != nil) {
1400 length = (int)CVPixelBufferGetDataSize(image_buffer);
1401 } else if (block_buffer != nil) {
1402 length = (int)CMBlockBufferGetDataLength(block_buffer);
1403 } else {
1405 return AVERROR(EINVAL);
1406 }
1407
1408 if (av_new_packet(pkt, length) < 0) {
1410 return AVERROR(EIO);
1411 }
1412
1413 CMItemCount count;
1414 CMSampleTimingInfo timing_info;
1415
1416 if (CMSampleBufferGetOutputSampleTimingInfoArray(ctx->current_frame, 1, &timing_info, &count) == noErr) {
1417 AVRational timebase_q = av_make_q(1, timing_info.presentationTimeStamp.timescale);
1418 pkt->pts = pkt->dts = av_rescale_q(timing_info.presentationTimeStamp.value, timebase_q, avf_time_base_q);
1419 }
1420
1421 pkt->stream_index = ctx->video_stream_index;
1422 pkt->flags |= AV_PKT_FLAG_KEY;
1423
1424 if (image_buffer) {
1425 status = copy_cvpixelbuffer(s, image_buffer, pkt);
1426 } else {
1427 status = 0;
1428 OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0, pkt->size, pkt->data);
1429 if (ret != kCMBlockBufferNoErr) {
1430 status = AVERROR(EIO);
1431 }
1432 }
1433 CFRelease(ctx->current_frame);
1434 ctx->current_frame = nil;
1435
1436 if (status < 0) {
1438 return status;
1439 }
1440 } else if (ctx->current_audio_frame != nil) {
1441 CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame);
1442 int block_buffer_size = CMBlockBufferGetDataLength(block_buffer);
1443
1444 if (!block_buffer || !block_buffer_size) {
1446 return AVERROR(EIO);
1447 }
1448
1449 if (ctx->audio_non_interleaved && block_buffer_size > ctx->audio_buffer_size) {
1452 }
1453
1454 if (av_new_packet(pkt, block_buffer_size) < 0) {
1456 return AVERROR(EIO);
1457 }
1458
1459 CMItemCount count;
1460 CMSampleTimingInfo timing_info;
1461
1462 if (CMSampleBufferGetOutputSampleTimingInfoArray(ctx->current_audio_frame, 1, &timing_info, &count) == noErr) {
1463 AVRational timebase_q = av_make_q(1, timing_info.presentationTimeStamp.timescale);
1464 pkt->pts = pkt->dts = av_rescale_q(timing_info.presentationTimeStamp.value, timebase_q, avf_time_base_q);
1465 }
1466
1467 pkt->stream_index = ctx->audio_stream_index;
1468 pkt->flags |= AV_PKT_FLAG_KEY;
1469
1470 if (ctx->audio_non_interleaved) {
1471 int sample, c, shift, num_samples;
1472
1473 OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0, pkt->size, ctx->audio_buffer);
1474 if (ret != kCMBlockBufferNoErr) {
1476 return AVERROR(EIO);
1477 }
1478
1479 num_samples = pkt->size / (ctx->audio_channels * (ctx->audio_bits_per_sample >> 3));
1480
1481 // transform decoded frame into output format
1482 #define INTERLEAVE_OUTPUT(bps) \
1483 { \
1484 int##bps##_t **src; \
1485 int##bps##_t *dest; \
1486 src = av_malloc(ctx->audio_channels * sizeof(int##bps##_t*)); \
1487 if (!src) { \
1488 unlock_frames(ctx); \
1489 return AVERROR(EIO); \
1490 } \
1491 \
1492 for (c = 0; c < ctx->audio_channels; c++) { \
1493 src[c] = ((int##bps##_t*)ctx->audio_buffer) + c * num_samples; \
1494 } \
1495 dest = (int##bps##_t*)pkt->data; \
1496 shift = bps - ctx->audio_bits_per_sample; \
1497 for (sample = 0; sample < num_samples; sample++) \
1498 for (c = 0; c < ctx->audio_channels; c++) \
1499 *dest++ = src[c][sample] << shift; \
1500 av_freep(&src); \
1501 }
1502
1503 if (ctx->audio_bits_per_sample <= 16) {
1505 } else {
1507 }
1508 } else {
1509 OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0, pkt->size, pkt->data);
1510 if (ret != kCMBlockBufferNoErr) {
1512 return AVERROR(EIO);
1513 }
1514 }
1515
1516 CFRelease(ctx->current_audio_frame);
1517 ctx->current_audio_frame = nil;
1518 } else {
1519 pkt->data = NULL;
1520 if (ctx->observed_quit) {
1522 return AVERROR_EOF;
1523 }
1524 // No frame available yet: wait until a capture callback delivers
1525 // one (or until the device is being torn down).
1526 pthread_cond_wait(&ctx->frame_wait_cond, &ctx->frame_lock);
1527 }
1528 } while (!pkt->data && !ctx->is_stopping);
1529
1530 if (ctx->is_stopping) {
1532 return AVERROR_EOF;
1533 }
1535
1536 return 0;
1537}
1538
1540{
1541 AVFContext* ctx = (AVFContext*)s->priv_data;
1543 return 0;
1544}
1545
1546static const AVOption options[] = {
1547 { "list_devices", "list available devices", offsetof(AVFContext, list_devices), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
1548 { "video_device_index", "select video device by index for devices with same name (starts at 0)", offsetof(AVFContext, video_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
1549 { "audio_device_index", "select audio device by index for devices with same name (starts at 0)", offsetof(AVFContext, audio_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
1550 { "video_device_id", "select video device by prefixed id (uid:<unique ID> or serial:<USB serial number>)", offsetof(AVFContext, video_device_id), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
1551 { "audio_device_id", "select audio device by prefixed id (uid:<unique ID> or serial:<USB serial number>)", offsetof(AVFContext, audio_device_id), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
1552 { "pixel_format", "set pixel format", offsetof(AVFContext, pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV420P}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
1553 { "framerate", "set frame rate", offsetof(AVFContext, framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
1554 { "video_size", "set video size", offsetof(AVFContext, width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
1555 { "capture_cursor", "capture the screen cursor", offsetof(AVFContext, capture_cursor), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
1556 { "capture_mouse_clicks", "capture the screen mouse clicks", offsetof(AVFContext, capture_mouse_clicks), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
1557 { "capture_raw_data", "capture the raw data from device connection", offsetof(AVFContext, capture_raw_data), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
1558 { "drop_late_frames", "drop frames that are available later than expected", offsetof(AVFContext, drop_late_frames), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
1559
1560 { NULL },
1561};
1562
1563static const AVClass avf_class = {
1564 .class_name = "AVFoundation indev",
1565 .item_name = av_default_item_name,
1566 .option = options,
1567 .version = LIBAVUTIL_VERSION_INT,
1569};
1570
1572 .p.name = "avfoundation",
1573 .p.long_name = NULL_IF_CONFIG_SMALL("AVFoundation input device"),
1574 .p.flags = AVFMT_NOFILE,
1575 .p.priv_class = &avf_class,
1576 .priv_data_size = sizeof(AVFContext),
1580};
static const char *const format[]
Definition af_aiir.c:445
const FFInputFormat ff_avfoundation_demuxer
static FILE * out
static AVFormatContext * ctx
int32_t
Main libavdevice API header.
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition avformat.c:834
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition avformat.h:490
static int get_audio_config(AVFormatContext *s)
static void lock_frames(AVFContext *ctx)
static const AVClass avf_class
static AVCaptureDevice * avf_audio_device_with_serial(const char *serial, NSArray *devices)
static int parse_device_name(AVFormatContext *s)
static AVCaptureDevice * avf_device_with_uid(const char *uid, NSArray *devices, NSArray *devices_muxed, int *is_muxed)
static AVCaptureDevice * avf_video_device_with_serial(const char *serial, NSArray *devices, NSArray *devices_muxed, int *is_muxed)
static int avf_close(AVFormatContext *s)
static const AVOption options[]
static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
static void unlock_frames(AVFContext *ctx)
static const AVRational avf_time_base_q
static void avf_log_device_entry(AVFContext *ctx, int index, AVCaptureDevice *device)
static NSArray * getDevicesWithMediaType(AVMediaType mediaType)
static const struct AVFPixelFormatSpec avf_pixel_formats[]
static int add_audio_device(AVFormatContext *s, AVCaptureDevice *audio_device)
static void destroy_context(AVFContext *ctx)
static int avf_read_header(AVFormatContext *s)
static int copy_cvpixelbuffer(AVFormatContext *s, CVPixelBufferRef image_buffer, AVPacket *pkt)
static NSString * avf_audio_serial_for_uid(NSString *uid)
static const int avf_time_base
static int configure_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
Configure the video device.
static NSString * avf_usb_serial_for_location(uint32_t location)
static int avf_device_from_id(AVFContext *ctx, AVMediaType media_type, NSArray *devices, NSArray *devices_muxed, const char *id, AVCaptureDevice **device, int *is_muxed)
static NSString * avf_device_listing_serial(AVCaptureDevice *device)
#define INTERLEAVE_OUTPUT(bps)
static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
static int get_video_config(AVFormatContext *s)
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
static int FUNC timing_info(CodedBitstreamContext *ctx, RWContext *rw, AV1RawTimingInfo *current)
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
Public libavutil channel layout APIs header.
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static __device__ float fabs(float a)
static AVPacket * pkt
enum AVCodecID id
Definition dts2pts.c:607
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
mode
Use these values in ebur128_init (or'ed).
Definition ebur128.h:83
double value
Definition eval.c:102
const char * key
static int read_header(FFV1Context *f, RangeCoder *c)
Definition ffv1dec.c:578
#define sample
#define fail
Definition test.h:479
#define AV_OPT_FLAG_DECODING_PARAM
A generic parameter which can be set by the user for demuxing or decoding.
Definition opt.h:355
@ AV_OPT_TYPE_IMAGE_SIZE
Underlying C type is two consecutive integers.
Definition opt.h:302
@ AV_OPT_TYPE_PIXEL_FMT
Underlying C type is enum AVPixelFormat.
Definition opt.h:306
@ AV_OPT_TYPE_VIDEO_RATE
Underlying C type is AVRational.
Definition opt.h:314
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
@ AV_CODEC_ID_PCM_F32LE
Definition codec_id.h:352
@ AV_CODEC_ID_PCM_S24BE
Definition codec_id.h:344
@ AV_CODEC_ID_RAWVIDEO
Definition codec_id.h:63
@ AV_CODEC_ID_PCM_S16LE
Definition codec_id.h:331
@ AV_CODEC_ID_PCM_F32BE
Definition codec_id.h:351
@ AV_CODEC_ID_PCM_S16BE
Definition codec_id.h:332
@ AV_CODEC_ID_PCM_S24LE
Definition codec_id.h:343
@ AV_CODEC_ID_PCM_S32LE
Definition codec_id.h:339
@ AV_CODEC_ID_DVVIDEO
Definition codec_id.h:74
@ AV_CODEC_ID_PCM_S32BE
Definition codec_id.h:340
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition packet.h:650
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition packet.c:98
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
Get the default channel layout for a given number of channels.
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition error.h:53
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition rational.h:104
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
AVMediaType
Definition avutil.h:198
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
int av_image_copy_to_buffer(uint8_t *dst, int dst_size, const uint8_t *const src_data[4], const int src_linesize[4], enum AVPixelFormat pix_fmt, int width, int height, int align)
Copy image data from an image into a buffer.
Definition imgutils.c:501
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition avstring.c:179
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition avstring.c:36
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
int index
Definition gxfenc.c:90
misc image utilities
AudioReceiver class - delegate for AVCaptureSession.
AVFContext * _context
FrameReceiver class - delegate for AVCaptureSession.
AVFContext * _context
static int shift(int a, int b)
Definition bonk.c:261
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:97
static av_cold int read_close(AVFormatContext *ctx)
Definition libcdio.c:143
@ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
Definition log.h:42
enum AVColorRange range
Memory handling functions.
UID uid
Definition mxfenc.c:2488
#define av_strdup(s)
Definition ops_static.c:55
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
Definition os2threads.h:168
static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
Definition os2threads.h:119
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
Definition os2threads.h:150
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition os2threads.h:104
static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
Definition os2threads.h:139
_fmutex pthread_mutex_t
Definition os2threads.h:53
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
Definition os2threads.h:132
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
Definition os2threads.h:198
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
Definition os2threads.h:112
misc parsing utilities
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition pixdesc.c:3380
#define AV_PIX_FMT_YUV422P10
Definition pixfmt.h:546
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition pixfmt.h:96
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition pixfmt.h:75
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_MONOBLACK
Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb.
Definition pixfmt.h:83
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition pixfmt.h:265
@ AV_PIX_FMT_RGB555BE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined
Definition pixfmt.h:114
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_BGR48BE
packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big...
Definition pixfmt.h:145
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition pixfmt.h:88
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition pixfmt.h:264
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition pixfmt.h:174
@ AV_PIX_FMT_YUVA444P16LE
planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian)
Definition pixfmt.h:192
@ AV_PIX_FMT_RGB565LE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
Definition pixfmt.h:113
@ AV_PIX_FMT_RGB555LE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined
Definition pixfmt.h:115
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition pixfmt.h:263
@ AV_PIX_FMT_RGB565BE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
Definition pixfmt.h:112
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition pixfmt.h:74
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition pixfmt.h:76
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition pixfmt.h:262
#define AV_PIX_FMT_YUV422P16
Definition pixfmt.h:557
#define AV_PIX_FMT_YUV444P10
Definition pixfmt.h:548
const char * name
Definition qsvenc.c:142
Describe the class of an AVClass context structure.
Definition log.h:76
int height
The height of the video frame in pixels.
Definition codec_par.h:150
AVChannelLayout ch_layout
The channel layout and number of channels.
Definition codec_par.h:207
int width
The width of the video frame in pixels.
Definition codec_par.h:143
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
int sample_rate
The number of audio samples per second.
Definition codec_par.h:213
int drop_late_frames
CMSampleBufferRef current_frame
pthread_cond_t frame_wait_cond
int32_t * audio_buffer
int capture_raw_data
int audio_stream_index
AVCaptureAudioDataOutput * audio_output
int video_stream_index
char * video_filename
char * audio_device_id
int num_video_devices
int capture_mouse_clicks
int audio_bits_per_sample
pthread_mutex_t frame_lock
int audio_device_index
int video_is_screen
int audio_non_interleaved
char * audio_filename
AVCaptureVideoDataOutput * video_output
int audio_signed_integer
int audio_frames_captured
AVRational framerate
enum AVPixelFormat pixel_format
int audio_buffer_size
AVCaptureSession * capture_session
int frames_captured
int video_device_index
CMSampleBufferRef current_audio_frame
char * video_device_id
AVCaptureDevice * observed_device
id avf_audio_delegate
enum AVPixelFormat ff_id
Format I/O context.
Definition avformat.h:1335
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
Rational number (pair of numerator and denominator).
Definition rational.h:58
Stream structure.
Definition avformat.h:768
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:791
int index
stream index in AVFormatContext
Definition avformat.h:774
#define av_freep(p)
#define av_log(a,...)
static void error(const char *err)
float framerate
Definition av1_levels.c:29
static int ref[MAX_W *MAX_W]
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
int size
static double c[64]