【问题标题】:Video freezes on camera switch with AVFoundation使用 AVFoundation 切换相机时视频冻结
【发布时间】:2013-01-17 22:08:37
【问题描述】:

我制作了一个具有捕捉和保存视频功能的应用。 我为此使用了 AVFoundation,Apple's AVCam 一直是我的向导。

希望我能说清楚:
一切正常,直到我第一次发布处理 AVCamCaptureManager 的 videoViewController(在 AVCam 中,这将是 AVCamViewController)。之后,当我再次创建它时,视频在相机切换后立即冻结。即使重新运行也无济于事,清理或设备重置也无济于事。 (有时其中一件事会有所帮助,但这不是规则)。

当不需要节省内存时,我会释放 videoViewController。

切换摄像头的代码与AVCam中基本相同:

NSError *error;
AVCaptureDeviceInput *newVideoInput;
AVCaptureDevicePosition position = currentVideoInput.device.position;

if (position == AVCaptureDevicePositionBack)
    newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:frontFacingCamera error:&error];
else if (position == AVCaptureDevicePositionFront)
    newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:backFacingCamera error:&error];

if (newVideoInput != nil) {
    [session beginConfiguration];
    [session removeInput:currentVideoInput];
    if ([session canAddInput:newVideoInput]) {
        [session addInput:newVideoInput];
        [self setVideoInput:newVideoInput];
} else {
    [session addInput:currentVideoInput];
}
    [session commitConfiguration];
    [newVideoInput release];
} else if (error) {
    NSLog(@"%@",[error localizedDescription]);
}

我用来关闭 videoView 的代码

[self.videoViewController.view removeFromSuperview];
self.videoViewController = nil;

我目前的“解决方法”是不管它,即使我不需要它。

谁能解释为什么会发生这种情况以及如何解决它。

编辑:已解决
正如 W Dyson 在他的回复中指出的那样,我应该在像这样释放我的 videoViewController 之前停止会话:

[[[self.videoViewController captureManager] session] stopRunning];
[self.videoViewController.view removeFromSuperview];
self.videoViewController = nil;

感谢戴森。

【问题讨论】:

    标签: objective-c ios4 avfoundation ipad-2


    【解决方案1】:

    试试这个——它对我来说就像一个冠军:

    BOOL isUsingFrontFacingCamera;
    
    - (BOOL) swapCameras
    {
        if ([self cameraCount] > 1) {
            AVCaptureDevicePosition desiredPosition;
            if (isUsingFrontFacingCamera) {
                desiredPosition = AVCaptureDevicePositionBack;
            } else {
                desiredPosition = AVCaptureDevicePositionFront;
            }
    
            for (AVCaptureDevice *d in [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]) {
                if ([d position] == desiredPosition) {
                    [[self session] beginConfiguration];
                    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:d error:nil];
                    for (AVCaptureInput *oldInput in [[self session] inputs]) {
                        [[self session] removeInput:oldInput];
                    }
                    [[self session] addInput:input];
                    [[self session] commitConfiguration];
                    break;
                }
            }
            isUsingFrontFacingCamera = !isUsingFrontFacingCamera;
            return YES;
        }
        return NO;
    }
    

    您应该能够将此代码放入 VideoRecorderCaptureManager.m

    中以替换原始 swapCameras

    来源:Apple 的 SquareCam 示例代码。

    【讨论】:

    • 这是唯一对我有用的代码。我想诀窍是从会话中删除所有输入设备。谢谢。
    • @mpemburn 这对我来说很好用,我可以用前后摄像头录制视频,但是在录制前置摄像头时,最终视频是静音(无音频),后置摄像头工作正常请帮我检查这个stackoverflow.com/questions/31457302/…
    【解决方案2】:

    您是否收到错误日志?如果没有,您需要修复上面的代码并查看他们所说的内容。 您使用的是什么版本的 AVCam?他们最近将项目更新到了 1.2 版,效率更高并且使用了块。

    根据我的经验,您不应该创建和重新创建会话,您可以保持打开状态。也许您需要稍微不同地构建您的应用程序。你的应用到底是关于什么的?也许我们可以帮助你。如果您的应用程序以相机为中心,那么离开会话会更容易,如果您只是以模态方式拍摄视频,那么使用 AVCam 可能是矫枉过正。

    对我来说,您的实际问题听起来像是 AVCaptureDeviceInput。下载原始的 AVCam 包,看看您是否更改了任何保留计数或安全 if 语句。如果还有其他代码,请贴出来。

    更新:你能改变吗

    } else if (error) {
        NSLog(@"%@",[error localizedDescription]);
    }
    

    } if (error) {
        NSLog(@"%@",[error localizedDescription]);
    }
    

    如果有错误告诉我?

    此外,在释放拥有会话的视图控制器之前,请确保停止会话并将捕获管理器设置为 nil。

    更新 2:试试这个切换代码。这是我一直在使用的。 AVCamMirringMode 是一个结构如下:

    enum {
        AVCamMirroringOff   = 1,
        AVCamMirroringOn    = 2,
        AVCamMirroringAuto  = 3
    };
    typedef NSInteger AVCamMirroringMode;
    
    
    - (BOOL) toggleCamera
    {
        BOOL success = NO;
    
        if ([self cameraCount] > 1) {
            NSError *error;
            AVCaptureDeviceInput *newVideoInput;
            AVCaptureDevicePosition position = [[videoInput device] position];
    
            BOOL mirror;
            if (position == AVCaptureDevicePositionBack){
                newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self frontFacingCamera] error:&error];
                switch ([self mirroringMode]) {
                    case AVCamMirroringOff:
                        mirror = NO;
                        break;
                    case AVCamMirroringOn:
                        mirror = YES;
                        break;
                    case AVCamMirroringAuto:
                    default:
                        mirror = YES;
                        break;
                }
            }
            else if (position == AVCaptureDevicePositionFront){
                newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backFacingCamera] error:&error];
                switch ([self mirroringMode]) {
                    case AVCamMirroringOff:
                        mirror = NO;
                        break;
                    case AVCamMirroringOn:
                        mirror = YES;
                        break;
                    case AVCamMirroringAuto:
                    default:
                        mirror = NO;
                        break;
                }
            }
            else
                goto bail;
    
            if (newVideoInput != nil) {
                [[self session] beginConfiguration];
                [[self session] removeInput:[self videoInput]];
                if ([[self session] canAddInput:newVideoInput]) {
                    [[self session] addInput:newVideoInput];
                    AVCaptureConnection *connection = [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
                    if ([connection isVideoMirroringSupported]) {
                        [connection setVideoMirrored:mirror];
                    }
                    [self setVideoInput:newVideoInput];
                } else {
                    [[self session] addInput:[self videoInput]];
                }
                [[self session] commitConfiguration];
                success = YES;
                [newVideoInput release];
    
            } else if (error) {
                if ([[self delegate] respondsToSelector:@selector(captureManager:didFailWithError:)]) {
                    [[self delegate] captureManager:self didFailWithError:error];
                }
            }
        }
    
    bail:
        return success;
    }
    

    【讨论】:

    • 不,没有错误日志。你有什么建议?我查看了 AVCam(是的,我使用了 1.2)并实现了它的 -captureManager:didFailWithError:,但仍然没有错误日志。该应用程序不以相机为中心。相机是附带的东西,可能根本不会被某些人使用。我再次检查了 AVCam。唯一的区别是,在 AVCam 中,摄像头始终存在,我想关闭它,原因我上面已经提到了。
    • 问题是,没有看到您的项目以及您对 AVCam 项目所做的更改,这很棘手。另外,运行分析器,看看它是否捕捉到任何东西。
    • 好的,我已经剥离了所有自定义代码并返回到原始 AVCam,但问题仍然存在。我已按照您的建议更改了错误位,但仍然没有错误。但是,如果我在相机冻结​​后尝试录制,则会出现错误。它说“操作无法完成。没有这样的文件或目录”。奇怪的是,它在相机切换之前正常记录。我希望这会有所帮助。
    • 感谢您在 UPDATE 2 中提供的代码 sn-p,但这并没有帮助...您所说的另一件事是什么,但我之前错过了它。在释放父 ViewController 之前,我必须停止会话。现在这是合乎逻辑的,但我之前没有想到它,因为视频仅在相机切换后冻结。非常感谢您的时间和精力。
    • 没问题。我发布的 UPDATE 2 代码来自 AVCam 的 1.0 版,我使用 1.0 的融合,1.2 是我的应用程序。如果您愿意,请随意使用它。很高兴我能帮上忙。
    猜你喜欢
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多