AAC音频流可以在Android的VLC中播放,但不能在Exoplayer中播放

时间:2018-07-09 07:48:11

标签: android vlc exoplayer

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

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));
}

我当前的问题是,ExtractorMediaSource中只有前三个Exoplayer可以正常工作。 mMediaSourceAudio拒绝在Exoplayer中播放,但在适用于Android的VLC Media Player中可以正常工作。

现在,我怀疑该格式是AAC-LTP,还是需要VLC中提供编解码器的任何AAC变体,但默认Android中没有。但是,我无法访问编码过程,因此我不确定。

如果不是这种情况,那是什么?

编辑:

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

此外,BandwidthMeter可以正常工作,总是在流的所有部分下载字节,而当视频流进入时则下载更多字节,但是当我调用{{1 }},返回值始终为0。此外,当我使用音频流源时,没有调用OMX代码-没有设置解码器。

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

编辑2:

进一步的调试显示,在所有视频流和音频流中,都使用相同的mPlayer.getBufferedPosition()。即使视频流具有FlvExtractor视频轨道编码和avc音频轨道编码。这正常吗?

2 个答案:

答案 0 :(得分:0)

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

现在,我通过使用自定义MediaSource创建自定义MediaPeriod来解决此问题。所述自定义MediaPeriod具有将SampleQueue的视频和音频轨道分开的代码,然后在我想播放时使用纯音频SampleQueue[]代替源SampleQueue[]纯音频流。

尽管这给我带来了另一个关注点:可以做一些事情来更改rtmp流中的“具有音频轨道(flag & 0x04)和视频轨道(flag & 0x01)标志,对吗?

答案 1 :(得分:0)

感谢您的评论,我是ExoPlayer的新手。但是您的评论帮助我进行了调试,并获得了解决该问题的多种解决方法。

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

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

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

因此,我在FlvExtractor中进行了进一步调试。在readFlvHeader中,我重写了hasAudio和hasVideo变量。这些变量将基于前几个tagHeaders(5或6)进行设置。我在循环中对输入使用peekFully 6次。在获取tagType和tagDataSize之后的每个循环中,将tagDataSize用于input.advancePeekPosition(),并使用tagType来标识我们在tagData中是否具有音频/视频格式数据。偷看了前6个连续的tagHeaders之后,我能够获取hasAudio和hasVideo的实际值,而忽略了用于设置这些变量的flvHeaders.flags。

自定义FlvExtractor解决方法看上去比自定义MediaSource / MediaPeriod干净,因为我们将根据需要创建那么多轨道,因为我们正在设置适当的hasVideo / hasAudio值。