Вопрос:

Безупречная запись звука при переключении камеры с использованием AVCaptureSession & AVAssetWriter

ios synchronization avcapturesession avassetwriter

293 просмотра

1 ответ

2702 Репутация автора

Я ищу способ сохранить непрерывную звуковую дорожку, переключаясь между передней и задней камерой. Многие приложения на рынке могут сделать это, один пример - Snapchat…

Решения должны использовать AVCaptureSession и AVAssetWriter. Также не следует явно использовать AVMutableComposition, поскольку существует ошибка между AVMutableComposition и AVCaptureSession ATM. Кроме того, я не могу позволить себе время пост-обработки.

В настоящее время, когда я меняю видеовход, аудиозапись пропускается и становится не синхронизированной.

Я включаю код, который может быть актуальным.

Флип камера

-(void) updateCameraDirection:(CamDirection)vCameraDirection {
    if(session) {
        AVCaptureDeviceInput* currentInput;
        AVCaptureDeviceInput* newInput;
        BOOL videoMirrored = NO;
        switch (vCameraDirection) {
            case CamDirection_Front:
                currentInput = input_Back;
                newInput = input_Front;
                videoMirrored = NO;
                break;
            case CamDirection_Back:
                currentInput = input_Front;
                newInput = input_Back;
                videoMirrored = YES;
                break;
            default:
                break;
        }

        [session beginConfiguration];
        //disconnect old input
        [session removeInput:currentInput];
        //connect new input
        [session addInput:newInput];
        //get new data connection and config
        dataOutputVideoConnection = [dataOutputVideo connectionWithMediaType:AVMediaTypeVideo];
        dataOutputVideoConnection.videoOrientation = AVCaptureVideoOrientationPortrait;
        dataOutputVideoConnection.videoMirrored = videoMirrored;
        //finish
        [session commitConfiguration];
    }
}

Образец буфера

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
    //not active
    if(!recordingVideo)
        return;

    //start session if not started
    if(!startedSession) {
        startedSession = YES;
        [assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
    }

    //Process sample buffers
    if (connection == dataOutputAudioConnection) {
        if([assetWriterInputAudio isReadyForMoreMediaData]) {
            BOOL success = [assetWriterInputAudio appendSampleBuffer:sampleBuffer];
            //…
        }

    } else if (connection == dataOutputVideoConnection) {
        if([assetWriterInputVideo isReadyForMoreMediaData]) {        
            BOOL success = [assetWriterInputVideo appendSampleBuffer:sampleBuffer];
            //…
        }
    }
}

Возможно, отрегулируйте время выборки аудиосэмпла?

Автор: Andres Canella Источник Размещён: 08.11.2016 07:21

Ответы (1)


0 плюса

207 Репутация автора

Привет, я столкнулся с той же проблемой и обнаружил, что после переключения камер следующий кадр был перемещен далеко не на место. Это, казалось, сдвигало каждый кадр после этого, приводя к тому, что видео и аудио не синхронизировались. Мое решение состояло в том, чтобы после переключения камер сдвинуть каждый неправильный кадр в правильное положение.

Извините мой ответ будет в Swift 4.2

Вы должны будете использовать AVAssetWriterInputPixelBufferAdaptor, чтобы добавить образцы буфера в указанную временную метку представления.

previousPresentationTimeStampявляется отметкой времени представления предыдущего кадра и currentPresentationTimestampявляется, как вы уже догадались, отметкой времени представления текущего. maxFrameDistanceработал хорошо при тестировании, но вы можете изменить это по своему вкусу.

let currentFramePosition = (Double(self.frameRate) * Double(currentPresentationTimestamp.value)) / Double(currentPresentationTimestamp.timescale)
let previousFramePosition = (Double(self.frameRate) * Double(previousPresentationTimeStamp.value)) / Double(previousPresentationTimeStamp.timescale)
var presentationTimeStamp = currentPresentationTimestamp
let maxFrameDistance = 1.1
let frameDistance = currentFramePosition - previousFramePosition
if frameDistance > maxFrameDistance {
    let expectedFramePosition = previousFramePosition + 1.0
    //print("[mwCamera]: Frame at incorrect position moving from \(currentFramePosition) to \(expectedFramePosition)")

    let newFramePosition = ((expectedFramePosition) * Double(currentPresentationTimestamp.timescale)) / Double(self.frameRate)

    let newPresentationTimeStamp = CMTime.init(value: CMTimeValue(newFramePosition), timescale: currentPresentationTimestamp.timescale)

    presentationTimeStamp = newPresentationTimeStamp
}

let success = assetWriterInputPixelBufferAdator.append(pixelBuffer, withPresentationTime: presentationTimeStamp)
if !success, let error = assetWriter.error {
    fatalError(error.localizedDescription)
}

Также обратите внимание - это сработало, потому что я поддерживал постоянную частоту кадров, поэтому убедитесь, что у вас есть полный контроль над частотой кадров устройства захвата на протяжении всего этого процесса.

У меня есть репо с использованием этой логики здесь

Автор: Woody Jean-louis Размещён: 13.06.2019 03:06
Вопросы из категории :
32x32