1

Я делаю видео из массива UIImages. Я сделал это успешно & все изображения показываются на видео. Я использую AVAssetExportSession для экспорта видео, которое также работает, за исключением случаев, когда я использую свойство VideoComposition AVAssetExportSession, на видео отображается только первое изображение. Вот мой код:AVAssetExportSession videoComposition не показывает все кадры в видео

func mergeAudioVideoFiles(videoUrl:NSURL, audioUrl:NSURL)->NSURL 
{ 
    let mixComposition : AVMutableComposition = AVMutableComposition() 
    var mutableCompositionVideoTrack : [AVMutableCompositionTrack] = [] 
    var mutableCompositionAudioTrack : [AVMutableCompositionTrack] = [] 
    let totalVideoCompositionInstruction : AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction() 


    //start merge 

    let aVideoAsset : AVAsset = AVAsset(URL: videoUrl) 
    let aAudioAsset : AVAsset = AVAsset(URL: audioUrl) 

    mutableCompositionVideoTrack.append(mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)) 
    mutableCompositionAudioTrack.append(mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)) 

    let aVideoAssetTrack : AVAssetTrack = aVideoAsset.tracksWithMediaType(AVMediaTypeVideo)[0] 
    let aAudioAssetTrack : AVAssetTrack = aAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0] 
    do{ 
     try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aVideoAssetTrack, atTime: kCMTimeZero) 

     try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aAudioAssetTrack, atTime: kCMTimeZero)  
    }catch{ 

    } 
    print("\nslide duraition:\(CMTimeGetSeconds(aVideoAssetTrack.timeRange.duration))\n") 
    totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,aVideoAssetTrack.timeRange.duration) 

    let mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition(propertiesOfAsset: aVideoAsset) 
    mutableVideoComposition.frameDuration = aVideoAssetTrack.timeRange.duration 
    mutableVideoComposition.renderSize = CGSizeMake(1280,720) 

    //find your video on this URl 
    let savePathUrl : NSURL = NSURL(fileURLWithPath: documentsPath.stringByAppendingPathComponent("pandorarofinalist.mov")) 

    // 4. Add subtitles (we call it theme) 
    let insertTime = kCMTimeZero 
    //let endTime = aVideoAssetTrack.timeRange.duration 
    //let range = self.totalFrameDuration 
    //let themeVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition(propertiesOfAsset: aVideoAsset) 
    // 4.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation. 

    let videolayerInstruction : AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: aVideoAssetTrack) 
    totalVideoCompositionInstruction.layerInstructions = NSArray(array: [videolayerInstruction]) as! [AVVideoCompositionLayerInstruction] 
    mutableVideoComposition.instructions = NSArray(array: [totalVideoCompositionInstruction]) as! [AVVideoCompositionInstructionProtocol] 

    //mutableCompositionAudioTrack[0].preferredTransform 
    videolayerInstruction.setTransform(mutableCompositionVideoTrack[0].preferredTransform, atTime: insertTime) 
    //videolayerInstruction.setOpacity(0.0, atTime: endTime) 

    // 4.3 - Add instructions 


    // mutableVideoComposition.renderScale = 1.0 
    //themeVideoComposition.renderSize = CGSizeMake(aVideoAssetTrack.naturalSize.width, aVideoAssetTrack.naturalSize.height) 
    //themeVideoComposition.frameDuration = self.totalFrameDuration 

    // add text 

    let title = String("my video") 

    let titleLayer = CATextLayer() 
    titleLayer.string = title 
    titleLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: 100) 
    let fontName: CFStringRef = "Helvetica-Bold" 
    let fontSize = CGFloat(50) 
    titleLayer.font = CTFontCreateWithName(fontName, fontSize, nil) 
    titleLayer.alignmentMode = kCAAlignmentCenter 
    titleLayer.foregroundColor = UIColor.orangeColor().CGColor 

    let backgroundLayer = CALayer() 
    backgroundLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: aVideoAssetTrack.naturalSize.height) 
    backgroundLayer.masksToBounds = true 
    backgroundLayer.addSublayer(titleLayer) 

    // 2. set parent layer and video layer 

    let parentLayer = CALayer() 
    let videoLayer = CALayer() 
    parentLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: aVideoAssetTrack.naturalSize.height) 
    videoLayer.frame = CGRect(x: 0, y: 0, width: aVideoAssetTrack.naturalSize.width, height: aVideoAssetTrack.naturalSize.height) 
    parentLayer.addSublayer(videoLayer) 
    parentLayer.addSublayer(backgroundLayer) 

    //backgroundLayer.opacity = 1.0 

    // 3. make animation 

    mutableVideoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer) 

    // Remove the file if it already exists (merger does not overwrite) 

    do{ 
     let fileManager = NSFileManager.defaultManager() 
     try fileManager.removeItemAtURL(savePathUrl) 
    }catch{ 
    } 

    let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)! 
    assetExport.outputFileType = AVFileTypeMPEG4 
    assetExport.outputURL = savePathUrl 
    assetExport.shouldOptimizeForNetworkUse = true 
    assetExport.videoComposition = mutableVideoComposition 

    assetExport.exportAsynchronouslyWithCompletionHandler {() -> Void in 
     switch assetExport.status { 

     case AVAssetExportSessionStatus.Completed: 

      PHPhotoLibrary.sharedPhotoLibrary().performChanges({ 
       PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(savePathUrl) 
      }) { success, error in 
       if !success { 
        print("Error saving video: \(error)") 
       } 
      } 

      //Uncomment this if u want to store your video in asset 

      //let assetsLib = ALAssetsLibrary() 
      //assetsLib.writeVideoAtPathToSavedPhotosAlbum(savePathUrl, completionBlock: nil) 

      print("success") 
     case AVAssetExportSessionStatus.Failed: 
      print("failed \(assetExport.error)") 
     case AVAssetExportSessionStatus.Cancelled: 
      print("cancelled \(assetExport.error)") 
     default: 
      print("complete") 
     } 
    } 

    return savePathUrl 
} 

Проблема заключается в том, что линия assetExport.videoComposition = mutableVideoComposition Если я пропустить эту строку вывода видео просто отлично. Но если я добавлю эту строку, на выходном видео отображается только первое изображение, которое я добавил для видео. Я должен установить videoComposition, потому что добавляю текст заголовка к видео, которое я добавил как CALayer. Я использую swift 2.2 для своего проекта. Любая помощь, пожалуйста? Заранее спасибо.

+0

Вы нашли решение? – Sam

+0

Это ошибка с AVVideoCompositionCoreAnimationTool, пожалуйста, проверьте этот пост и все связанные записи http://stackoverflow.com/search?tab=newest&q=swift%20AVAssetWriter – Sam

+0

Однако мне не удалось реализовать решение – Sam

ответ

2

Я считаю, что проблема эта линия:

mutableVideoComposition.frameDuration = aVideoAssetTrack.timeRange.duration

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

Для 30fps видео, вы должны установить frameDuration 1/30 секунды, как это:

mutableVideoComposition.frameDuration = CMTime(value: 1, timescale: 30)


Предупреждение: Будьте осторожны, чтобы не использовать другой инициализации метод CMTime(seconds: 1.0, preferredTimescale: 30) , потому что это сделает ваш frameDuration 1 секундой.

 Смежные вопросы

  • Нет связанных вопросов^_^