una terminar por película pelicula importar guardar formato enviar descargar como cambiar archivo iphone video audio export avassetwriter

iphone - terminar - guardar archivo i movie



¿Cómo escribir una película con video Y audio usando AVAssetWriter? (2)

Quiero exportar una película con AVAssetWriter y no puedo imaginar cómo incluir sincronizadas las pistas de audio y video. Exportar solo video funciona bien, pero cuando agrego audio, la película resultante se ve así:

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

Intenté algunas cosas con CMSampleBufferSetOutputPresentationTimeStamp (restando el primer CMSampleBufferGetPresentationTimeStamp de la corriente) para el audio, pero no funcionó y no creo que sea la dirección correcta, ya que el video y el audio en la película de origen deben estar sincronizados. de todas formas...

Mi configuración en resumen: creo un AVAssetReader y 2 AVAssetReaderTrackOutput (uno para video, uno para audio) y los agrego a AVAssetReader , luego creo un AVAssetWriter y 2 AVAssetWriterInput (video y audio) y los agrego al AVAssetWriter ... Lo empiezo todo con:

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

Luego ejecuto 2 colas para hacer el búfer 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 ambas colas hasta que terminen:

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

Además, trato de guardar 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 ...?


Parece que assetWriterAudioInput ignora el tiempo de búfer de muestra para la escritura de audio. Hacer de esta manera

1) Escribir la pista de vídeo.

2) Cuando haya terminado, márquelo como finalizado, es decir, [videoWriterInput markAsFinished];

3) do [assetWriter startSessionAtSourceTime: timeRangeStart];

3) crear una instancia de lector de audio y comenzar a escribir audio.


-(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 } } ]; }

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