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 加入
我能做的,就是调整好自己的精神状态,以最佳的面貌去面对那些未曾经历过得事情,对生活充满热情和希望。











评论