Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xcode/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用AVFoundation访问图像和音频_Ios_Xcode_Avfoundation - Fatal编程技术网

Ios 使用AVFoundation访问图像和音频

Ios 使用AVFoundation访问图像和音频,ios,xcode,avfoundation,Ios,Xcode,Avfoundation,我使用AVFoundation访问图像和音频制作视频。问题是,当我添加类似音频的设备时 AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeAudio]; AVCaptureDeviceInput * microphone_input = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil

我使用AVFoundation访问图像和音频制作视频。问题是,当我添加类似音频的设备时

AVCaptureDevice *audioDevice     = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeAudio];
AVCaptureDeviceInput * microphone_input = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
AVCaptureAudioDataOutput * audio_output = [[AVCaptureAudioDataOutput alloc] init];
[self.captureSession2 addInput:microphone_input];
[self.captureSession2 addOutput:audio_output];
dispatch_queue_t queue2;
queue2 = dispatch_queue_create("Audio", NULL);
[audio_output setSampleBufferDelegate:self queue:queue2];
dispatch_release(queue2);
和照相机的图像

AVCaptureDevice *cameraDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

//putting it on the input.
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:cameraDevice error:nil];

//selecting the Output. 
AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init];

[self.captureSession addInput:captureInput];
[self.captureSession addOutput:captureOutput];
dispatch_queue_t    queue;
queue = dispatch_queue_create("cameraQueue", 0);
[captureOutput setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
毕竟,通过代理获取原始数据

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
   fromConnection:(AVCaptureConnection *)connection 
{   
if ([captureOutput isKindOfClass:[AVCaptureAudioDataOutput class]]) 
    [self sendAudeoRaw:sampleBuffer];
if ([captureOutput isKindOfClass:[AVCaptureVideoDataOutput class]]) 
    [self sendVideoRaw:sampleBuffer];}
获取图像原始数据的速度非常慢,大约每秒2张图像。我如何改进它,因为我每秒看10-12张图像。
请帮助

从以下四件事开始:

创建一个全局队列,在释放封装对象之前不要释放它;将“串行”指定为队列类型,并使目标队列成为主队列:

_captureOutputQueue  = dispatch_queue_create_with_target("bush.alan.james.PhotosRemote.captureOutputQueue", DISPATCH_QUEUE_SERIAL, dispatch_get_main_queue());
从每个示例缓冲区获取媒体类型描述,以确定示例缓冲区是否包含音频或视频数据:

CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
CMMediaType mediaType = CMFormatDescriptionGetMediaType(formatDescription);
if (mediaType == kCMMediaType_Audio)...
if (mediaType == kCMMediaType_Video)...
将另一个类作为数据输出委托,而不是通过方法调用将示例缓冲区发送给另一个类;否则的话,你要加倍努力了

最后,确保您正在自己的队列中运行AVSession。根据苹果公司的AVCaptureSession文档:

dispatch_async(self.sessionQueue, ^{
    [self configureSession];
});

dispatch_async(self.sessionQueue, ^{
    [self.session startRunning];
});

dispatch_async(self.sessionQueue, ^{
    [self.session stopRunning];
});
startRunning
方法是一个阻塞调用,可能需要一些时间, 因此,您应该在串行队列上执行会话设置,以便 主队列没有被阻塞(这使UI保持响应)。看见 为了 实现示例

这包括对配置摄像机的方法的任何调用,特别是调用AVCaptureSession的startRunning或stopRunning方法的任何调用:

dispatch_async(self.sessionQueue, ^{
    [self configureSession];
});

dispatch_async(self.sessionQueue, ^{
    [self.session startRunning];
});

dispatch_async(self.sessionQueue, ^{
    [self.session stopRunning];
});

如果不能将委托设置为处理示例缓冲区的类,则可以考虑将它们放在两个类都有访问权限的队列中,然后传递一个键:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    static char kMyKey; // set key to any value; pass the key--not the sample buffer--to the receiver
    dispatch_queue_set_specific(((AppDelegate *)[[UIApplication sharedApplication] delegate].serialQueue,
                                &kMyKey,
                                (void*)CFRetain(sampleBuffer),
                                (dispatch_function_t)CFRelease); 
    });      
}
在receiver类中:

dispatch_async(((AppDelegate *)[[UIApplication sharedApplication] delegate]).serialQueue, ^{
            CMSampleBufferRef sb = dispatch_get_specific(&kMyKey);
            NSLog(@"sb: %i", CMSampleBufferIsValid(sb));
});

从以下四件事开始:

创建一个全局队列,在释放封装对象之前不要释放它;将“串行”指定为队列类型,并使目标队列成为主队列:

_captureOutputQueue  = dispatch_queue_create_with_target("bush.alan.james.PhotosRemote.captureOutputQueue", DISPATCH_QUEUE_SERIAL, dispatch_get_main_queue());
从每个示例缓冲区获取媒体类型描述,以确定示例缓冲区是否包含音频或视频数据:

CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
CMMediaType mediaType = CMFormatDescriptionGetMediaType(formatDescription);
if (mediaType == kCMMediaType_Audio)...
if (mediaType == kCMMediaType_Video)...
将另一个类作为数据输出委托,而不是通过方法调用将示例缓冲区发送给另一个类;否则的话,你要加倍努力了

最后,确保您正在自己的队列中运行AVSession。根据苹果公司的AVCaptureSession文档:

dispatch_async(self.sessionQueue, ^{
    [self configureSession];
});

dispatch_async(self.sessionQueue, ^{
    [self.session startRunning];
});

dispatch_async(self.sessionQueue, ^{
    [self.session stopRunning];
});
startRunning
方法是一个阻塞调用,可能需要一些时间, 因此,您应该在串行队列上执行会话设置,以便 主队列没有被阻塞(这使UI保持响应)。看见 为了 实现示例

这包括对配置摄像机的方法的任何调用,特别是调用AVCaptureSession的startRunning或stopRunning方法的任何调用:

dispatch_async(self.sessionQueue, ^{
    [self configureSession];
});

dispatch_async(self.sessionQueue, ^{
    [self.session startRunning];
});

dispatch_async(self.sessionQueue, ^{
    [self.session stopRunning];
});

如果不能将委托设置为处理示例缓冲区的类,则可以考虑将它们放在两个类都有访问权限的队列中,然后传递一个键:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    static char kMyKey; // set key to any value; pass the key--not the sample buffer--to the receiver
    dispatch_queue_set_specific(((AppDelegate *)[[UIApplication sharedApplication] delegate].serialQueue,
                                &kMyKey,
                                (void*)CFRetain(sampleBuffer),
                                (dispatch_function_t)CFRelease); 
    });      
}
在receiver类中:

dispatch_async(((AppDelegate *)[[UIApplication sharedApplication] delegate]).serialQueue, ^{
            CMSampleBufferRef sb = dispatch_get_specific(&kMyKey);
            NSLog(@"sb: %i", CMSampleBufferIsValid(sb));
});

什么是
[self-sendVideoRaw:sampleBuffer]
?另外,您可以在captureOutput代码中简单地比较指针,而不是使用isKindOfClass。e、 g.
if(captureOutput==音频输出)
。你们在上课的时候一定要小心。它可能会返回一些你可能没有预料到的东西。这通常只发生在容器类中。请参阅此讨论。最后想一想。您不需要为音频和视频使用两个不同的捕获会话。两个AV IO类都可以添加到同一个会话中。@SteveMcFarlin分离音频和图像原始数据进行处理。@SteveMcFarlin但主要问题是视频帧的速度非常慢,委托函数在一秒钟内调用了2次,我在一秒钟内查看了8-10次。用户名-这很奇怪。您应该能够实现30FPS,只需一个纯粹的捕获。我问什么是
[self-sendVideoRaw:sampleBuffer]
的原因是,我认为这段代码可能阻塞了捕获队列,以至于只允许2FPS。如果您取消注释该代码,您将获得什么样的FPS。我假设仍然是2FPS。这可能是一个配置问题,但如果没有更多的代码,我就说不出了。你可以看看苹果公司的AVCamDemo项目。什么是
[self-sendVideoRaw:sampleBuffer]
?另外,你可以在captureOutput代码中简单地比较指针,而不是使用isKindOfClass。e、 g.
if(captureOutput==音频输出)
。你们在上课的时候一定要小心。它可能会返回一些你可能没有预料到的东西。这通常只发生在容器类中。请参阅此讨论。最后想一想。您不需要为音频和视频使用两个不同的捕获会话。两个AV IO类都可以添加到同一个会话中。@SteveMcFarlin分离音频和图像原始数据进行处理。@SteveMcFarlin但主要问题是视频帧的速度非常慢,委托函数在一秒钟内调用了2次,我在一秒钟内查看了8-10次。用户名-这很奇怪。您应该能够实现30FPS,只需一个纯粹的捕获。我问什么是
[self-sendVideoRaw:sampleBuffer]
的原因是,我认为这段代码可能阻塞了捕获队列,以至于只允许2FPS。如果您取消注释该代码,您将获得什么样的FPS。我假设仍然是2FPS。这可能是一个配置问题,但如果没有更多的代码,我就说不出了。你可以看看苹果公司的AVCamDemo项目。