|
|
|
@ -172,99 +172,23 @@ static void destroy_context(AVFContext* ctx) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int avf_read_header(AVFormatContext *s) |
|
|
|
|
static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device) |
|
|
|
|
{ |
|
|
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
|
|
|
AVFContext *ctx = (AVFContext*)s->priv_data; |
|
|
|
|
ctx->first_pts = av_gettime(); |
|
|
|
|
|
|
|
|
|
pthread_mutex_init(&ctx->frame_lock, NULL); |
|
|
|
|
pthread_cond_init(&ctx->frame_wait_cond, NULL); |
|
|
|
|
|
|
|
|
|
// List devices if requested |
|
|
|
|
if (ctx->list_devices) { |
|
|
|
|
av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); |
|
|
|
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
for (AVCaptureDevice *device in devices) { |
|
|
|
|
const char *name = [[device localizedName] UTF8String]; |
|
|
|
|
int index = [devices indexOfObject:device]; |
|
|
|
|
av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); |
|
|
|
|
} |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Find capture device |
|
|
|
|
AVCaptureDevice *video_device = nil; |
|
|
|
|
|
|
|
|
|
// check for device index given in filename |
|
|
|
|
if (ctx->video_device_index == -1) { |
|
|
|
|
sscanf(s->filename, "%d", &ctx->video_device_index); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ctx->video_device_index >= 0) { |
|
|
|
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
|
|
|
|
|
if (ctx->video_device_index >= [devices count]) { |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "Invalid device index\n"); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
video_device = [devices objectAtIndex:ctx->video_device_index]; |
|
|
|
|
} else if (strncmp(s->filename, "", 1) && |
|
|
|
|
strncmp(s->filename, "default", 7)) { |
|
|
|
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
|
|
|
|
|
for (AVCaptureDevice *device in devices) { |
|
|
|
|
if (!strncmp(s->filename, [[device localizedName] UTF8String], strlen(s->filename))) { |
|
|
|
|
video_device = device; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!video_device) { |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "Video device not found\n"); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeMuxed]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Video capture device not found, looking for AVMediaTypeVideo |
|
|
|
|
if (!video_device) { |
|
|
|
|
video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
|
|
|
|
|
if (!video_device) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "No AV capture device found\n"); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
NSString* dev_display_name = [video_device localizedName]; |
|
|
|
|
av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [dev_display_name UTF8String]); |
|
|
|
|
|
|
|
|
|
// Initialize capture session |
|
|
|
|
ctx->capture_session = [[AVCaptureSession alloc] init]; |
|
|
|
|
|
|
|
|
|
NSError *error = nil; |
|
|
|
|
AVFContext *ctx = (AVFContext*)s->priv_data; |
|
|
|
|
NSError *error = nil; |
|
|
|
|
AVCaptureDeviceInput* capture_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:video_device error:&error] autorelease]; |
|
|
|
|
|
|
|
|
|
if (!capture_dev_input) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to create AV capture input device: %s\n", |
|
|
|
|
[[error localizedDescription] UTF8String]); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!capture_dev_input) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to add AV capture input device to session: %s\n", |
|
|
|
|
[[error localizedDescription] UTF8String]); |
|
|
|
|
goto fail; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ([ctx->capture_session canAddInput:capture_dev_input]) { |
|
|
|
|
[ctx->capture_session addInput:capture_dev_input]; |
|
|
|
|
} else { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "can't add video input to capture session\n"); |
|
|
|
|
goto fail; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Attaching output |
|
|
|
@ -272,7 +196,7 @@ static int avf_read_header(AVFormatContext *s) |
|
|
|
|
|
|
|
|
|
if (!ctx->video_output) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to init AV video output\n"); |
|
|
|
|
goto fail; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// select pixel format |
|
|
|
@ -290,7 +214,7 @@ static int avf_read_header(AVFormatContext *s) |
|
|
|
|
if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "Selected pixel format (%s) is not supported by AVFoundation.\n", |
|
|
|
|
av_get_pix_fmt_name(pxl_fmt_spec.ff_id)); |
|
|
|
|
goto fail; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// check if the pixel format is available for this device |
|
|
|
@ -323,14 +247,14 @@ static int avf_read_header(AVFormatContext *s) |
|
|
|
|
|
|
|
|
|
// fail if there is no appropriate pixel format or print a warning about overriding the pixel format |
|
|
|
|
if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) { |
|
|
|
|
goto fail; |
|
|
|
|
return 1; |
|
|
|
|
} else { |
|
|
|
|
av_log(s, AV_LOG_WARNING, "Overriding selected pixel format to use %s instead.\n", |
|
|
|
|
av_get_pix_fmt_name(pxl_fmt_spec.ff_id)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ctx->pixel_format = pxl_fmt_spec.ff_id; |
|
|
|
|
NSNumber *pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id]; |
|
|
|
|
NSDictionary *capture_dict = [NSDictionary dictionaryWithObject:pixel_format |
|
|
|
|
forKey:(id)kCVPixelBufferPixelFormatTypeKey]; |
|
|
|
@ -348,10 +272,15 @@ static int avf_read_header(AVFormatContext *s) |
|
|
|
|
[ctx->capture_session addOutput:ctx->video_output]; |
|
|
|
|
} else { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "can't add video output to capture session\n"); |
|
|
|
|
goto fail; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
[ctx->capture_session startRunning]; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int get_video_config(AVFormatContext *s) |
|
|
|
|
{ |
|
|
|
|
AVFContext *ctx = (AVFContext*)s->priv_data; |
|
|
|
|
|
|
|
|
|
// Take stream info from the first frame. |
|
|
|
|
while (ctx->frames_captured < 1) { |
|
|
|
@ -363,7 +292,7 @@ static int avf_read_header(AVFormatContext *s) |
|
|
|
|
AVStream* stream = avformat_new_stream(s, NULL); |
|
|
|
|
|
|
|
|
|
if (!stream) { |
|
|
|
|
goto fail; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
avpriv_set_pts_info(stream, 64, 1, avf_time_base); |
|
|
|
@ -375,12 +304,99 @@ static int avf_read_header(AVFormatContext *s) |
|
|
|
|
stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
|
|
|
|
stream->codec->width = (int)image_buffer_size.width; |
|
|
|
|
stream->codec->height = (int)image_buffer_size.height; |
|
|
|
|
stream->codec->pix_fmt = pxl_fmt_spec.ff_id; |
|
|
|
|
stream->codec->pix_fmt = ctx->pixel_format; |
|
|
|
|
|
|
|
|
|
CFRelease(ctx->current_frame); |
|
|
|
|
ctx->current_frame = nil; |
|
|
|
|
|
|
|
|
|
unlock_frames(ctx); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int avf_read_header(AVFormatContext *s) |
|
|
|
|
{ |
|
|
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
|
|
|
AVFContext *ctx = (AVFContext*)s->priv_data; |
|
|
|
|
ctx->first_pts = av_gettime(); |
|
|
|
|
|
|
|
|
|
pthread_mutex_init(&ctx->frame_lock, NULL); |
|
|
|
|
pthread_cond_init(&ctx->frame_wait_cond, NULL); |
|
|
|
|
|
|
|
|
|
// List devices if requested |
|
|
|
|
if (ctx->list_devices) { |
|
|
|
|
av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); |
|
|
|
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
for (AVCaptureDevice *device in devices) { |
|
|
|
|
const char *name = [[device localizedName] UTF8String]; |
|
|
|
|
int index = [devices indexOfObject:device]; |
|
|
|
|
av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); |
|
|
|
|
} |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Find capture device |
|
|
|
|
AVCaptureDevice *video_device = nil; |
|
|
|
|
|
|
|
|
|
// check for device index given in filename |
|
|
|
|
if (ctx->video_device_index == -1) { |
|
|
|
|
sscanf(s->filename, "%d", &ctx->video_device_index); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ctx->video_device_index >= 0) { |
|
|
|
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
|
|
|
|
|
if (ctx->video_device_index >= [devices count]) { |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "Invalid device index\n"); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
video_device = [devices objectAtIndex:ctx->video_device_index]; |
|
|
|
|
} else if (strncmp(s->filename, "", 1) && |
|
|
|
|
strncmp(s->filename, "default", 7)) { |
|
|
|
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
|
|
|
|
|
for (AVCaptureDevice *device in devices) { |
|
|
|
|
if (!strncmp(s->filename, [[device localizedName] UTF8String], strlen(s->filename))) { |
|
|
|
|
video_device = device; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!video_device) { |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "Video device not found\n"); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Video capture device not found, looking for AVMediaTypeVideo |
|
|
|
|
if (!video_device) { |
|
|
|
|
video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; |
|
|
|
|
|
|
|
|
|
if (!video_device) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "No AV capture device found\n"); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
NSString* dev_display_name = [video_device localizedName]; |
|
|
|
|
av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [dev_display_name UTF8String]); |
|
|
|
|
|
|
|
|
|
// Initialize capture session |
|
|
|
|
ctx->capture_session = [[AVCaptureSession alloc] init]; |
|
|
|
|
|
|
|
|
|
if (add_video_device(s, video_device)) { |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
[ctx->capture_session startRunning]; |
|
|
|
|
|
|
|
|
|
if (get_video_config(s)) { |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
[pool release]; |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|