我尝试使用AVMutableComposition在精确的时间播放一系列声音文件。
当视图加载时,我创建合成,目的是在1秒内均匀间隔播放4种声音。不管声音有多长或多短都不重要,我只想在0,0.25,0.5和0.75秒内发射声音:
AVMutableComposition *composition = [[AVMutableComposition alloc] init];
NSDictionary *options = @{AVURLAssetPreferPreciseDurationAndTimingKey : @YES};
for (NSInteger i = 0; i < 4; i++)
{
AVMutableCompositionTrack* track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
NSURL *url = [[NSBundle mainBundle] URLForResource:[NSString stringWithFormat:@"sound_file_%i", i] withExtension:@"caf"];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:options];
AVAssetTrack *assetTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;
CMTimeRange timeRange = [assetTrack timeRange];
Float64 t = i * 0.25;
NSError *error;
BOOL success = [track insertTimeRange:timeRange ofTrack:assetTrack atTime:CMTimeMakeWithSeconds(t, 1) error:&error];
if (!success)
{
NSLog(@"unsuccesful creation of composition");
}
if (error)
{
NSLog(@"composition creation error: %@", error);
}
}
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithAsset:composition];
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];
成功创建,没有错误。后来,当我想播放序列时,我这样做:
[self.avPlayer seekToTime:CMTimeMakeWithSeconds(0, 1)];
[self.avPlayer play];
出于某种原因,声音根本没有均匀分布 - 但几乎全部播放。我尝试了相同的东西,间隔超过4秒,取代了这样的时间计算:
Float64 t = i * 1.0;
这完美无缺。任何1秒以下的时间间隔似乎都会产生意外结果。我错过了什么? AVCompositions不应该用于1秒以下的时间间隔吗?或者我可能误解了时间间隔?
答案 0 :(得分:2)
您的CMTimeMakeWithSeconds(t, 1)
完全是第二个&#39;切片&#39;因为你的时间刻度设置为1.无论分数t
是多少,atTime:总是最终为0.这就是为什么当你将它增加到1秒(t = i * 1)时它会起作用。 / p>
您需要将时间刻度设置为4以获得所需的0.25秒切片。由于CMTime现在是0.25秒切片,因此您不需要进行i * 0.25计算。只需直接使用i
; atTime:CMTimeMake(i, 4)
如果您将来可能需要更精确,那么您应该立即考虑它,以便您以后不必调整代码。 Apple建议使用600的时间刻度,因为它是普通视频帧速率的倍数(24,25和30 FPS),但它也适用于仅音频。因此,对于您的情况,您将使用24个切片来获得.25秒的值; Float64 t = i * 24
; atTime:CMTimeMake(t, 600)
关于你几乎同时播放所有4种声音的问题,请注意this unanswered SO question只会在第一次播放时发生。即使有上述变化,您仍可能遇到此问题。
答案 1 :(得分:1)
除非每个曲目正好是0.25秒,否则这就是你的问题:
Float64 t = i * 0.25;
NSError *error;
BOOL success = [track insertTimeRange:timeRange ofTrack:assetTrack atTime:CMTimeMakeWithSeconds(t, 1) error:&error];
您需要跟踪到目前为止添加的累积时间范围,并在此时插入下一首曲目:
CMTime currentTime = kCMTimeZero;
for (NSInteger i = 0; i < 4; i++) {
/* Code to create track for insertion */
CMTimeRange trackTimeRange = [assetTrack timeRange];
BOOL success = [track insertTimeRange:trackTimeRange
ofTrack:assetTrack
atTime:currentTime
error:&error];
/* Error checking code */
//Update time range for insertion
currentTime = CMTimeAdd(currentTime,trackTimeRange.duration);
}
答案 2 :(得分:0)
我改变了你的代码,抱歉我没时间测试它。
AVMutableComposition *composition = [AVMutableComposition composition];
NSDictionary *options = @{AVURLAssetPreferPreciseDurationAndTimingKey : @YES};
CMTime totalDuration = kCMTimeZero;
for (NSInteger i = 0; i < 4; i++)
{
AVMutableCompositionTrack* track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Record_%i", i] ofType:@"caf"]];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:options];
AVAssetTrack *assetTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
CMTimeRange timeRange = [assetTrack timeRange];
NSError *error;
BOOL success = [track insertTimeRange:timeRange ofTrack:assetTrack atTime:CMTIME_COMPARE_INLINE(totalDuration, >, kCMTimeZero)? CMTimeAdd(totalDuration, CMTimeMake(1, 4)): totalDuration error:&error];
if (!success)
{
NSLog(@"unsuccesful creation of composition");
}
if (error)
{
NSLog(@"composition creation error: %@", error);
}
totalDuration = CMTimeAdd(CMTimeAdd(totalDuration,CMTimeMake(1, 4)), asset.duration);
}
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithAsset:composition];
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];
P.S。使用kCMTimeZero
代替CMTimeMakeWithSeconds(0, 1)
。