ios 循环AVMutableCompositionTrack

goqiplq2  于 2023-05-30  发布在  iOS
关注(0)|答案(4)|浏览(123)

我有两个音轨,我把它们像这样合并在一起:

AVMutableComposition *composition = [[AVMutableComposition alloc] init];

AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack setPreferredVolume:1.0];
AVAsset *avAsset = [AVURLAsset URLAssetWithURL:originalContentURL options:nil];
AVAssetTrack *clipAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];

AVMutableCompositionTrack *compositionAudioTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack1 setPreferredVolume:0.01];
NSString *soundOne1  =[[NSBundle mainBundle]pathForResource:@"jingle1" ofType:@"m4a"];
NSURL *url1 = [NSURL fileURLWithPath:soundOne1];
AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:url1 options:nil];
AVAssetTrack *clipAudioTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack1 atTime:kCMTimeZero error:nil];

正如你所看到的,第一个AVAsset是第二个轨道的基本长度,这意味着如果我有一个很长的第二个轨道,它将被削减,这正是我想要的方式。
然而,我需要能够循环第二个轨道,以便如果第一个轨道太长,第二个轨道继续下去。我后来必须保存产生的轨道上光盘,这是一个重要的因素以及。
在我做了一项研究之后,我发现在iOS中没有方便的方法来循环播放曲目。其中一种方法是在AVMutableComposition处多次插入第二首曲目,但这对我来说听起来很奇怪。任何基于这个主题的想法都是非常有用的。

b0zn9rqh

b0zn9rqh1#

我认为它应该工作:

CMTime videoDuration = avAsset.duration;
if(CMTimeCompare(videoDuration, audioAsset.duration) == -1){
    [compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack1 atTime:kCMTimeZero error:nil];
}else if(CMTimeCompare(videoDuration, audioAsset.duration) == 1){
     CMTime currentTime = kCMTimeZero;
     while(YES){
           CMTime audioDuration = audioAsset.duration;
           CMTime totalDuration = CMTimeAdd(currentTime,audioDuration);
           if(CMTimeCompare(totalDuration, videoDuration)==1){
              audioDuration = CMTimeSubtract(totalDuration,videoDuration);

           }
           [compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioDuration) ofTrack:clipAudioTrack1 atTime:currentTime error:nil];
           currentTime = CMTimeAdd(currentTime, audioDuration);
           if(CMTimeCompare(currentTime, videoDuration) == 1 || CMTimeCompare(currentTime, videoDuration) == 0){
               break;
           }
     }
}
zaq34kh6

zaq34kh62#

在Gaurav响应中,您应该更改这一行:
audioDuration = CMTimeSubtract(totalDuration,videoDuration);
致:
audioDuration = CMTimeSubtract(videoDuration,currentTime);
否则音轨将长于视频(这将只是黑色)

rkttyhzu

rkttyhzu3#

在Swift中使用repeat whiel循环。

  • 修复视频长度isuue*
let audioLength = CMTime(value: 100, timescale: 1)
let videoLength = CMTime(value: 220, timescale: 1)

func getAudioRepeatInfo(audioLength:CMTime, videoLength:CMTime) -> [(at:CMTime, duration:CMTime)] {
    var at = [(at:CMTime, duration:CMTime)](), start = CMTime.zero
    repeat {
        let info = (at:start, duration: min(CMTimeSubtract(videoLength, start), audioLength) )
        at.append(info)
        start = CMTimeAdd(start, info.duration)
    } while start < videoLength
    return at
}

var ranges =  getAudioRepeatInfo(audioLength: audioLength, videoLength: videoLength)

Playground输出:

[(at: __C.CMTime(value: 0, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0), duration: __C.CMTime(value: 100, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0)),
 (at: __C.CMTime(value: 100, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0), duration: __C.CMTime(value: 100, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0)),
 (at: __C.CMTime(value: 200, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0), duration: __C.CMTime(value: 20, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0))]

用途:

for info in repeatInfo {
    try compositionAudioTrack1?.insertTimeRange(.init(start: .zero, duration: info.duration), of: assetTrack, at: info.at)
}
4szc88ey

4szc88ey4#

Gaurav在Swift 5.5中回答(他的解决方案是正确的,并且运行得很好)。

let videoDuration = avAsset.duration

  if (CMTimeCompare(videoDuration, audioAsset.duration) == -1) {
    // Handle insertTimeRange
  } else if (CMTimeCompare(videoDuration, audioAsset.duration) == 1) {

    var currentTime = CMTime.zero

    while(true) {
      let audioDuration = audioAsset.duration
      let totalDuration = CMTimeAdd(currentTime, audioDuration)

      if (CMTimeCompare(totalDuration, videoDuration) == 1) {
        audioDuration = CMTimeSubtract(videoDuration, currentTime)
      }
  
      // Handle insertTimeRange
  
      currentTime = CMTimeAdd(currentTime, audioDuration)
      if(CMTimeCompare(currentTime, videoDuration) == 1 || CMTimeCompare(currentTime, videoDuration) == 0){
        break
      }
    }
  }

相关问题