我有一个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));
}
我目前的问题是只有前三个 ExtractorMediaSource
在 Exoplayer
中正常工作 . mMediaSourceAudio
拒绝在 Exoplayer
中播放,但在适用于Android的VLC媒体播放器中工作得很好 .
现在我怀疑格式是AAC-LTP,或者需要VLC中可用编解码器而不是默认Android中的编解码器的任何AAC变体 . 但是,我无法访问编码过程,所以我不确定 .
如果不是这样,那是什么?
编辑:
我一直在调试 BandwidthMeter
并添加了 MediaSourceEventListener
. 当我使用普通视频源时,会调用 onDownstreamFormatChanged()
,但在使用该音频流源时则不会 .
此外, BandwidthMeter
工作正常,在视频流进入时,字节总是在流的所有部分下载,更多字节,但仅在仅音频流中,当我调用 mPlayer.getBufferedPosition()
时,返回的值始终为0 . ,当我使用音频流源时,没有调用OMX代码 - 没有设置解码器 .
我看到格式错误的音频流,还是需要更改Exoplayer的设置?
编辑2:
进一步调试显示,在所有视频流和音频流中,使用相同的 FlvExtractor
. 即使视频流具有 avc
视频轨道编码和 mp4a-latm
音频轨道编码 . 这是正常的吗?
2 回答
事实证明这是因为流被识别为有两个轨道/
sampleQueue
. 一个音频轨道和一个空格式轨道 . 该空轨道应该是视频轨道,根据流的flvHeader
标志应该存在 .现在,我通过使用自定义
MediaPeriod
创建自定义MediaSource
来解决这个问题 . 所述自定义MediaPeriod
具有分隔SampleQueue
的视频和音频轨道的代码,然后当我想播放仅音频流时使用仅音频SampleQueue[]
而不是源SampleQueue[]
.虽然这给了我另一个值得关注的问题:在rtmp流中有's something one can do to alter the '有音轨(
flag & 0x04
)和视频轨道(flag & 0x01
)'标志,对吧?感谢您的评论,我是ExoPlayer的新手 . 但是您的评论帮助我调试并获得了多个问题的解决方法 .
我尝试使用自定义MediaSource和自定义MediaPeriod来解决此音频问题 . 我观察到视频格式数据出现在视频音频流的音频数据之后,因此函数maybeFinishPrepare()将在调用onPrepared之前等待获取视频和音频格式标签数据,如果首先接收到视频tagData . 首先接收到的音频数据,它不会等待并将调用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值 .