分享

android硬编码h264

 mediatv 2016-07-20

本人对Android已无大爱,更新太快,就h264编码先后实现了 ffmpeg+x264软编  Mediarecoder提取,还没能稳定的又出了MediaCodec,更新太快。更新快也是好事,说明android生命力旺盛。

既然瞅了几眼,就发出来个测试版本吧。android编码h264, 用udp发送到vlc播放测试。代码上传至:http://download.csdn.net/detail/liuhongxiangm/6772629

上代码:

  1. <span style="font-size:18px;">package com.encode.androidencode;  
  2.   
  3. import java.nio.ByteBuffer;  
  4. import android.annotation.SuppressLint;  
  5. import android.media.MediaCodec;  
  6. import android.media.MediaCodecInfo;  
  7. import android.media.MediaFormat;  
  8. import android.util.Log;  
  9.   
  10.   
  11.   
  12. public class AvcEncoder   
  13. {  
  14.   
  15.     private MediaCodec mediaCodec;  
  16.     int m_width;  
  17.     int m_height;  
  18.     byte[] m_info = null;  
  19.   
  20.   
  21.     private byte[] yuv420 = null;   
  22.     @SuppressLint("NewApi")  
  23.     public AvcEncoder(int width, int height, int framerate, int bitrate) {   
  24.           
  25.         m_width  = width;  
  26.         m_height = height;  
  27.         yuv420 = new byte[width*height*3/2];  
  28.       
  29.         mediaCodec = MediaCodec.createEncoderByType("video/avc");  
  30.         MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);  
  31.         mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);  
  32.         mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);  
  33.         mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);      
  34.         mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); //关键帧间隔时间 单位s  
  35.           
  36.         mediaCodec.configure(mediaFormat, nullnull, MediaCodec.CONFIGURE_FLAG_ENCODE);  
  37.         mediaCodec.start();  
  38.     }  
  39.   
  40.     @SuppressLint("NewApi")  
  41.     public void close() {  
  42.         try {  
  43.             mediaCodec.stop();  
  44.             mediaCodec.release();  
  45.         } catch (Exception e){   
  46.             e.printStackTrace();  
  47.         }  
  48.     }  
  49.   
  50.     @SuppressLint("NewApi")  
  51.     public int offerEncoder(byte[] input, byte[] output)   
  52.     {     
  53.         int pos = 0;  
  54.         swapYV12toI420(input, yuv420, m_width, m_height);  
  55.         try {  
  56.             ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();  
  57.             ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();  
  58.             int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);  
  59.             if (inputBufferIndex >= 0)   
  60.             {  
  61.                 ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];  
  62.                 inputBuffer.clear();  
  63.                 inputBuffer.put(yuv420);  
  64.                 mediaCodec.queueInputBuffer(inputBufferIndex, 0, yuv420.length, 00);  
  65.             }  
  66.   
  67.             MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();  
  68.             int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);  
  69.              
  70.             while (outputBufferIndex >= 0)   
  71.             {  
  72.                 ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];  
  73.                 byte[] outData = new byte[bufferInfo.size];  
  74.                 outputBuffer.get(outData);  
  75.                   
  76.                 if(m_info != null)  
  77.                 {                 
  78.                     System.arraycopy(outData, 0,  output, pos, outData.length);  
  79.                     pos += outData.length;  
  80.                       
  81.                 }  
  82.                   
  83.                 else //保存pps sps 只有开始时 第一个帧里有, 保存起来后面用  
  84.                 {  
  85.                      ByteBuffer spsPpsBuffer = ByteBuffer.wrap(outData);    
  86.                      if (spsPpsBuffer.getInt() == 0x00000001)   
  87.                      {    
  88.                          m_info = new byte[outData.length];  
  89.                          System.arraycopy(outData, 0, m_info, 0, outData.length);  
  90.                      }   
  91.                      else   
  92.                      {    
  93.                             return -1;  
  94.                      }        
  95.                 }  
  96.                   
  97.                 mediaCodec.releaseOutputBuffer(outputBufferIndex, false);  
  98.                 outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);  
  99.             }  
  100.   
  101.             if(output[4] == 0x65//key frame   编码器生成关键帧时只有 00 00 00 01 65 没有pps sps, 要加上  
  102.             {  
  103.                 System.arraycopy(output, 0,  yuv420, 0, pos);  
  104.                 System.arraycopy(m_info, 0,  output, 0, m_info.length);  
  105.                 System.arraycopy(yuv420, 0,  output, m_info.length, pos);  
  106.                 pos += m_info.length;  
  107.             }  
  108.               
  109.         } catch (Throwable t) {  
  110.             t.printStackTrace();  
  111.         }  
  112.   
  113.         return pos;  
  114.     }  
  115.      //yv12 转 yuv420p  yvu -> yuv  
  116.     private void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width, int height)   
  117.     {        
  118.         System.arraycopy(yv12bytes, 0, i420bytes, 0,width*height);  
  119.         System.arraycopy(yv12bytes, width*height+width*height/4, i420bytes, width*height,width*height/4);  
  120.         System.arraycopy(yv12bytes, width*height, i420bytes, width*height+width*height/4,width*height/4);    
  121.     }    
  122.   
  123.       
  124. }  
  125. </span>  


  1. <span style="font-size:18px;">package com.interfaces.androidencode;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.DatagramPacket;  
  5. import java.net.DatagramSocket;  
  6. import java.net.InetAddress;  
  7. import java.net.SocketException;  
  8. import java.net.UnknownHostException;  
  9. import java.util.List;  
  10.   
  11.   
  12. import android.graphics.ImageFormat;  
  13. import android.hardware.Camera;  
  14. import android.hardware.Camera.PreviewCallback;  
  15. import android.os.Bundle;  
  16. import android.os.StrictMode;  
  17. import android.annotation.SuppressLint;  
  18. import android.app.Activity;  
  19. import android.util.Log;  
  20. import android.view.Menu;  
  21. import android.view.SurfaceHolder;  
  22. import android.view.SurfaceHolder.Callback;  
  23. import android.view.SurfaceView;  
  24. import com.encode.androidencode.AvcEncoder;  
  25.   
  26. public class MainActivity extends Activity  
  27. implements SurfaceHolder.Callback, PreviewCallback   
  28. {  
  29.   
  30.     DatagramSocket socket;  
  31.     InetAddress address;  
  32.       
  33.     AvcEncoder avcCodec;  
  34.     public Camera m_camera;    
  35.     SurfaceView   m_prevewview;  
  36.     SurfaceHolder m_surfaceHolder;  
  37.     int width = 1280;  
  38.     int height = 720;  
  39.     int framerate = 20;  
  40.     int bitrate = 2500000;  
  41.       
  42.     byte[] h264 = new byte[width*height*3/2];  
  43.   
  44.     @SuppressLint("NewApi")  
  45.     @Override  
  46.     protected void onCreate(Bundle savedInstanceState) {  
  47.           
  48.         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
  49.         .detectDiskReads()  
  50.         .detectDiskWrites()  
  51.         .detectAll()   // or .detectAll() for all detectable problems  
  52.         .penaltyLog()  
  53.         .build());  
  54. StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()  
  55.         .detectLeakedSqlLiteObjects()  
  56.         .detectLeakedClosableObjects()  
  57.         .penaltyLog()  
  58.         .penaltyDeath()  
  59.         .build());  
  60.           
  61.         super.onCreate(savedInstanceState);  
  62.         setContentView(R.layout.activity_main);  
  63.           
  64.         avcCodec = new AvcEncoder(width,height,framerate,bitrate);  
  65.           
  66.         m_prevewview = (SurfaceView) findViewById(R.id.SurfaceViewPlay);  
  67.         m_surfaceHolder = m_prevewview.getHolder(); // 绑定SurfaceView,取得SurfaceHolder对象  
  68.         m_surfaceHolder.setFixedSize(width, height); // 预览大小設置  
  69.         m_surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  70.         m_surfaceHolder.addCallback((Callback) this);     
  71.           
  72.         try {  
  73.             socket = new DatagramSocket();  
  74.             address = InetAddress.getByName("192.168.12.124");  
  75.         } catch (SocketException e) {  
  76.             // TODO Auto-generated catch block  
  77.             e.printStackTrace();  
  78.         } catch (UnknownHostException e) {  
  79.             // TODO Auto-generated catch block  
  80.             e.printStackTrace();  
  81.         }  
  82.           
  83.     }  
  84.   
  85.     @Override  
  86.     public boolean onCreateOptionsMenu(Menu menu) {  
  87.         // Inflate the menu; this adds items to the action bar if it is present.  
  88.         getMenuInflater().inflate(R.menu.main, menu);  
  89.         return true;  
  90.     }  
  91.     @Override  
  92.     public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)   
  93.     {  
  94.       
  95.     }  
  96.   
  97.     @SuppressLint("NewApi")  
  98.     @SuppressWarnings("deprecation")  
  99.     @Override  
  100.     public void surfaceCreated(SurfaceHolder arg0)   
  101.     {  
  102.         try   
  103.         {  
  104.             m_camera = Camera.open();  
  105.             m_camera.setPreviewDisplay(m_surfaceHolder);  
  106.             Camera.Parameters parameters = m_camera.getParameters();  
  107.             parameters.setPreviewSize(width, height);  
  108.             parameters.setPictureSize(width, height);  
  109.             parameters.setPreviewFormat(ImageFormat.YV12);  
  110.             m_camera.setParameters(parameters);   
  111.             m_camera.setPreviewCallback((PreviewCallback) this);  
  112.             m_camera.startPreview();  
  113.               
  114.         } catch (IOException e)   
  115.         {  
  116.             e.printStackTrace();  
  117.         }     
  118.     }  
  119.   
  120.     @Override  
  121.     public void surfaceDestroyed(SurfaceHolder arg0)   
  122.     {  
  123.         m_camera.setPreviewCallback(null); //!!这个必须在前,不然退出出错  
  124.         m_camera.stopPreview();   
  125.         m_camera.release();  
  126.         m_camera = null;   
  127.         avcCodec.close();  
  128.     }  
  129.   
  130.       
  131.     @Override  
  132.     public void onPreviewFrame(byte[] data, Camera camera)   
  133.     {  
  134.           
  135.         Log.v("h264""h264 start");  
  136.         int ret = avcCodec.offerEncoder(data,h264);  
  137.           
  138.         if(ret > 0)  
  139.         {  
  140.             try {         
  141.                 DatagramPacket packet=new DatagramPacket(h264,ret, address,5000);  
  142.                 socket.send(packet);  
  143.             } catch (IOException e)  
  144.             {  
  145.               
  146.             }  
  147.         }  
  148.         Log.v("h264""h264 end");  
  149.           
  150.     }  
  151.   
  152. }  
  153. </span>  

vlc的设置:设置里面的去复用器设置成H264的就好了,然后打开网络串流:udp://@:5000 就好了


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多