【问题标题】:An AAC audio stream is playable in VLC for Android, but not in ExoplayerAAC 音频流可在 VLC for Android 中播放,但不能在 Exoplayer 中播放
【发布时间】:2018-12-16 20:04:42
【问题描述】:

我有一个 RTMP 流,我想使用 Exoplayer 库在我的应用中播放。我的设置如下:

TrackSelector trackSelector = new DefaultTrackSelector();
RtmpDataSourceFactory rtmpDataSourceFactory = new RtmpDataSourceFactory(bandwidthMeter);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
factory = new ExtractorMediaSource.Factory(rtmpDataSourceFactory);
factory.setExtractorsFactory(extractorsFactory);
createSource();

mPlayer = ExoPlayerFactory.newSimpleInstance(mActivity, trackSelector, new DefaultLoadControl(
        new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
        1000,  // min buffer
        3000, // max buffer
        1000, // playback
        2000,   //playback after rebuffer
        DefaultLoadControl.DEFAULT_TARGET_BUFFER_BYTES,
        true
));
vwExoPlayer.setPlayer(mPlayer);
mPlayer.addListener(mVideoStreamHandler);
mPlayer.addVideoListener(new VideoListener() {
    @Override
    public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
        Log.d("hasil", "onVideoSizeChanged: w:" + width + ", h:" + height);
        String res = width + "x" + height;
        resolution.setText(res);
    }
    @Override
    public void onRenderedFirstFrame() {
    }
});

其中createSource()如下:

private void createSource() {
    mMediaSource180 = factory.createMediaSource(Uri.parse(API.GAME_VIDEO_STREAM_URL_180));
    mMediaSource360 = factory.createMediaSource(Uri.parse(API.GAME_VIDEO_STREAM_URL_360));
    mMediaSource720 = factory.createMediaSource(Uri.parse(API.GAME_VIDEO_STREAM_URL_720));
    mMediaSourceAudio = factory.createMediaSource(Uri.parse(API.GAME_AUDIO_STREAM_URL));
}

我目前的问题是只有前三个ExtractorMediaSources 在Exoplayer 中工作正常。 mMediaSourceAudio 拒绝在 Exoplayer 中播放,但在 Android 的 VLC 媒体播放器中运行良好。

现在我怀疑格式是 AAC-LTP,或者需要 VLC 中可用的编解码器但默认 Android 中没有的任何 AAC 变体。但是,我无权访问编码过程,所以我不确定。

如果不是这样,那是什么?

编辑:

我一直在调试BandwidthMeter 并添加了MediaSourceEventListener。当我使用普通视频源时,onDownstreamFormatChanged() 会被调用,但在我使用音频流源时不会。

此外,BandwidthMeter 工作正常,总是在流的所有部分下载字节,当视频流进入时会下载更多字节,但仅在音频流中,当我调用 mPlayer.getBufferedPosition() 时,返回值始终为 0。此外,当我使用音频流源时,没有调用 OMX 代码 - 没有设置解码器。

我是否看到格式错误的音频流,或者我需要更改我的 Exoplayer 的设置?

编辑 2:

进一步调试发现,在所有视频流和音频流中,都使用了相同的FlvExtractor。即使视频流具有avc 视频轨道编码和mp4a-latm 音频轨道编码。这正常吗?

【问题讨论】:

    标签: android vlc exoplayer


    【解决方案1】:

    原来是因为流被识别为有两个轨道/sampleQueues。一个音频轨道和一个 null 格式的轨道。该空轨道应该是视频轨道,根据流的flvHeader 标志应该存在。

    现在,我通过使用自定义 MediaPeriod 创建自定义 MediaSource 来解决这个问题。说自定义MediaPeriod 有代码来分离SampleQueues 的视频和音频轨道,然后在我想播放纯音频流时使用纯音频SampleQueue[] 而不是源SampleQueue[]

    虽然这给了我另一个关注点:可以做些什么来改变 rtmp 流中的“有音轨 (flag & 0x04) 和视频轨道 (flag & 0x01)”标志,对吗?

    【讨论】:

      【解决方案2】:

      感谢 cmets,我是 ExoPlayer 的新手。但是您的 cmets 帮助我调试并解决了该问题。

      我尝试使用自定义 MediaSource 和自定义 MediaPeriod 来解决此音频问题。我已经观察到视频格式数据在视频+音频 wowza 流的情况下出现在音频数据之后,因此函数 mayeFinishPrepare() 将在调用 onPrepared 之前等待获取视频和音频格式标签数据,以防首先收到视频标签数据。如果先收到音频数据,它不会等待,会调用 onPrepare()。

      通过上述更改,我能够单独播放音频和 video_audio wowza 流,其中带有 tagTypes 的 rtmp tagHeader 按视频 tagData 的顺序出现,然后是音频数据。

      我无法使用与 srs 服务器相同的补丁来播放具有相同更改的 audio_only 和 video_audio 流。 srs 服务器按音频然后视频 tagData 的顺序给出 tagData,

      所以,我在 FlvExtractor 中进一步调试。在 readFlvHeader 中,我已经覆盖了 hasAudio 和 hasVideo 变量。这些变量将根据前几个 tagHeaders(5 或 6)设置。我在一个循环中对输入使用了 6 次 peekFully。在获取tagType和tagDataSize后的每个循环中,tagDataSize用于input.advancePeekPosition(),tagType用于识别tagData中是否有音视频格式数据。在查看了前 6 个连续的 tagHeaders 之后,我能够得到 hasAudio 和 hasVideo 的实际值,而忽略了用于设置这些变量的 flvHeaders.flags。

      自定义 FlvExtractor 解决方法,看起来比自定义 MediaSource/MediaPeriod 更干净,因为我们将根据需要创建许多轨道,因为我们正在设置正确的 hasVideo/hasAudio 值。

      【讨论】:

        猜你喜欢
        • 2020-02-29
        • 2023-03-23
        • 2017-02-18
        • 1970-01-01
        • 1970-01-01
        • 2011-08-18
        • 1970-01-01
        • 2014-01-29
        • 1970-01-01
        相关资源
        最近更新 更多