写点什么

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
用户头像

Changing Lin

关注

获得机遇的手段远超于固有常规之上~ 2020.04.29 加入

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

评论

发布
暂无评论
ExoPlayer 重写 OpusReader思路