2014-11-22 4 views
3

Я пытаюсь сделать некоторые основные видео-композиции в Xamarin/Monotouch и имею некоторый успех, но я застрял, что кажется довольно простой задачей.AVAssetExportSession - видео не может быть составлено

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

выпуск:

Когда я добавить звуковую дорожку в экспорт я всегда получаю отказавший ответ с этой ошибкой:

Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo=0x1912c320 {NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The video could not be composed.}

Если я не установить свойство videoComposition на exportSession аудио и экспорт видео идеально подходит только с неправильной ориентацией. Если бы кто-нибудь мог дать мне несколько советов, то это было бы весьма признательно. Ниже мой код:

var composition = new AVMutableComposition(); 
       var compositionTrackAudio = composition.AddMutableTrack(AVMediaType.Audio, 0); 
       var compositionTrackVideo = composition.AddMutableTrack(AVMediaType.Video, 0); 
       var videoCompositionInstructions = new AVVideoCompositionInstruction[files.Count]; 
      var index = 0; 
      var renderSize = new SizeF(480, 480); 
      var _startTime = CMTime.Zero; 
      //AVUrlAsset asset; 



      var asset = new AVUrlAsset(new NSUrl(file, false), new AVUrlAssetOptions()); 
      //var asset = AVAsset.FromUrl(new NSUrl(file, false)); 


      //create an avassetrack with our asset 
      var videoTrack = asset.TracksWithMediaType(AVMediaType.Video)[0]; 
      var audioTrack = asset.TracksWithMediaType(AVMediaType.Audio)[0]; 

      //create a video composition and preset some settings 

      NSError error; 

      var assetTimeRange = new CMTimeRange { Start = CMTime.Zero, Duration = asset.Duration }; 

      compositionTrackAudio.InsertTimeRange(new CMTimeRange 
      { 
       Start = CMTime.Zero, 
       Duration = asset.Duration, 
      }, audioTrack, _startTime, out error); 

      if (error != null) { 
       Debug.WriteLine (error.Description); 
      } 

      compositionTrackVideo.InsertTimeRange(assetTimeRange, videoTrack, _startTime, out error); 

      //create a video instruction 


      var transformer = new AVMutableVideoCompositionLayerInstruction 
      { 
       TrackID = videoTrack.TrackID, 
      }; 

      var audioMix = new AVMutableAudioMix(); 
      var mixParameters = new AVMutableAudioMixInputParameters{ 
       TrackID = audioTrack.TrackID 
      }; 

      mixParameters.SetVolumeRamp (1.0f, 1.0f, new CMTimeRange { 
       Start = CMTime.Zero, 
       Duration = asset.Duration 
      }); 


      audioMix.InputParameters = new [] { mixParameters }; 
      var t1 = CGAffineTransform.MakeTranslation(videoTrack.NaturalSize.Height, 0); 
      //Make sure the square is portrait 
      var t2 = CGAffineTransform.Rotate(t1, (float)(Math.PI/2f)); 
      var finalTransform = t2; 

      transformer.SetTransform(finalTransform, CMTime.Zero); 
      //add the transformer layer instructions, then add to video composition 


      var instruction = new AVMutableVideoCompositionInstruction 
      { 
       TimeRange = assetTimeRange, 
       LayerInstructions = new []{ transformer } 
      }; 
      videoCompositionInstructions[index] = instruction; 
      index++; 
      _startTime = CMTime.Add(_startTime, asset.Duration); 

      var videoComposition = new AVMutableVideoComposition(); 
      videoComposition.FrameDuration = new CMTime(1 , (int)videoTrack.NominalFrameRate); 
      videoComposition.RenderScale = 1; 
      videoComposition.Instructions = videoCompositionInstructions; 
      videoComposition.RenderSize = renderSize; 

      var exportSession = new AVAssetExportSession(composition, AVAssetExportSession.PresetHighestQuality); 

      var filePath = _fileSystemManager.TempDirectory + DateTime.UtcNow.Ticks + ".mp4"; 

      var outputLocation = new NSUrl(filePath, false); 

      exportSession.OutputUrl = outputLocation; 
      exportSession.OutputFileType = AVFileType.Mpeg4; 
      exportSession.VideoComposition = videoComposition; 
      exportSession.AudioMix = audioMix; 
      exportSession.ShouldOptimizeForNetworkUse = true; 
      exportSession.ExportAsynchronously(() => 
      { 
       Debug.WriteLine(exportSession.Status); 

       switch (exportSession.Status) 
       { 

        case AVAssetExportSessionStatus.Failed: 
         { 
          Debug.WriteLine(exportSession.Error.Description); 
          Debug.WriteLine(exportSession.Error.DebugDescription); 
          break; 
         } 
        case AVAssetExportSessionStatus.Completed: 
         { 
          if (File.Exists(filePath)) 
          { 
           _uploadService.AddVideoToVideoByteList(File.ReadAllBytes(filePath), ".mp4"); 
           Task.Run(async() => 
           { 
            await _uploadService.UploadVideo(_videoData); 
           }); 
          } 
          break; 
         } 
        case AVAssetExportSessionStatus.Unknown: 
         { 
          break; 
         } 
        case AVAssetExportSessionStatus.Exporting: 
         { 
          break; 
         } 
        case AVAssetExportSessionStatus.Cancelled: 
         { 
          break; 
         } 

       } 
      }); 

ответ

3

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

+0

Привет, у меня есть такая же ошибка, могу ли я узнать, что вы редактируете, чтобы решить эту проблему? –

+0

Привет @HongZhou, это было довольно давно, но это было из-за, как указано выше, где я порядок активов был неправильным. У меня больше нет кода, как это было на моей предыдущей работе. – beedubsss

0

Моя проблема заключается в том, что я забыл установить TimeRange, он должен быть, как этот

let instruction = AVMutableVideoCompositionInstruction() 
instruction.layerInstructions = [layer] 
instruction.timeRange = CMTimeRange(start: kCMTimeZero, duration: videoDuration) 

Обратите внимание, что время окончания AVMutableVideoCompositionInstruction.timeRange «s должен быть действительным. Он отличается от AVAssetExportSession.timeRange

The time range to be exported from the source. The default time range of an export session is kCMTimeZero to kCMTimePositiveInfinity, meaning that (modulo a possible limit on file length) the full duration of the asset will be exported. You can observe this property using Key-value observing.