text: //
  //  EMMVXViewController.h
  //  App
  //
  //  Created by niegaotao on 2018/4/14.
  //  Copyright © 2018年 niegaotao. All rights reserved.
  //
  
  #import <NXUI/NXTableViewController.h>
  
  @interface EMMVXViewController : NXTableViewController
  
  @end
  
  
  
  
  /*
   NSObject -> AVAsset -> AVComposition -> AVMutableComposition //相当于一个容器
   NSObject -> AVAsset -> AVURLAsset -> AVFragmentedAsset
   
   
   1.创建一个容器:再分别创建一个视频轨道和一个音频轨道
   AVMutableComposition *mainComposition =  [[AVMutableComposition alloc] init];
   
   AVMutableCompositionTrack *compositionVideoTrack = [mainComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
   AVMutableCompositionTrack *compositionAudioTrack = [mainComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
  
   
   2.根据已有的视频音频资源获取视频轨道和音频轨道
   NSArray<AVAssetTrack *> *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
   AVAssetTrack *videoTrack = [videoTracks objectAtIndex:0]
   
   NSArray<AVAssetTrack *> *audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
   AVAssetTrack *audioTrack = [audioTracks objectAtIndex:0]
  
   
   3.视轨+音轨加入目标音轨视轨
   float videotime = asset.duration.value / asset.duration.timescale //时长：单位秒
   
   compositionVideoTrack.preferredTransform = videoTrack.preferredTransform
   [compositionVideoTrack insertTimeRange(CMTimeRangeMake(KCMTimeZero, assit.duration)) ofTrack:videoTrack atTime:KCMTimeZero error:nil]
   
   float audio_time_scale = audioTrack.natureTimeScale
   CMTime audio_duration = CMTimeMake(videotime * audio_time_scale, audio_time_scale)
   [compositionAudioTrack insertTimeRanke(CMTimeRangeMake(kCMTimeZero, audio_duration) ofTrack:audioTrack atTime:KCMTimeZero error:nil)]
   
   //insertTimeRange:表示该视频的时间范围，atTime表示你要在哪个时间点去插入这个轨道
   
  4.对音轨和视轨进行操作
   AVMuatableVideoComposition *targetComposition = [AVMutavleVideoComposition videoCompositionWithProperitiesOfAsset:mainComposition]
   AVMuatableVideoComposition *originComposition = [AVMutavleVideoComposition videoCompositionWithProperitiesOfAsset:asset]
  
   targetComposition.renderSize = originComposition.renderSize
   
   AVMuatableAudioMix *avMixTools = [AVMutableAudioMix audioMix]
  //获取第一个音频轨道
   AVMuatableAudioMixInputParamaters *one_audioParam = [AVMutableAudioMixInputParamaters audioMixInputParamatersWithTrack:complsotionAudioTrack];
  //设置第一个音轨的音量
   [one_audioParam setVolumeRampFromStartVolume:startVolume toEndVolume:endVolume timeRange:CMTimeRankeMake(KCMTimeZero, asset.duration)]
   //获取第一个音频轨道
   AVMuatableAudioMixInputParamaters *two_audioParam = [AVMutableAudioMixInputParamaters audioMixInputParamatersWithTrack:mixAudioTrack];
   //设置第一个音轨的音量
   [two_audioParam setVolumeRampFromStartVolume:startVolume toEndVolume:endVolume timeRange:CMTimeRankeMake(KCMTimeZero, asset.duration)]
   
   avMixTools.inputParameters = @[one_audioParam, two_audioParam]
   
   5.输出
   - (void)createAssetReader:(AVComposition *)composition videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix {
      AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:composition error:nil]
      assetReader.timeRange = CMTimeRangeMake(KCMTimeZero, CTTimeMake(composition.duration.value, composition.duration.timescale))
      NSDictionary *outputSettings = @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)};
      AVAssetReaderVideoCompositionOutput *readerVideoOutput = [AVAssetReaderVideoCompositionOutput assetReaderVideoCompositionOutputWithVideoTracks:[composition tracksWithMediaType:.video] videoSettings:videoSettings];
   
      if !TARGET_IPHONE_SIMULATOR
      if ([AVVideoComposition isKindOfClass:AVMutableVideoComposition]) {
          [(AVMutableVideoComposition *)videoComposition setRenderScale:1.0];
      }
      #endif
      readerVideoOutput.videoComposition = videoComposition
      readerVideoOutput.alwaysCopiesSampleData = NO
      [assetReader addOutput:readerVideoOutput];
   
      NSArray *audioTracks = [composition tracksWithMediaMediaType:.audio];
   
      BOOL shouldRecordAudioTrack = ([audioTracks count] > 0);//modify be Chen siyang 2017-04-08
      AVAssetReaderAudioMixOutput *readerAudioOutput = nil;
   
      if (shouldRecordAudioTrack){
          readerAudioOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:audioTracks audioSettings:nil];
          readerAudioOutput.audioMix = audioMix;
          readerAudioOutput.alwaysCopiesSampleData = NO;
          [assetReader addOutput:readerAudioOutput];
      }
      return assetReader;
   }
   
   - (NSDictionary *)configAudioInput{
   AudioChannelLayout channelLayout = {
   .mChannelLayoutTag = kAudioChannelLayoutTag_Stereo,
   .mChannelBitmap = kAudioChannelBit_Left,
   .mNumberChannelDescriptions = 0
   };
   NSData *channelLayoutData = [NSData dataWithBytes:&channelLayout length:offsetof(AudioChannelLayout, mChannelDescriptions)];
   NSDictionary *audioInputSetting = @{
   AVFormatIDKey: @(kAudioFormatMPEG4AAC),
   AVSampleRateKey: @(44100),
   AVNumberOfChannelsKey: @(2),
   AVChannelLayoutKey:channelLayoutData
   };
   return audioInputSetting;
   }
   
   - (NSDictionary *)configVideoInput{
   NSDictionary *videoInputSetting = @{
   AVVideoCodecKey:AVVideoCodecH264,
   AVVideoWidthKey: @(374),
   AVVideoHeightKey: @(666)
   };
   return videoInputSetting;
   }
   
   [assetReader startReading];
   [assetWriter startWriting];
   
   dispatch_queue_t rwAudioSerializationQueue = dispatch_queue_create("Audio Queue", DISPATCH_QUEUE_SERIAL);
   dispatch_queue_t rwVideoSerializationQueue = dispatch_queue_create("Video Queue", DISPATCH_QUEUE_SERIAL);
   dispatch_group_t dispatchGroup = dispatch_group_create();
   
   //这里开始时间是可以自己设置的
   [assetWriter startSessionAtSourceTime:kCMTimeZero];
   
   
   dispatch_group_enter(dispatchGroup);
   __block BOOL isAudioFirst = YES;
   [assetWriterAudioInput requestMediaDataWhenReadyOnQueue:rwAudioSerializationQueue usingBlock:^{
   
   while ([assetWriterAudioInput isReadyForMoreMediaData]&&assetReader.status == AVAssetReaderStatusReading) {
   CMSampleBufferRef nextSampleBuffer = [assetReaderAudioOutput copyNextSampleBuffer];
   if (isAudioFirst) {
   isAudioFirst = !isAudioFirst;
   continue;
   }
   if (nextSampleBuffer) {
   [assetWriterAudioInput appendSampleBuffer:nextSampleBuffer];
   CFRelease(nextSampleBuffer);
   } else {
   [assetWriterAudioInput markAsFinished];
   dispatch_group_leave(dispatchGroup);
   break;
   }
   
   }
   
   }];
   
   dispatch_group_enter(dispatchGroup);
   __block BOOL isVideoFirst = YES;
   [assetWriterVideoInput requestMediaDataWhenReadyOnQueue:rwVideoSerializationQueue usingBlock:^{
   
   while ([assetWriterVideoInput isReadyForMoreMediaData]&&assetReader.status == AVAssetReaderStatusReading) {
   
   CMSampleBufferRef nextSampleBuffer = [assetReaderVideoOutput copyNextSampleBuffer];
   if (isVideoFirst) {
   isVideoFirst = !isVideoFirst;
   continue;
   }
   if (nextSampleBuffer) {
   [assetWriterVideoInput appendSampleBuffer:nextSampleBuffer];
   CFRelease(nextSampleBuffer);
   NSLog(@"加载");
   } else {
   [assetWriterVideoInput markAsFinished];
   dispatch_group_leave(dispatchGroup);
   break;
   }
   }
   }];
   
   dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
   [assetWriter finishWritingWithCompletionHandler:^{
   if (assetWriter.status == AVAssetWriterStatusCompleted) {
   NSLog(@"加载完毕");
   
   } else {
   NSLog(@"加载失败");
   }
   if ([self.delegate respondsToSelector:@selector(synthesisResult)]) {
   [self.delegate synthesisResult];
   }
   
   
   }];
   });
   
   作者：Y_Swordsman
   链接：https://www.jianshu.com/p/3f2966f162a5
   來源：简书
   简书著作权归作者所有，任何形式的转载都请联系作者获得授权并注明出处。
   
   */
  