Firefly开源社区

打印 上一主题 下一主题

【基础+代码流】在JAVA下利用MEDIACODEC进行硬解码

493

积分

6

威望

0

贡献

技术达人

Rank: 2

积分
493
QQ

【基础+代码流】在JAVA下利用MEDIACODEC进行硬解码

发表于 2016-10-12 17:06:17      浏览:8705 | 回复:6        打印      只看该作者   [复制链接] 楼主
  1. /****************************************************
  2. /*        利用原生SURFACE和MEDIACODEC进行本地文件播放和流媒体播放
  3. /*
  4. /*
  5. *****************************************************/

  6. package com.timestech.xplayer;

  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.nio.ByteBuffer;

  10. import android.annotation.SuppressLint;
  11. import android.app.Activity;
  12. import android.content.pm.ActivityInfo;
  13. import android.media.AudioManager;
  14. import android.media.MediaCodec;
  15. import android.media.MediaCodec.BufferInfo;
  16. import android.media.MediaExtractor;
  17. import android.media.MediaFormat;
  18. import android.net.Uri;
  19. import android.os.Bundle;
  20. import android.util.Log;
  21. import android.view.Surface;
  22. import android.view.SurfaceHolder;
  23. import android.view.SurfaceView;
  24. import android.view.View;
  25. import android.view.Window;
  26. import android.view.WindowManager;
  27. import android.view.WindowManager.LayoutParams;

  28. public class MainActivity extends Activity implements SurfaceHolder.Callback {
  29.         private SurfaceView xSurface = null;
  30.         private PlayerThread xPlayer = null;
  31.         private TsRecv tR = null;
  32.        
  33.         private static final String videoUrl = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
  34.         private static final String videoLocalUrl = "http://192.168.1.179:60000";
  35.         private static final String videoPath = "/mnt/sdcard/Movies/std_p.ts";
  36.        
  37.         @SuppressLint("SdCardPath")
  38.         @Override
  39.         protected void onCreate(Bundle savedInstanceState) {
  40.                 super.onCreate(savedInstanceState);
  41.                 //隐藏标题栏
  42.                 this.requestWindowFeature(Window.FEATURE_NO_TITLE);
  43.                 //沉浸模式
  44.                 getWindow().getDecorView().setSystemUiVisibility(
  45.                                                                                                                 View.SYSTEM_UI_FLAG_FULLSCREEN |
  46.                                                                                                                 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
  47.                                                                                                                 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
  48.                 // 设置横屏 禁止翻转
  49.                 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  50.                
  51.                 // 禁止休眠
  52.                 getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
  53.                                 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  54.                
  55.                 setContentView(R.layout.activity_main);

  56.                 //----------------------------------------surfaceView播放视频----------------------------------------//
  57.                 xSurface = (SurfaceView)findViewById(R.id.surfaceView);
  58.         
  59.         /*
  60.                 LayoutParams lp = (LayoutParams) xSurface.getLayoutParams();        //导致闪退
  61.                 lp.width = 1280;
  62.                 lp.height = 647;
  63.                 xSurface.setLayoutParams(lp);
  64.                 */
  65.             
  66.             SurfaceHolder surfaceHolder = xSurface.getHolder(); //SurfaceHolder是SurfaceView的控制接口
  67.             surfaceHolder.addCallback(this); //因为这个类实现了SurfaceHolder.Callback接口,所以回调参数直接this
  68.                 //surfaceHolder.setFixedSize(1280, 720); //显示的分辨率,不是surface的大小,不设置为视频默认
  69.         }

  70.         private class PlayerThread extends Thread {
  71.                 private MediaExtractor extractor;
  72.                 private MediaCodec decoder;
  73.                 private Surface surface;
  74.                 private boolean DEMUX_ANDROID = false;
  75.                 public PlayerThread(Surface surface) {
  76.                         this.surface = surface;
  77.                 }
  78.                
  79.                 @Override
  80.                 public void run() {
  81.                         if(DEMUX_ANDROID)
  82.                         {
  83.                                 ////////////////////MediaExtractor
  84.                                 extractor = new MediaExtractor();
  85.                                 try {
  86.                                         extractor.setDataSource(videoPath);
  87.                                 } catch (IOException e1) {
  88.                                         // TODO Auto-generated catch block
  89.                                         e1.printStackTrace();
  90.                                 }
  91.                        
  92.                                 for (int i = 0; i < extractor.getTrackCount(); i++) {
  93.                                         MediaFormat format = extractor.getTrackFormat(i);
  94.                                         String mime = format.getString(MediaFormat.KEY_MIME);
  95.                                         if (mime.startsWith("video/")) {
  96.                                                 extractor.selectTrack(i);
  97.                                                 decoder = MediaCodec.createDecoderByType(mime);
  98.                                                 decoder.configure(format, surface, null, 0);
  99.                                                 break;
  100.                                         }
  101.                                 }
  102.                         }
  103.                         else
  104.                         {
  105.                                 tR = new TsRecv();
  106.                                 tR.start(videoLocalUrl, 0);
  107.                                
  108.                                 MediaFormat format;
  109.                                 format = MediaFormat.createVideoFormat("video/avc", 1280, 720);
  110.                                 String mime = format.getString(MediaFormat.KEY_MIME);
  111.                                 decoder = MediaCodec.createDecoderByType(mime);
  112.                                 decoder.configure(format, surface, null, 0);
  113.                         }
  114.                        
  115.                         if (decoder == null) {
  116.                                 Log.e("DecodeActivity", "Can't find video info!");
  117.                                 return;
  118.                         }

  119.                         decoder.start();
  120.                        
  121.                         ByteBuffer[] inputBuffers = decoder.getInputBuffers();
  122.                         ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
  123.                         BufferInfo info = new BufferInfo();
  124.                         long startMs = System.currentTimeMillis();
  125.                         int sampleSize = 0;
  126.                         boolean isEOS = false;

  127.                         while (true) {
  128.                                 //if (!isEOS)
  129.                                 {
  130.                                         int inIndex = decoder.dequeueInputBuffer(10000);
  131.                                         if (inIndex >= 0) {
  132.                                                 ByteBuffer buffer = inputBuffers[inIndex];
  133.                                                
  134.                                                 if(DEMUX_ANDROID)
  135.                                                 {
  136.                                                         ////////////////////MediaExtractor
  137.                                                         sampleSize = extractor.readSampleData(buffer, 0);
  138.                                                         if (sampleSize < 0) {
  139.                                                                 // We shouldn't stop the playback at this point, just pass the EOS
  140.                                                                 // flag to decoder, we will get it again from the
  141.                                                                 // dequeueOutputBuffer
  142.                                                                 Log.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM");
  143.                                                                 decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
  144.                                                                 isEOS = true;
  145.                                                         } else {
  146.                                                                 ///////////////////   MediaExtractor
  147.                                                                 //Log.d("SAMPLESIZE", "SIZE["+sampleSize+"]");
  148.                                                                 long timeus = extractor.getSampleTime();
  149.                                                                 //Log.d("TIMESUS", "extractor.getSampleTime() is "+timeus);
  150.                                                                 decoder.queueInputBuffer(inIndex, 0, sampleSize, timeus, 0);
  151.                                                                 extractor.advance();
  152.                                                         }
  153.                                                 }
  154.                                                 else
  155.                                                 {
  156.                                                         sampleSize = tR.readSampleData(buffer);
  157.                                                        
  158.                                                         if (sampleSize <= 0) {
  159.                                                                 // We shouldn't stop the playback at this point, just pass the EOS
  160.                                                                 // flag to decoder, we will get it again from the
  161.                                                                 // dequeueOutputBuffer
  162.                                                                 Log.d("DecodeActivity", "###########################InputBuffer BUFFER_FLAG_END_OF_STREAM");
  163.                                                                 //decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
  164.                                                         } else {
  165.                                                                 //Log.d("SAMPLESIZE", "SIZE["+sampleSize+"]");
  166.                                                                 decoder.queueInputBuffer(inIndex, 0, sampleSize, 0, 0);
  167.                                                                 //Log.d("DecodeActivity", "sampleSize   "+sampleSize);
  168.                                                         }
  169.                                                 }
  170.                                         }
  171.                                         else
  172.                                                 continue;
  173.                                 }
  174.                                
  175.                                 int outIndex = decoder.dequeueOutputBuffer(info, 0);
  176.                                 //Log.d("SAMPLESIZE", "OUTINDEX["+outIndex+"]");
  177.                                 switch (outIndex) {
  178.                                 case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
  179.                                         //Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");
  180.                                         //outputBuffers = decoder.getOutputBuffers();
  181.                                         break;
  182.                                 case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
  183.                                         //Log.d("DecodeActivity", "New format " + decoder.getOutputFormat());
  184.                                         break;
  185.                                 case MediaCodec.INFO_TRY_AGAIN_LATER:
  186.                                         //Log.d("DecodeActivity", "dequeueOutputBuffer timed out!");
  187.                                         break;
  188.                                 default:
  189.                                         if(DEMUX_ANDROID)
  190.                                         {
  191.                                                 ////////////////////MediaExtractor
  192.                                                 ByteBuffer buffer = outputBuffers[outIndex];
  193.                                                 //Log.v("DecodeActivity", "We can't use this buffer but render it due to the API limit, " + buffer);
  194.        
  195.                                                 // We use a very simple clock to keep the video FPS, or the video
  196.                                                 // playback will be too fast
  197.                                                
  198.                                                 //Log.v("DecodeActivity", "info.presentationTimeUs is  " + info.presentationTimeUs/1000 + " currTimeMilli is " + System.currentTimeMillis() + " startMs is " + startMs);
  199.                                                 while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
  200.                                                         try {
  201.                                                                 sleep(12);
  202.                                                         } catch (InterruptedException e) {
  203.                                                                 e.printStackTrace();
  204.                                                                 break;
  205.                                                         }
  206.                                                 }
  207.                                         }
  208.                                         else
  209.                                         {
  210.                                                 try {
  211.                                                         sleep(30);
  212.                                                 } catch (InterruptedException e) {
  213.                                                         // TODO Auto-generated catch block
  214.                                                         e.printStackTrace();
  215.                                                 }
  216.                                         }
  217.                                         decoder.releaseOutputBuffer(outIndex, true);
  218.                                         break;
  219.                                 }
  220.                                
  221.                                 // All decoded frames have been rendered, we can stop playing now
  222.                                
  223.                                 if(DEMUX_ANDROID)
  224.                                 {
  225.                                         ////////////////////MediaExtractor
  226.                                         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
  227.                                                 Log.d("DecodeActivity", "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
  228.                                                 break;
  229.                                         }
  230.                                 }
  231.                                 else
  232.                                 {
  233.                                        

  234.                                        
  235.                                 }
  236.                         }
  237.                        
  238.                         Log.d("PlayerThread:", "OVER.......................................");
  239.                        
  240.                         if(DEMUX_ANDROID)
  241.                         {
  242.                                 ////////////////////MediaExtractor
  243.                                 decoder.stop();
  244.                                 decoder.release();
  245.                                 extractor.release();
  246.                         }
  247.                         return ;
  248.                 }
  249.         }
  250.        
  251.         public void surfaceCreated(SurfaceHolder holder) {
  252.                 if (xPlayer == null) {
  253.                         xPlayer = new PlayerThread(holder.getSurface());
  254.                         xPlayer.start();
  255.                 }
  256.         }

  257.         @Override
  258.         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  259.                 // TODO Auto-generated method stub
  260.         }

  261.         @Override
  262.         public void surfaceDestroyed(SurfaceHolder holder) {
  263.                 // TODO Auto-generated method stub
  264.                
  265.         }
  266.        
  267.     protected void onDestroy() {
  268.             tR.stop();
  269.         super.onDestroy();
  270.     }
  271. }
复制代码
回复

使用道具 举报

53

积分

0

威望

0

贡献

技术小白

积分
53
发表于 2016-11-30 16:10:35        只看该作者  沙发
这个强大了,楼主大大能否开源项目代码呢?
TsRecv这个类是怎样操作的呢?
回复

使用道具 举报

154

积分

0

威望

0

贡献

技术小白

积分
154
发表于 2016-11-30 20:15:34        只看该作者  板凳
参考下实现思路
回复

使用道具 举报

493

积分

6

威望

0

贡献

技术达人

Rank: 2

积分
493
QQ
发表于 2016-12-15 09:51:57        只看该作者  地板
huntengan 发表于 2016-11-30 16:10
这个强大了,楼主大大能否开源项目代码呢?
TsRecv这个类是怎样操作的呢?

TsRecv是自己写的针对TS流的接收,解复用,封装,打包库,是在JNI下用C实现的
回复

使用道具 举报

493

积分

6

威望

0

贡献

技术达人

Rank: 2

积分
493
QQ
发表于 2016-12-15 09:52:50        只看该作者  5#
jingjin221 发表于 2016-12-15 09:51
TsRecv是自己写的针对TS流的接收,解复用,封装,打包库,是在JNI下用C实现的

你可以用FFMEPG的解复用库,支持的格式更多
回复

使用道具 举报

18

积分

0

威望

0

贡献

游客

积分
18
发表于 2017-1-13 15:37:27        只看该作者  6#
回复

使用道具 举报

132

积分

0

威望

0

贡献

技术小白

积分
132
发表于 2018-3-15 11:16:32        只看该作者  7#
请教一下,怎么从MediaCodec获取解码后的帧呢?
我是使用的decoder.configure中的surface使用null,然后在dequeueOutputBuffer后使用decoder.getOutputBuffers()或者getOutputImage()得到的bytebuffer都是空的position都为0。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

友情链接 : 爱板网 电子发烧友论坛 云汉电子社区 粤ICP备14022046号-2
快速回复 返回顶部 返回列表