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