2011-03-30 6 views
18

Quiero exportar una película con AVAssetWriter y no puedo encontrar la manera de incluir las pistas de audio y video en sincronización. Exportar solo video funciona bien, pero cuando agrego audio la película resultante se ve así:¿Cómo escribir una película con video Y audio usando AVAssetWriter?

Primero veo el video (sin audio), luego el video se congela (mostrando el último cuadro de la imagen hasta el final) y después de algunos segundos oigo el audio.

He intentado algunas cosas con CMSampleBufferSetOutputPresentationTimeStamp (restando la primera CMSampleBufferGetPresentationTimeStamp de la corriente) para el audio, pero todo no funcionaba y no creo que es la dirección correcta, ya que el vídeo & de audio en la fuente película debería estar en sintonía de todos modos ...

Mi configuración en resumen: creo una AVAssetReader y 2 AVAssetReaderTrackOutput (uno para vídeo, una para audio) y añadirlos a la AVAssetReader, entonces creo una AVAssetWriter y 2 AVAssetWriterInput (video & audio) y agrégalos al AVAssetWriter ... Comienzo todo con:

[assetReader startReading]; 
[assetWriter startWriting]; 
[assetWriter startSessionAtSourceTime:kCMTimeZero]; 

Luego ejecutar 2 colas para hacer las cosas de tampón de muestra:

dispatch_queue_t queueVideo=dispatch_queue_create("assetVideoWriterQueue", NULL); 
[assetWriterVideoInput requestMediaDataWhenReadyOnQueue:queueVideo usingBlock:^ 
{ 
    while([assetWriterVideoInput isReadyForMoreMediaData]) 
    { 
     CMSampleBufferRef sampleBuffer=[assetReaderVideoOutput copyNextSampleBuffer]; 
     if(sampleBuffer) 
     { 
      [assetWriterVideoInput appendSampleBuffer:sampleBuffer]; 
      CFRelease(sampleBuffer); 
     } else 
     { 
      [assetWriterVideoInput markAsFinished]; 
      dispatch_release(queueVideo); 
      videoFinished=YES; 
      break; 
     } 
    } 
}]; 

dispatch_queue_t queueAudio=dispatch_queue_create("assetAudioWriterQueue", NULL); 
[assetWriterAudioInput requestMediaDataWhenReadyOnQueue:queueAudio usingBlock:^ 
{ 
    while([assetWriterAudioInput isReadyForMoreMediaData]) 
    { 
     CMSampleBufferRef sampleBuffer=[assetReaderAudioOutput copyNextSampleBuffer]; 
     if(sampleBuffer) 
     { 
      [assetWriterAudioInput appendSampleBuffer:sampleBuffer]; 
      CFRelease(sampleBuffer); 
     } else 
     { 
      [assetWriterAudioInput markAsFinished]; 
      dispatch_release(queueAudio); 
      audioFinished=YES; 
      break; 
     } 
    } 
}]; 

En el bucle principal espero a las dos colas hasta que terminen:

while(!videoFinished && !audioFinished) 
{ 
    sleep(1); 
} 
[assetWriter finishWriting]; 

Además Intento guarde el archivo resultante en la biblioteca con el siguiente código ...

NSURL *url=[[NSURL alloc] initFileURLWithPath:path]; 
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 
if([library videoAtPathIsCompatibleWithSavedPhotosAlbum:url]) 
{ 
    [library writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) 
    { 
     if(error) 
      NSLog(@"error=%@",error.localizedDescription); 
     else 
      NSLog(@"completed..."); 
    }]; 
} else 
    NSLog(@"error, video not saved..."); 

[library release]; 
[url release]; 

... pero me sale el error:

Video /Users/cb/Library/Application Support/iPhone Simulator/4.2/Applications/E9865BF9-D190-4912-9248-66768B1AB635/Documents/export.mp4 cannot be saved to the saved photos album: Error Domain=NSOSStatusErrorDomain Code=-12950 "Movie could not be played." UserInfo=0x5e4fb90 {NSLocalizedDescription=Movie could not be played.}

El código funciona sin problemas en otro programa. Entonces, ¿algo está mal con la película ...?

+0

Escribí una publicación en stackoverflow para crear una película a partir de un archivo de audio y una matriz de imágenes. Quizás alguna parte del código pueda ayudarte. http://stackoverflow.com/questions/6061092/make-movie-file-with-picture-array-and-song-file-using-avasset – TheRonin

Respuesta

-3

Comprueba que assetWriterAudioInput ignora el tiempo de búfer de muestra para la grabación de audio. Hazlo de esta manera.

1) Escribir pista de video.

2) Cuando termine, márquelo terminado, es decir [videoWriterInput markAsFinished];

3) do [assetWriter startSessionAtSourceTime: timeRangeStart];

3) crea una instancia del lector de audio y comienza a escribir audio.

+0

startSessionAtSourceTime es para escritor de activos, no para una entrada. Es imposible usarlo para gestionar entradas. – AlexeyVMP

9
-(void)mergeAudioVideo 
{ 

    NSString *videoOutputPath=[_documentsDirectory stringByAppendingPathComponent:@"dummy_video.mp4"]; 
    NSString *outputFilePath = [_documentsDirectory stringByAppendingPathComponent:@"final_video.mp4"]; 
    if ([[NSFileManager defaultManager]fileExistsAtPath:outputFilePath]) 
     [[NSFileManager defaultManager]removeItemAtPath:outputFilePath error:nil]; 


    NSURL *outputFileUrl = [NSURL fileURLWithPath:outputFilePath]; 
    NSString *filePath = [_documentsDirectory stringByAppendingPathComponent:@"newFile.m4a"]; 
    AVMutableComposition* mixComposition = [AVMutableComposition composition]; 

    NSURL *audio_inputFileUrl = [NSURL fileURLWithPath:filePath]; 
    NSURL *video_inputFileUrl = [NSURL fileURLWithPath:videoOutputPath]; 

    CMTime nextClipStartTime = kCMTimeZero; 

    AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:video_inputFileUrl options:nil]; 
    CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration); 

    AVMutableCompositionTrack *a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [a_compositionVideoTrack insertTimeRange:video_timeRange ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:nextClipStartTime error:nil]; 

    AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil]; 
    CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration); 
    AVMutableCompositionTrack *b_compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [b_compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:nextClipStartTime error:nil]; 

    AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality]; 
    _assetExport.outputFileType = @"com.apple.quicktime-movie"; 
    _assetExport.outputURL = outputFileUrl; 

    [_assetExport exportAsynchronouslyWithCompletionHandler: 
    ^(void) { 
     if (_assetExport.status == AVAssetExportSessionStatusCompleted) { 

      //Write Code Here to Continue 
     } 
     else { 
      //Write Fail Code here  
     } 
    } 
    ]; 



} 

Puede usar este código para combinar audio y video.

Cuestiones relacionadas