欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ExoPlayer之Extractor媒体文件解封装使用

程序员文章站 2022-03-08 14:28:03
ExoPlayer之ExtractorExtractor的作用接口说明Extractor的调用内置的Extractors通过extension拓展ExtractorExtractor的作用代码中关于Extractor的注释说明 - Extracts media data from a container format.Extractor对应于媒体文件解封装的处理:解封装的 作用,就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如 MP4,MKV,RMV...



Extractor的作用

代码中关于Extractor的注释说明 - Extracts media data from a container format.
Extractor对应于媒体文件解封装的处理:
解封装的 作用,就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如 MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数 据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。

接口说明

com.google.android.exoplayer2.extractor.Extractor:

public interface Extractor { ... boolean sniff(ExtractorInput input) throws IOException, InterruptedException; void init(ExtractorOutput output); @ReadResult int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException; void seek(long position, long timeUs); void release(); } 

1 boolean sniff(ExtractorInput input)
通过对输入媒体数据流头信息的判断,决策当前Extractor是否能够处理输入的媒体数据。

2 void init(ExtractorOutput output)
初始化,接收输出类,只执行一次。

3 int read(ExtractorInput input, PositionHolder seekPosition)
解析封装格式数据,在seek位置读取数据输出到ExtractorOutput。

4 void seek(long position, long timeUs)
跳转。

Extractor的调用

DefaultExtractorsFactory。
由ProgressiveMediaSource使用。

内置的Extractors

@Override public synchronized Extractor[] createExtractors() { Extractor[] extractors = new Extractor[14]; extractors[0] = new MatroskaExtractor(matroskaFlags); extractors[1] = new FragmentedMp4Extractor(fragmentedMp4Flags); extractors[2] = new Mp4Extractor(mp4Flags); extractors[3] = new Mp3Extractor( mp3Flags | (constantBitrateSeekingEnabled ? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING : 0)); extractors[4] = new AdtsExtractor( adtsFlags | (constantBitrateSeekingEnabled ? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING : 0)); extractors[5] = new Ac3Extractor(); extractors[6] = new TsExtractor(tsMode, tsFlags); extractors[7] = new FlvExtractor(); extractors[8] = new OggExtractor(); extractors[9] = new PsExtractor(); extractors[10] = new WavExtractor(); extractors[11] = new AmrExtractor( amrFlags | (constantBitrateSeekingEnabled ? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING : 0)); extractors[12] = new Ac4Extractor(); if (FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR != null) { try { extractors[13] = FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR.newInstance(); } catch (Exception e) { // Should never happen. throw new IllegalStateException("Unexpected error creating FLAC extractor", e); } } else { extractors[13] = new FlacExtractor(); } return extractors; } 

ExoPlayer内置的Extractors目前有13个,分别是MatroskaExtractor、FragmentedMp4Extractor、Mp4Extractor、Mp3Extractor、AdtsExtractor、Ac3Extractor、TsExtractor、FlvExtractor、OggExtractor、PsExtractor、WavExtractor、AmrExtractor、Ac4Extractor,对应处理mp4、MP3、flv等媒体封装格式

通过extension拓展Extractor

以rmvb为例。Exoplayer框架不支持rmvb媒体封装格式,如果想让exoplayer支持rmvb,需要添加对rmvb媒体封装格式的解析,需要支持rm相关的codec,如rv40等。

/**
 * Facilitates the extraction of data from the real container format.
 */ public final class RmvbExtractor implements Extractor { private final String TAG = RmvbExtractor.class.getSimpleName(); /** Factory that returns one extractor which is a {@link RmvbExtractor}. */ public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new RmvbExtractor()}; private final ParsableByteArray outputBuffer; private @MonotonicNonNull ExtractorOutput extractorOutput; private @MonotonicNonNull TrackOutput trackOutput; private MediaContainerDemuxer mDemuxer; public RmvbExtractor() { outputBuffer = new ParsableByteArray(); mDemuxer = new MediaContainerDemuxer(); } public void setUrl(String url) { mDemuxer.setUrl(url); } @Override public void init(ExtractorOutput output) { extractorOutput = output; trackOutput = extractorOutput.track(0, C.TRACK_TYPE_VIDEO); extractorOutput.endTracks(); mDemuxer.init(output); } @Override public boolean sniff(ExtractorInput input) throws IOException, InterruptedException { final byte[] RM_TAG = {'.', 'R', 'M', 'F'}; byte[] head = new byte[4]; input.peek(head, 0, 4); return Arrays.equals(head, RM_TAG); } @Override public int read(final ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { int rt = mDemuxer.prepare(input); if (rt != 0) return Extractor.RESULT_END_OF_INPUT; return Extractor.RESULT_CONTINUE; } @Override public void seek(long position, long timeUs) { } @Override public void release() { } } 

对应的,在DefaultExtractorsFactory中,需要将Rmvb Extractor添加进去:

private static final Constructor<? extends Extractor> RMVB_EXTENSION_EXTRACTOR_CONSTRUCTOR; static { Constructor<? extends Extractor> flacExtensionExtractorConstructor = null; Constructor<? extends Extractor> rmExtensionExtractorConstructor = null; try { { rmExtensionExtractorConstructor = Class.forName("com.google.android.exoplayer2.ext.ffmpeg.RmvbExtractor") .asSubclass(Extractor.class) .getConstructor(); } } catch (ClassNotFoundException e) { // Expected if the app was built without the FLAC extension. } catch (Exception e) { // The FLAC extension is present, but instantiation failed. throw new RuntimeException("Error instantiating FLAC extension", e); } RMVB_EXTENSION_EXTRACTOR_CONSTRUCTOR = rmExtensionExtractorConstructor; } ... @Override public synchronized Extractor[] createExtractors() { Extractor[] extractors = new Extractor[15]; ... if (RMVB_EXTENSION_EXTRACTOR_CONSTRUCTOR != null) { try { extractors[14] = RMVB_EXTENSION_EXTRACTOR_CONSTRUCTOR.newInstance(); } catch (Exception e) { // Should never happen. throw new IllegalStateException("Unexpected error creating RMVB extractor", e); } } return extractors; } 

本文地址:https://blog.csdn.net/weixin_48649321/article/details/107705068

相关标签: android ffmpeg