奥特 發表於 2019-8-19 16:56:00

Android开发 多媒体提取器MediaExtractor详解_入门篇

<h1><span style="background-color: rgba(255, 255, 255, 1); color: rgba(0, 128, 128, 1)">版权声明</span></h1>
<p>本文来自博客园,作者:观心静&nbsp;,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/11378133.html</p>
<div>本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。</div>
<h1><span style="background-color: rgba(255, 255, 255, 1); color: rgba(0, 128, 128, 1)">前言</span></h1>
<p>  MediaExtractor字面意思是多媒体提取器,它在Android的音视频开发里主要负责提取视频或者音频中的信息和数据流(例如将视频文件,剥离出音频与视频).本章博客将讲解一些入门简单的东西.如何分别音频和视频轨道和获取视频里的一些信息.我将在其他章节里讲解其他MediaExtractor使用方法.</p>
<p>&nbsp;</p>
<h1><span style="color: rgba(0, 128, 128, 1)">获取轨道</span></h1>
<p><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">  在一个多媒体视频里,可以包含多个数据流(一般是视频与音频各一个,但是音频可以多个).<strong>我们需要先获取需要的数据轨道编号,才能后续的各种操作.所以使用MediaExtractor的第一步就是获取轨道</strong>.<span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">如下代码展示了获取轨道的方法.</span></span></span><br></span></p>
<h2><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)"><span style="color: rgba(0, 0, 0, 1)">列举所有轨道编码格式的Demo方法</span></span></span></span></h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> trackDemo(){
      mFile </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> File(getExternalCacheDir(),"demo.mp4"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">mFile.exists()){
            Log.e(TAG, </span>"mp4文件不存在"<span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
      }
      MediaExtractor extractor </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> MediaExtractor();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实例一个MediaExtractor</span>
      <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            extractor.setDataSource(mFile.getAbsolutePath());</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置添加MP4文件路径</span>
      } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
            e.printStackTrace();
      }
      </span><span style="color: rgba(0, 0, 255, 1)">int</span> count = extractor.getTrackCount();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取轨道数量</span>
      Log.e(TAG, "轨道数量 = "+<span style="color: rgba(0, 0, 0, 1)">count);
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; count; i++<span style="color: rgba(0, 0, 0, 1)">){
            MediaFormat mediaFormat </span>= extractor.getTrackFormat(0<span style="color: rgba(0, 0, 0, 1)">);
            Log.e(TAG, i</span>+"编号通道格式 = "+<span style="color: rgba(0, 0, 0, 1)">mediaFormat.getString(MediaFormat.KEY_MIME));
      }

    }</span></pre>
</div>
<p>上面的代码已经注释的很清楚了.<strong>注意! 实际项目里建议将这些操作放到线程中.</strong></p>
<p>结果:</p>
<div class="cnblogs_code">
<pre>2019-08-19 17:08:21.197 18775-18775/demo.yt.com.demo E/测试Demo: 轨道数量 = 2
2019-08-19 17:08:21.198 18775-18775/demo.yt.com.demo E/测试Demo: 0编号通道格式 = video/<span style="color: rgba(0, 0, 0, 1)">avc
</span>2019-08-19 17:08:21.198 18775-18775/demo.yt.com.demo E/测试Demo: 1编号通道格式 = audio/mp4a-latm</pre>
</div>
<p>从结果可以看到,这个demo.mp4视频文件有2个轨道数量,一个是视频流的轨道,一个是音频流的轨道.</p>
<h2>通过编码格式字符串对比获取指定轨道的方法</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Integer getTrackIndex(String targetTrack) {
      MediaExtractor extractor </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> MediaExtractor();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实例一个MediaExtractor</span>
      <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            extractor.setDataSource(mFile.getAbsolutePath());</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置添加MP4文件路径</span>
      } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
            e.printStackTrace();
      }
      Integer trackIndex </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">int</span> count = extractor.getTrackCount();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取轨道数量</span>
      <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; count; i++<span style="color: rgba(0, 0, 0, 1)">) {
            MediaFormat mediaFormat </span>=<span style="color: rgba(0, 0, 0, 1)"> extractor.getTrackFormat(i);
            String currentTrack </span>=<span style="color: rgba(0, 0, 0, 1)"> mediaFormat.getString(MediaFormat.KEY_MIME);
            </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (currentTrack.startsWith(targetTrack)) {
                trackIndex </span>=<span style="color: rgba(0, 0, 0, 1)"> i;
                </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
            }
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> trackIndex;

    }</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> @Override
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onCreate(Bundle savedInstanceState) {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCreate(savedInstanceState);
      setContentView(R.layout.activity_media_extractor);
      mFile </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> File(getExternalCacheDir(), "demo.mp4"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">int</span> index = getTrackIndex("video/"<span style="color: rgba(0, 0, 0, 1)">);
      Log.e(TAG, </span>"onCreate: index = " +<span style="color: rgba(0, 0, 0, 1)"> index);

    }</span></pre>
</div>
<p>&nbsp;</p>
<h1><span style="color: rgba(0, 128, 128, 1)">提取视频数据信息</span></h1>
<h3><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1)">从MediaFormat里获取数据信息</span></h3>
<p><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1)">  在上面的获取轨道的代码里我们,可以看到使用<span style="color: rgba(0, 0, 0, 1)">MediaFormat可以</span>获取当前轨道的编码格式.除了获取编码格式我们还能获取到很多其他信息.这里我们将会一一列出,但是视频里的一些数据是肯定可以获取到的,而一些其他数据是需要看视频是否携带这些这些数据,如果未携带操作获取这些数据会抛出空指针错误.</span></p>
<h3><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1)">  基本可以获取到的信息</span></h3>
<p><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1)">  1.获取MIME信息,上面也有已经演示过了</span></p>
<div class="cnblogs_code">
<pre>MediaFormat mediaFormat = extractor.getTrackFormat(0);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取多媒体格式,因为是demo已经确定自己的视频文件没问题,所以直接获取0位轨道</span>
String mimeFormat = mediaFormat.getString(MediaFormat.KEY_MIME);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取MIME格式内容</span>
Log.e(TAG, "mediaExtractor: 获取MIME格式内容="+mimeFormat);</pre>
</div>
<p>  2.获取语言格式(大多数情况是获取到空的字符串,但是至少不会报null)</p>
<div class="cnblogs_code">
<pre>MediaFormat mediaFormat = extractor.getTrackFormat(0);
String language = mediaFormat.getString(MediaFormat.KEY_LANGUAGE);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取语言格式内容</span>
Log.e(TAG, "mediaExtractor: 获取语言格式内容="+language);</pre>
</div>
<p>&nbsp;  3.视频的高度与宽度</p>
<div class="cnblogs_code">
<pre>MediaFormat mediaFormat = extractor.getTrackFormat(0<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">int</span> width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取高度</span>
<span style="color: rgba(0, 0, 255, 1)">int</span> height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取高度</span></pre>
</div>
<p>  4.播放总时长</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">long</span> durationTime = mediaFormat.getLong(MediaFormat.KEY_DURATION);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">总时间</span></pre>
</div>
<p>  5.获取MediaFormat描述的数据缓冲区的最大字节数的键</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> maxByteCount = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取视频缓存输出的最大大小</span></pre>
</div>
<p>  </p>
<h3>不确定可以获取到的信息</h3>
<p>  1.获取采样率</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取采样率</span></pre>
</div>
<p>  2.获取比特率</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> bitRate = mediaFormat.getInteger(MediaFormat.KEY_BIT_RATE);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取比特</span></pre>
</div>
<p>  3.获取声道数量</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取声道数量</span></pre>
</div>
<p>  4.获取最大高度与最大宽度</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> maxWidth = mediaFormat.getInteger(MediaFormat.KEY_MAX_WIDTH);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">最大宽度</span>
<span style="color: rgba(0, 0, 255, 1)">int</span> maxHeight = mediaFormat.getInteger(MediaFormat.KEY_MAX_HEIGHT);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">最大高度</span></pre>
</div>
<p>  5.获取颜色格式</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> colorFormat = mediaFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">颜色格式</span></pre>
</div>
<p>  6.获取帧率</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">帧率</span></pre>
</div>
<p>  7.获取图块的高度与宽度</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> tileWidth = mediaFormat.getInteger(MediaFormat.KEY_TILE_WIDTH);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">图块分辨率</span>
<span style="color: rgba(0, 0, 255, 1)">int</span> tileHeight = mediaFormat.getInteger(MediaFormat.KEY_TILE_HEIGHT);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">图块分辨率</span></pre>
</div>
<p>  8.获取网格行</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> gridRows = mediaFormat.getInteger(MediaFormat.KEY_GRID_ROWS);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">网格行</span></pre>
</div>
<p>  9.获取网格列</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> gridColumns = mediaFormat.getInteger(MediaFormat.KEY_GRID_COLUMNS);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">网格列</span></pre>
</div>
<p>  10.<span style="color: rgba(0, 0, 0, 1)">PCM-编码 模拟信号编码</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> pcmEncoding = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">PCM-编码 模拟信号编码</span></pre>
</div>
<p>  11.捕获率</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">float</span> captureRate = mediaFormat.getFloat(MediaFormat.KEY_CAPTURE_RATE);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">捕获率</span></pre>
</div>
<p>  12.是否是AAS</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> isAdts = mediaFormat.getInteger(MediaFormat.KEY_IS_ADTS);</pre>
</div>
<p>&nbsp;</p>
<h1><span style="color: rgba(0, 128, 128, 1)">API列表</span></h1>
<div>
<ul>
<li>setDataSource(String path):即可以设置本地文件又可以设置网络文件</li>
<li class="_mce_tagged_br">getTrackCount():得到源文件通道数</li>
<li class="_mce_tagged_br">getTrackFormat(int index):获取指定(index)的通道格式</li>
<li class="_mce_tagged_br">getSampleTime():返回当前的时间戳</li>
<li class="_mce_tagged_br">readSampleData(ByteBuffer byteBuf, int offset):把指定通道中的数据按偏移量读取到ByteBuffer中;</li>
<li class="_mce_tagged_br">advance():读取下一帧数据</li>
<li class="_mce_tagged_br">release(): 读取结束后释放资源</li>
</ul>
</div>
<div>&nbsp;</div>
<div>end</div>

</div>
<div id="MySignature" role="contentinfo">
    <div style="text-align: center">
    <p style="color:orange;font-size:16px;" >本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/11378133.html </p>
    <div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/11378133.html
頁: [1]
查看完整版本: Android开发 多媒体提取器MediaExtractor详解_入门篇