23 #import <AVFoundation/AVFoundation.h> 66 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 76 if (core_video_fmt == pixel_format_map[i].core_video_fmt)
77 return pixel_format_map[i].
pix_fmt;
85 if (pix_fmt == pixel_format_map[i].pix_fmt)
115 #define AUDIO_DEVICES 1 116 #define VIDEO_DEVICES 2 117 #define ALL_DEVICES AUDIO_DEVICES | VIDEO_DEVICES 119 #define OFFSET(x) offsetof(AVFoundationCaptureContext, x) 120 #define DEC AV_OPT_FLAG_DECODING_PARAM 122 {
"list_devices",
"List available devices and exit",
OFFSET(list_devices),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX,
DEC,
"list_devices" },
128 {
"video_size",
"A string describing frame size, such as 640x480 or hd720.",
OFFSET(video_size),
AV_OPT_TYPE_STRING, { .str =
NULL }, 0, 0, DEC },
135 NSArray *devices = [AVCaptureDevice devicesWithMediaType:type];
138 for (AVCaptureDevice *device
in devices) {
140 [[device uniqueID] UTF8String],
141 [[device localizedName] UTF8String]);
143 for (AVCaptureDeviceFormat *
format in device.formats)
145 [[NSString stringWithFormat: @
"%@",
format] UTF8String]);
165 AVCaptureVideoDataOutput *
out = [[AVCaptureVideoDataOutput alloc] init];
167 for (NSNumber *cv_pixel_format
in[out availableVideoCVPixelFormatTypes]) {
168 OSType cv_fmt = [cv_pixel_format intValue];
189 @interface VideoCapture : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
196 - (
void)captureOutput:(AVCaptureOutput *)captureOutput
197 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
198 fromConnection:(AVCaptureConnection *)connection;
206 if (
self = [super
init]) {
212 - (
void)captureOutput:(AVCaptureOutput *)captureOutput
213 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
214 fromConnection:(AVCaptureConnection *)connection
216 CVImageBufferRef buf;
223 buf = CMSampleBufferGetImageBuffer(videoFrame);
246 AVCaptureDeviceFormat *selected_format = nil;
247 AVFrameRateRange *selected_range = nil;
249 double epsilon = 0.00000001;
252 CMFormatDescriptionRef formatDescription;
253 CMVideoDimensions dimensions;
255 formatDescription = (CMFormatDescriptionRef)
format.formatDescription;
256 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
259 (dimensions.width == ctx->
width && dimensions.height == ctx->
height)) {
261 dimensions.width, dimensions.height);
262 ctx->
width = dimensions.width;
263 ctx->
height = dimensions.height;
268 for (AVFrameRateRange *range
in format.videoSupportedFrameRateRanges)
269 if (range.minFrameRate <= (framerate + epsilon) &&
270 range.maxFrameRate >= (framerate - epsilon)) {
271 selected_range = range;
275 selected_range =
format.videoSupportedFrameRateRanges[0];
276 framerate = selected_range.maxFrameRate;
280 if (selected_format && selected_range)
285 if (!selected_format) {
286 av_log(s,
AV_LOG_ERROR,
"Selected video size (%dx%d) is not supported by the device\n",
294 if (framerate && !selected_range) {
303 if ([video_device lockForConfiguration :
NULL] == YES) {
304 [video_device setActiveFormat : selected_format];
305 [video_device setActiveVideoMinFrameDuration : CMTimeMake(1, framerate)];
306 [video_device setActiveVideoMaxFrameDuration : CMTimeMake(1, framerate)];
318 CMFormatDescriptionRef formatDescription;
319 CMVideoDimensions dimensions;
321 formatDescription = (CMFormatDescriptionRef)
format.formatDescription;
322 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
324 for (AVFrameRateRange *range
in format.videoSupportedFrameRateRanges)
326 dimensions.width, dimensions.height,
327 range.minFrameRate, range.maxFrameRate);
334 NSError *__autoreleasing error = nil;
335 AVCaptureDeviceInput *input;
336 AVCaptureSession *session = (__bridge AVCaptureSession *)ctx->
session;
347 input = [AVCaptureDeviceInput deviceInputWithDevice:device
351 [[error localizedDescription] UTF8String]);
355 if ([session canAddInput : input]) {
356 [session addInput : input];
363 if ([device hasMediaType : AVMediaTypeVideo]) {
364 AVCaptureVideoDataOutput *
out = [[AVCaptureVideoDataOutput alloc] init];
371 [out setAlwaysDiscardsLateVideoFrames : YES];
375 core_video_fmt = [NSNumber numberWithInt:pix_fmt_to_core_video(av_get_pix_fmt(ctx->pixel_format))];
376 if ([[out availableVideoCVPixelFormatTypes] indexOfObject : core_video_fmt] != NSNotFound) {
379 core_video_fmt = nil;
385 for (NSNumber *cv_pixel_format
in[out availableVideoCVPixelFormatTypes]) {
386 OSType cv_fmt = [cv_pixel_format intValue];
390 core_video_fmt = cv_pixel_format;
398 if (!core_video_fmt) {
405 NSDictionary *capture_dict = [NSDictionary dictionaryWithObject:core_video_fmt
406 forKey:(const NSString *)kCVPixelBufferPixelFormatTypeKey];
407 [out setVideoSettings : capture_dict];
411 dispatch_queue_t queue = dispatch_queue_create(
"avf_queue",
NULL);
412 [out setSampleBufferDelegate : delegate queue : queue];
414 if ([session canAddOutput : out]) {
415 [session addOutput : out];
430 CVImageBufferRef image_buffer;
431 CGSize image_buffer_size;
441 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
450 image_buffer_size = CVImageBufferGetEncodedSize(image_buffer);
454 stream->codec->width = (int)image_buffer_size.width;
455 stream->codec->height = (
int)image_buffer_size.height;
468 AVCaptureSession *session = (__bridge AVCaptureSession *)ctx->
session;
469 [session stopRunning];
483 AVCaptureDevice *device;
484 for (NSString *type
in @[AVMediaTypeVideo]) {
485 device = [AVCaptureDevice defaultDeviceWithMediaType:type];
488 [[device uniqueID] UTF8String]);
502 NSError *__autoreleasing error = nil;
503 NSRegularExpression *exp;
505 AVCaptureDevice *device;
507 filename = [NSString stringWithFormat:@ "%s", s->filename];
509 if ((device = [AVCaptureDevice deviceWithUniqueID:filename])) {
515 NSString *pat =
@"(?<=\\[).*?(?=\\])";
516 exp = [NSRegularExpression regularExpressionWithPattern:pat
521 [[error localizedDescription] UTF8String]);
525 matches = [exp matchesInString:filename options:0
526 range:NSMakeRange(0, [filename length])];
528 if (matches.count > 0) {
529 for (NSTextCheckingResult *match
in matches) {
530 NSRange range = [match rangeAtIndex:0];
531 NSString *uniqueID = [filename substringWithRange:NSMakeRange(range.location, range.length)];
533 if (!(device = [AVCaptureDevice deviceWithUniqueID:uniqueID])) {
547 AVCaptureDevice *device;
552 ctx->
session = (__bridge_retained CFTypeRef)[[AVCaptureSession alloc]
init];
554 if (!strncmp(s->
filename,
"default", 7)) {
572 [(__bridge AVCaptureSession *)ctx->session startRunning];
575 [device unlockForConfiguration];
657 }
while (!pkt->
data);
685 .priv_class = &avfoundation_class,
static av_unused void pthread_cond_signal(pthread_cond_t *cond)
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
AVRational internal_framerate
int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
Parse str and put in width_ptr and height_ptr the detected values.
static av_unused void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
#define AV_LOG_WARNING
Something somehow does not look correct.
packed RGB 8:8:8, 24bpp, RGBRGB...
static int get_video_config(AVFormatContext *s)
packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 ...
av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (%s)\, len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic ? ac->func_descr_generic :ac->func_descr)
static enum AVSampleFormat formats[]
static void destroy_context(AVFoundationCaptureContext *ctx)
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
CRITICAL_SECTION pthread_mutex_t
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
static void print_supported_formats(AVFormatContext *s, AVCaptureDevice *device)
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
static double av_q2d(AVRational a)
Convert rational to double.
static av_cold int read_close(AVFormatContext *ctx)
#define AV_LOG_VERBOSE
Detailed information.
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Main libavdevice API header.
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
static void lock_frames(AVFoundationCaptureContext *ctx)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
static int pthread_mutex_init(pthread_mutex_t *m, void *attr)
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
static int pthread_mutex_unlock(pthread_mutex_t *m)
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
static int setup_streams(AVFormatContext *s)
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
static int setup_default_stream(AVFormatContext *s)
#define AV_PIX_FMT_YUV444P10
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
int flags
A combination of AV_PKT_FLAG values.
static const struct AVPixelFormatMap pixel_format_map[]
static enum AVPixelFormat core_video_to_pix_fmt(OSType core_video_fmt)
CVImageBufferRef current_frame
static int pthread_mutex_destroy(pthread_mutex_t *m)
static av_unused void pthread_cond_destroy(pthread_cond_t *cond)
pthread_cond_t frame_wait_cond
char filename[1024]
input or output filename
static av_unused int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
pthread_mutex_t frame_lock
static int avfoundation_read_close(AVFormatContext *s)
packed RGB 8:8:8, 24bpp, BGRBGR...
static int avfoundation_list_capture_devices(AVFormatContext *s)
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big...
static int avfoundation_read_packet(AVFormatContext *s, AVPacket *pkt)
static int read_header(FFV1Context *f)
int64_t av_gettime(void)
Get the current time in microseconds.
static const AVOption options[]
static int pthread_mutex_lock(pthread_mutex_t *m)
#define AV_LOG_INFO
Standard information.
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
char * av_strdup(const char *s)
Duplicate the string s.
static int avfoundation_read_header(AVFormatContext *s)
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
static void(WINAPI *cond_broadcast)(pthread_cond_t *cond)
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
static int read_packet(AVFormatContext *ctx, AVPacket *pkt)
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
Describe the class of an AVClass context structure.
planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian)
rational number numerator/denominator
AVFoundationCaptureContext * _context
static AVCaptureDevice * create_device(AVFormatContext *s)
Try to open device given in filename Two supported formats: "device_unique_id" or "[device_unique_id]...
#define AV_PIX_FMT_YUV422P10
packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0 ...
static const AVClass avfoundation_class
Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb...
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
static OSType pix_fmt_to_core_video(enum AVPixelFormat pix_fmt)
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
static av_cold int init(AVCodecParserContext *s)
static void list_capture_devices_by_type(AVFormatContext *s, NSString *type)
static void unlock_frames(AVFoundationCaptureContext *ctx)
void * priv_data
Format private data.
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
static bool configure_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
Configure the video device.
static int list_formats(AVFormatContext *s)
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
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.
static int setup_stream(AVFormatContext *s, AVCaptureDevice *device)
AVPixelFormat
Pixel format.
This structure stores compressed data.
#define AV_PIX_FMT_YUV422P16
AVInputFormat ff_avfoundation_demuxer
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...