iOS 8 iPad在录制13-14秒后,AVCaptureMovieFileOutput无法获取音轨或者丢失了音轨。

17
我有以下代码,适用于iOS 6和7.x。
在iOS 8.1中,我有一个奇怪的问题,如果你捕获大约13秒或更长时间的会话,则生成的AVAsset只有一个轨道(视频),音频轨道不存在。
如果您录制较短的时间,AVAsset将如预期一样具有2个轨道(视频和音频)。我有足够的磁盘空间,应用程序已被授予使用相机和麦克风的权限。
我创建了一个具有最少代码的新项目,它重现了这个问题。
非常感谢任何想法。
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
{
    enum RecordingState { Recording, Stopped };
    enum RecordingState recordingState;

    AVCaptureSession *session;
    AVCaptureMovieFileOutput *output;
    AVPlayer *player;
    AVPlayerLayer *playerLayer;
    bool audioGranted;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self setupAV];
    recordingState = Stopped;
}

-(void)setupAV
{
    session = [[AVCaptureSession alloc] init];
    [session beginConfiguration];
    AVCaptureDevice *videoDevice = nil;

    for ( AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] ) {
        if ( device.position == AVCaptureDevicePositionBack ) {
            videoDevice = device;
            break;
        }
    }
    AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    if (videoDevice && audioDevice)
    {
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
        [session addInput:input];

        AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
        [session addInput:audioInput];

        NSURL *recordURL = [self tempUrlForRecording];
        [[NSFileManager defaultManager] removeItemAtURL:recordURL error:nil];

        output= [[AVCaptureMovieFileOutput alloc] init];
        output.maxRecordedDuration = CMTimeMake(45, 1);
        output.maxRecordedFileSize = 1028 * 1028 * 1000;
        [session addOutput:output];
    }
    [session commitConfiguration];
}

- (IBAction)recordingButtonClicked:(id)sender {
    if(recordingState == Stopped)
    {
        [self startRecording];
    }
    else
    {
        [self stopRecording];
    }
}

-(void)startRecording
{
    recordingState = Recording;
    [session startRunning];
    [output startRecordingToOutputFileURL:[self tempUrlForRecording] recordingDelegate:self];

}

-(void)stopRecording
{
    recordingState = Stopped;
    [output stopRecording];
    [session stopRunning];
}

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    AVAsset *cameraInput = [AVAsset assetWithURL:[self tempUrlForRecording]];
    //DEPENDING ON HOW LONG RECORDED THIS DIFFERS (<14 SECS - 2 Tracks, >14 SECS - 1 Track)
    NSLog(@"Number of tracks: %i", cameraInput.tracks.count);
}

-(id)tempUrlForRecording
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [paths objectAtIndex:0];

    NSString *path = @"camerabuffer.mp4";
    NSString *pathCameraInput =[documentsDirectoryPath stringByAppendingPathComponent: path];
    NSURL *urlCameraInput = [NSURL fileURLWithPath:pathCameraInput];

    return urlCameraInput;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

我还应该提到的是,在didFinishRecordingToOutputFileAtURL中没有报告任何错误(nil)。 - Si-N
好的,将片段间隔(fragmentInterval)设置比录制时间长就可以解决这个问题。但我确信我不应该需要这样做。CMTime fragmentInterval = CMTimeMake(5,1); [movieOutput setMovieFragmentInterval:fragmentInterval]; - Si-N
如果您不使用 maxRecordedDuration 并在 45 秒后手动停止录制,会发生什么? - Ja͢ck
我有同样的问题。我发现如果使用ffmpeg转码流并明确设置音量(即ffmpeg -i movie.mp4 -vol 256 movie2.mp4),您可以恢复声音。 - mvds
2个回答

18

这些内容可以帮助您解决问题。

[movieOutput setMovieFragmentInterval:kCMTimeInvalid];

我认为这是一个bug。文档上说,如果录制不成功,样本表就不会被写入。所以,如果录制成功了,它应该会自动被写入。但现在似乎不是这样了。

有什么想法吗?


1
哇,终于搞定了——我一直在为这个 BUG 烦恼。提供给其他人参考,问题并不在于最大持续时间或大小。 - Aaron Zinman
我有一个最大的大小和持续时间。我之前使用的是movieOutput.movieFragmentInterval = CMTime(value: 2, timescale: 1),偶尔会出现只有音频没有视频的情况。将其设置为kCMTimeInvalid解决了40%的问题。我的视频长度为8秒,因此不需要片段。 - atlex2
嗨@atlex2。你能给我提供一个演示吗?我没有遇到这个问题。 - Hugo
@dusty 我很乐意分享一个离线样本。这个 bug 也是我的麻烦之一。https://dev59.com/8mgv5IYBdhLWcg3wFs2m#10962216 - atlex2
self.movieOutput!.movieFragmentInterval = kCMTimeInvalid - drpawelo

3

我曾经遇到过这个问题,在Swift 4中解决方法如下:

  • 不要设置movieFileOutput.maxRecordedDuration。似乎存在一个错误,如果你设置了它,那么如果你录制的视频超过12-13秒,它们将没有音频。

  • 相反,使用一个计时器来停止录制,并像此一样设置movieFragmentInterval:

movieFileOutput.movieFragmentInterval = CMTime.invalid

以下是整个代码块,以展示我是如何做到的:

var seconds = 20
var timer = Timer()
var movieFileOutput = AVCaptureMovieFileOutput()

func startRecording(){
    movieFileOutput.movieFragmentInterval = CMTime.invalid
    movieFileOutput.startRecording(to: URL(fileURLWithPath: getVideoFileLocation()), recordingDelegate: self)
    startTimer()
}

func stopRecording(){
    movieFileOutput.stopRecording()
    timer.invalidate()
}

func startTimer(){
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)
}

@objc func updateTimer(){
    seconds -= 1
    if(seconds == 0){
        stopRecording()
    }
}

func getVideoFileLocation() -> String {
    return NSTemporaryDirectory().appending("myrecording.mp4")
}


extension FTVideoReviewViewController : AVCaptureFileOutputRecordingDelegate{
    public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
        print("Finished recording: \(outputFileURL)")
        // do stuff here when recording is finished
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接