我有一个要使用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
音频轨道编码。这正常吗?
答案 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值。