ExoPlayer 重写 OpusReader 思路
作者:Changing Lin
- 2021 年 12 月 17 日
本文字数:1947 字
阅读完需:约 6 分钟
1.需求
使用 ExoPlayer 来播放远程的 TS 在线文件
由于特殊的原因导致,客户端的音频编码采用 opus,这也导致了流媒体服务存储的录音文件的音频编码也是 opus。我们测试过多种 PC 端播放器,PotPlayer 和 VLC、MediaPlayer,仅有 VLC 可以正常播放和解码,而 PotPlayer 只能渲染视频画面,无法播放声音。
2.分析
我们的思路是,在 ExoPlayer 的 TsExtractor 中加入 opus 解码的支持,重写一个 OpusReader 来实现对在线 TS 文件的音频解码。
PlayerActivity.onCreate->
DemoUtil.getDataSourceFactory->
DemoUtil.getHttpDataSourceFactory->
CronetDataSource.Factory->CronetEngineWrapper->
com.google.android.exoplayer2.upstream.DefaultDataSource#open->
DefaultMediaSourceFactory
SimpleExoPlayer->MediaSourceFactory->DefaultMediaSourceFactory
->CronetDataSource->
->DefaultExtractorsFactory->FileTypes.TS->TsExtractor
复制代码
3.源码
DefaultTsPayloadReaderFactory.java
@Override
@Nullable
public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) {
Log.e("cclin", String.format("createPayloadReader: 0x%x-%s-%s", streamType, esInfo.streamType, esInfo.language));
switch (streamType) {
case TsExtractor.TS_STREAM_TYPE_MPA:
case TsExtractor.TS_STREAM_TYPE_MPA_LSF:
return new PesReader(new MpegAudioReader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_AAC_ADTS:
return isSet(FLAG_IGNORE_AAC_STREAM)
? null : new PesReader(new AdtsReader(false, esInfo.language));
case TsExtractor.TS_STREAM_TYPE_AAC_LATM:
return isSet(FLAG_IGNORE_AAC_STREAM)
? null : new PesReader(new LatmReader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_AC3:
case TsExtractor.TS_STREAM_TYPE_E_AC3:
return new PesReader(new Ac3Reader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_AC4:
return new PesReader(new Ac4Reader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_HDMV_DTS:
if (!isSet(FLAG_ENABLE_HDMV_DTS_AUDIO_STREAMS)) {
return null;
}
// Fall through.
case TsExtractor.TS_STREAM_TYPE_DTS:
return new PesReader(new DtsReader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_H262:
return new PesReader(new H262Reader(buildUserDataReader(esInfo)));
case TsExtractor.TS_STREAM_TYPE_H263:
return new PesReader(new H263Reader(buildUserDataReader(esInfo)));
case TsExtractor.TS_STREAM_TYPE_H264:
return isSet(FLAG_IGNORE_H264_STREAM) ? null
: new PesReader(new H264Reader(buildSeiReader(esInfo),
isSet(FLAG_ALLOW_NON_IDR_KEYFRAMES), isSet(FLAG_DETECT_ACCESS_UNITS)));
case TsExtractor.TS_STREAM_TYPE_H265:
return new PesReader(new H265Reader(buildSeiReader(esInfo)));
case TsExtractor.TS_STREAM_TYPE_SPLICE_INFO:
return isSet(FLAG_IGNORE_SPLICE_INFO_STREAM)
? null
: new SectionReader(new PassthroughSectionPayloadReader(MimeTypes.APPLICATION_SCTE35));
case TsExtractor.TS_STREAM_TYPE_ID3:
return new PesReader(new Id3Reader());
case TsExtractor.TS_STREAM_TYPE_DVBSUBS:
return new PesReader(
new DvbSubtitleReader(esInfo.dvbSubtitleInfos));
case TsExtractor.TS_STREAM_TYPE_AIT:
return new SectionReader(new PassthroughSectionPayloadReader(MimeTypes.APPLICATION_AIT));
case 6:
return new PesReader(new OpusReader());
default:
return null;
}
}
复制代码
OpusReader.java
public class OpusReader implements ElementaryStreamReader {
private static final String TAG = "OpusReader";
@Override
public void seek() {
}
@Override
public void createTracks(ExtractorOutput extractorOutput,
PesReader.TrackIdGenerator idGenerator) {
}
@Override
public void packetStarted(long pesTimeUs, int flags) {
}
@Override
public void consume(ParsableByteArray data) throws ParserException {
}
@Override
public void packetFinished() {
}
}
复制代码
基础框架已经搭建好了,未完待续
划线
评论
复制
发布于: 1 小时前阅读数: 4
版权声明: 本文为 InfoQ 作者【Changing Lin】的原创文章。
原文链接:【http://xie.infoq.cn/article/f86e367996c0b673d31b68402】。文章转载请联系作者。
Changing Lin
关注
获得机遇的手段远超于固有常规之上~ 2020.04.29 加入
我能做的,就是调整好自己的精神状态,以最佳的面貌去面对那些未曾经历过得事情,对生活充满热情和希望。
评论