iOS: аудио- и видеосигнал от Airplay
Я сделал видеоплеер, который анализирует аудио и видео треки в реальном времени из видео, которое воспроизводится в данный момент. Видео хранятся на устройстве iOS (в каталоге документов приложений).
Это все отлично работает. Я использую MTAudioProcessingTap для получения всех аудиосэмплов и выполнения некоторых БПФ, и я анализирую видео, просто копируя пиксельные буферы из текущего воспроизводимого CMTime (свойство currentTime AVPlayer). Как я уже сказал, это прекрасно работает.
Но сейчас я хочу поддержать Airplay. Просто трансляция сама по себе не сложна, но мои краны перестают работать, как только Airplay переключается и видео воспроизводится на ATV. Каким-то образом MTAudioProcessingTap не будет обрабатываться, и все пиксельные буферы пусты... Я не могу получить данные.
Есть ли способ добраться до этих данных?
Чтобы получить пиксельные буферы, я просто запускаю событие каждые несколько миллисекунд и извлекаю currentTime игрока. Затем:
CVPixelBufferRef imageBuffer = [videoOutput copyPixelBufferForItemTime:time itemTimeForDisplay:nil];
CVPixelBufferLockBaseAddress(imageBuffer,0);
uint8_t *tempAddress = (uint8_t *) CVPixelBufferGetBaseAddress(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
куда tempAddress
мой пиксельный буфер, и videoOutput
это пример AVPlayerItemVideoOutput
,
Для аудио я использую:
AVMutableAudioMixInputParameters *inputParams = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:audioTrack];
// Create a processing tap for the input parameters
MTAudioProcessingTapCallbacks callbacks;
callbacks.version = kMTAudioProcessingTapCallbacksVersion_0;
callbacks.clientInfo = (__bridge void *)(self);
callbacks.init = init;
callbacks.prepare = prepare;
callbacks.process = process;
callbacks.unprepare = unprepare;
callbacks.finalize = finalize;
MTAudioProcessingTapRef tap;
OSStatus err = MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks,
kMTAudioProcessingTapCreationFlag_PostEffects, &tap);
if (err || !tap) {
NSLog(@"Unable to create the Audio Processing Tap");
return;
}
inputParams.audioTapProcessor = tap;
// Create a new AVAudioMix and assign it to our AVPlayerItem
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
audioMix.inputParameters = @[inputParams];
playerItem.audioMix = audioMix;
С уважением, Ниек
1 ответ
К сожалению, по моему опыту, невозможно получить информацию об аудио / видео во время Airplay, так как воспроизведение выполняется на Apple TV, поэтому на устройстве iOS нет никакой информации.
У меня была та же проблема с получением данных субтитров SMPTE из timedMetaData
, который перестает получать сообщения во время Airplay.
Вот решение:
это для реализации AirPlay, я использую этот код только для аудио в моем приложении, я не знаю, можете ли вы улучшить видео, но вы можете попробовать;)
На AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[RADStyle applyStyle];
[radiosound superclass];
[self downloadZip];
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
А если вы используете airplay в nice для реализации элементов управления LockScreen, ArtWork, Stop/play, Title ecc.
В DetailViewController вашего игрока используйте этот код:
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString: (self.saved)[@"image"]]];
if (imageData == nil){
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"lockScreen.png"]];
infoCenter.nowPlayingInfo = @{MPMediaItemPropertyTitle: saved[@"web"],MPMediaItemPropertyArtist: saved[@"title"], MPMediaItemPropertyArtwork:albumArt};
} else {
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageWithData:imageData]];
infoCenter.nowPlayingInfo = @{MPMediaItemPropertyTitle: saved[@"link"],MPMediaItemPropertyArtist: saved[@"title"], MPMediaItemPropertyArtwork:albumArt};
}
}
Надеюсь, этот код поможет вам;)