当前位置: 首页 > 知识库问答 >
问题:

从AVPlayer获取HLS的PCM数据

施俊哲
2023-03-14

这个问题在过去几年里似乎被问了几次,但都没有答案。我正在尝试处理来自HLS的PCM数据,我必须使用AVPlayer。

这篇文章点击了本地文件https://chritto.wordpress.com/2013/01/07/processing-avplayers-audio-with-mtaudioprocessingtap/

此水龙头适用于远程文件,但不适用于. m3u8 hls文件。http://venodesigns.net/2014/01/08/recording-live-audio-streams-on-ios/

我可以播放播放列表中的前两首曲目,但它不会启动获取pcm所需的回调,当文件是本地或远程(不是流)时,我仍然可以获取pcm,但它是hls不工作,我需要HLS工作

这是我的代码

//avplayer tap try
- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL*testUrl= [NSURL URLWithString:@"http://playlists.ihrhls.com/c5/1469/playlist.m3u8"];

    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:testUrl];
    self.player = [AVPlayer playerWithPlayerItem:item];

    // Watch the status property - when this is good to go, we can access the
    // underlying AVAssetTrack we need.
    [item addObserver:self forKeyPath:@"status" options:0 context:nil];

}

-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
    if(![keyPath isEqualToString:@"status"])
        return;

    AVPlayerItem *item = (AVPlayerItem *)object;
    if(item.status != AVPlayerItemStatusReadyToPlay)
        return;

    NSArray *tracks = [self.player.currentItem tracks];
    for(AVPlayerItemTrack *track in tracks) {
        if([track.assetTrack.mediaType isEqualToString:AVMediaTypeAudio]) {
            NSLog(@"GOT DAT FUCKER");
            [self beginRecordingAudioFromTrack:track.assetTrack];
            [self.player play];
        }
    }
}

- (void)beginRecordingAudioFromTrack:(AVAssetTrack *)audioTrack
{
    // Configure an MTAudioProcessingTap to handle things.
    MTAudioProcessingTapRef tap;
    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;

    OSStatus err = MTAudioProcessingTapCreate(
                                              kCFAllocatorDefault,
                                              &callbacks,
                                              kMTAudioProcessingTapCreationFlag_PostEffects,
                                              &tap
                                              );

    if(err) {
        NSLog(@"Unable to create the Audio Processing Tap %d", (int)err);
        return;
    }

    // Create an AudioMix and assign it to our currently playing "item", which
    // is just the stream itself.
    AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
    AVMutableAudioMixInputParameters *inputParams = [AVMutableAudioMixInputParameters
                                                     audioMixInputParametersWithTrack:audioTrack];

    inputParams.audioTapProcessor = tap;
    audioMix.inputParameters = @[inputParams];
    self.player.currentItem.audioMix = audioMix;
}

void process(MTAudioProcessingTapRef tap, CMItemCount numberFrames,
             MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut,
             CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut)
{
    OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut,
                                                      flagsOut, NULL, numberFramesOut);
    if (err) NSLog(@"Error from GetSourceAudio: %d", (int)err);

    NSLog(@"Process");

}

void init(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut)
{
    NSLog(@"Initialising the Audio Tap Processor");
    *tapStorageOut = clientInfo;
}

void finalize(MTAudioProcessingTapRef tap)
{
    NSLog(@"Finalizing the Audio Tap Processor");
}

void prepare(MTAudioProcessingTapRef tap, CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat)
{
    NSLog(@"Preparing the Audio Tap Processor");
}

void unprepare(MTAudioProcessingTapRef tap)
{
    NSLog(@"Unpreparing the Audio Tap Processor");
}

void init被称为void prepare,也必须调用process

我该怎么做?

共有2个答案

融宏伟
2023-03-14

我建议使用奴佛卡因

在iOS和Mac OS X中,使用音频单元实现真正快速的音频是很困难的,这会让你伤痕累累、血肉模糊。过去需要几天的时间,现在只需几行代码就可以完成。

经兴安
2023-03-14

我建议您使用FFMPEG库来处理HLS流。这有点难,但提供了更多的灵活性。几年前,我为Android制作了HLS Player(使用了这个项目),我相信这同样适用于iOS。

 类似资料:
  • 我们正在尝试使用从HLS流中捕获的PCM数据进行处理,最好是在播放之前,尽管之后是可以接受的。我们希望在仍然使用AVPlayer的情况下完成所有这些工作。 有人这样做过吗?对于非HLS流以及本地文件,这似乎可以通过MPAudioProcessingTap实现,但不能通过HLS实现。本期讨论如何使用非HLS:AVFoundation音频处理,使用AVPlayer的MTAudioProcessingT

  • 我正在尝试从苹果示例直播流URL播放HLS流。 我在信息中添加了ATS异常。plist。 当AVPlayer开始准备播放应用程序崩溃时。以下例外。

  • 我正在使用作为使用HTTP实时流的无线电应用程序。现在我想为该音频流实现一个电平表。最好是一个显示不同频率的电平表,但是一个简单的左/右解决方案将是一个很好的起点。 我发现了几个使用AVAudioPlayer的示例。但是我无法找到从AVPlayer获取所需信息的解决方案。 有人能想出解决我问题的办法吗? 编辑我想创建这样的东西(但更好) 编辑二 一个建议是使用MTAudioProcessingTa

  • AVPlayer 是一个基于ffmpeg、libtorrent的P2P播放器实现。 一直以来, 在多媒体播放器这块, 即使目前有许多开源的播放器项目, 但要写一个播放器仍然是件非常困难的事, 如果在windows上你有可能需要熟悉DShow, 另外的话, 你需要学习一堆开源项目(比如FFmpeg, MPC, VLC, Mplayer), 而且多数都是基于linux, 在windows上学习起来很不

  • 问题内容: 日志,为什么? 问题答案: 为了详细说明@Raynos所说的内容,您定义的函数是一个异步回调。它不会立即执行,而是在文件加载完成后执行。当您调用readFile时,将立即返回控件并执行下一行代码。因此,当您调用console.log时,尚未调用您的回调,并且尚未设置此内容。欢迎使用异步编程。 示例方法 或者更好的是,如Raynos的示例所示,将您的调用包装在一个函数中并传递您自己的回调

  • 我一直在尝试使用nativescript创建一个android应用程序。我正在使用fetch模块从服务器获取响应。当我试图从httpbin获得响应时。org/get,没关系。但当我试图从本地服务器获取响应时,网络请求失败。错误 发送到httpbin。组织/获取- 发送到本地主机:8000/api- 当我尝试从纯节点中的localhost:8000/api获取响应时。js通过请求模块。它工作得很好。