Android使用MediaCodec将摄像头采集的视频编码为h264

前端之家收集整理的这篇文章主要介绍了Android使用MediaCodec将摄像头采集的视频编码为h264前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本文实例为大家分享了Android使用MediaCodec将摄像头采集的视频编码为h264,供大家参考,具体内容如下

MainActivity.java

  1. import android.app.Activity;
  2. import android.graphics.ImageFormat;
  3. import android.hardware.Camera;
  4. import android.hardware.Camera.Parameters;
  5. import android.hardware.Camera.PreviewCallback;
  6. import android.os.Bundle;
  7. import android.view.SurfaceHolder;
  8. import android.view.SurfaceView;
  9.  
  10. import java.io.IOException;
  11. import java.util.concurrent.ArrayBlockingQueue;
  12.  
  13. public class MainActivity extends Activity implements SurfaceHolder.Callback,PreviewCallback{
  14.  
  15. private SurfaceView surfaceview;
  16.  
  17. private SurfaceHolder surfaceHolder;
  18.  
  19. private Camera camera;
  20.  
  21. private Parameters parameters;
  22.  
  23. int width = 1280;
  24.  
  25. int height = 720;
  26.  
  27. int framerate = 30;
  28.  
  29. int biterate = 8500*1000;
  30.  
  31. private static int yuvqueuesize = 10;
  32.  
  33. //待解码视频缓冲队列,静态成员!
  34. public static ArrayBlockingQueue<byte[]> YUVQueue = new ArrayBlockingQueue<byte[]>(yuvqueuesize);
  35.  
  36. private AvcEncoder avcCodec;
  37.  
  38. @Override
  39. protected void onCreate(Bundle savedInstanceState) {
  40. super.onCreate(savedInstanceState);
  41. setContentView(R.layout.activity_main);
  42. surfaceview = (SurfaceView)findViewById(R.id.surfaceview);
  43. surfaceHolder = surfaceview.getHolder();
  44. surfaceHolder.addCallback(this);
  45. }
  46.  
  47. @Override
  48. public void surfaceCreated(SurfaceHolder holder) {
  49. camera = getBackCamera();
  50. startcamera(camera);
  51. //创建AvEncoder对象
  52. avcCodec = new AvcEncoder(width,height,framerate,biterate);
  53. //启动编码线程
  54. avcCodec.StartEncoderThread();
  55.  
  56. }
  57.  
  58. @Override
  59. public void surfaceChanged(SurfaceHolder holder,int format,int width,int height) {
  60.  
  61. }
  62.  
  63. @Override
  64. public void surfaceDestroyed(SurfaceHolder holder) {
  65. if (null != camera) {
  66. camera.setPreviewCallback(null);
  67. camera.stopPreview();
  68. camera.release();
  69. camera = null;
  70. avcCodec.StopThread();
  71. }
  72. }
  73.  
  74. @Override
  75. public void onPreviewFrame(byte[] data,android.hardware.Camera camera) {
  76. //将当前帧图像保存在队列中
  77. putYUVData(data,data.length);
  78. }
  79.  
  80. public void putYUVData(byte[] buffer,int length) {
  81. if (YUVQueue.size() >= 10) {
  82. YUVQueue.poll();
  83. }
  84. YUVQueue.add(buffer);
  85. }
  86.  
  87. private void startcamera(Camera mCamera){
  88. if(mCamera != null){
  89. try {
  90. mCamera.setPreviewCallback(this);
  91. mCamera.setDisplayOrientation(90);
  92. if(parameters == null){
  93. parameters = mCamera.getParameters();
  94. }
  95. //获取默认的camera配置
  96. parameters = mCamera.getParameters();
  97. //设置预览格式
  98. parameters.setPreviewFormat(ImageFormat.NV21);
  99. //设置预览图像分辨率
  100. parameters.setPreviewSize(width,height);
  101. //配置camera参数
  102. mCamera.setParameters(parameters);
  103. //将完全初始化的SurfaceHolder传入到setPreviewDisplay(SurfaceHolder)中
  104. //没有surface的话,相机不会开启preview预览
  105. mCamera.setPreviewDisplay(surfaceHolder);
  106. //调用startPreview()用以更新preview的surface,必须要在拍照之前start Preview
  107. mCamera.startPreview();
  108.  
  109. } catch (IOException e) {
  110. e.printStackTrace();
  111. }
  112. }
  113. }
  114.  
  115. private Camera getBackCamera() {
  116. Camera c = null;
  117. try {
  118. //获取Camera的实例
  119. c = Camera.open(0);
  120. } catch (Exception e) {
  121. e.printStackTrace();
  122. }
  123. //获取Camera的实例失败时返回null
  124. return c;
  125. }
  126.  
  127. }

2.AvcEncoder.java

  1. import android.media.MediaCodec;
  2. import android.media.MediaCodecInfo;
  3. import android.media.MediaFormat;
  4. import android.os.Environment;
  5.  
  6. import java.io.BufferedOutputStream;
  7. import java.io.File;
  8. import java.io.FileOutputStream;
  9. import java.io.IOException;
  10. import java.nio.ByteBuffer;
  11.  
  12. import static android.media.MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
  13. import static android.media.MediaCodec.BUFFER_FLAG_KEY_FRAME;
  14.  
  15. public class AvcEncoder
  16. {
  17. private final static String TAG = "MeidaCodec";
  18.  
  19. private int TIMEOUT_USEC = 12000;
  20.  
  21. private MediaCodec mediaCodec;
  22. int m_width;
  23. int m_height;
  24. int m_framerate;
  25.  
  26. public byte[] configbyte;
  27.  
  28. public AvcEncoder(int width,int height,int framerate,int bitrate) {
  29.  
  30. m_width = width;
  31. m_height = height;
  32. m_framerate = framerate;
  33. MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc",width,height);
  34. mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
  35. mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,width*height*5);
  36. mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE,30);
  37. mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,1);
  38. try {
  39. mediaCodec = MediaCodec.createEncoderByType("video/avc");
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. }
  43. //配置编码器参数
  44. mediaCodec.configure(mediaFormat,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
  45. //启动编码器
  46. mediaCodec.start();
  47. //创建保存编码后数据的文件
  48. createfile();
  49. }
  50.  
  51. private static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test1.h264";
  52. private BufferedOutputStream outputStream;
  53.  
  54. private void createfile(){
  55. File file = new File(path);
  56. if(file.exists()){
  57. file.delete();
  58. }
  59. try {
  60. outputStream = new BufferedOutputStream(new FileOutputStream(file));
  61. } catch (Exception e){
  62. e.printStackTrace();
  63. }
  64. }
  65.  
  66. private void StopEncoder() {
  67. try {
  68. mediaCodec.stop();
  69. mediaCodec.release();
  70. } catch (Exception e){
  71. e.printStackTrace();
  72. }
  73. }
  74.  
  75. public boolean isRuning = false;
  76.  
  77. public void StopThread(){
  78. isRuning = false;
  79. try {
  80. StopEncoder();
  81. outputStream.flush();
  82. outputStream.close();
  83. } catch (IOException e) {
  84. e.printStackTrace();
  85. }
  86. }
  87.  
  88. int count = 0;
  89.  
  90. public void StartEncoderThread(){
  91. Thread EncoderThread = new Thread(new Runnable() {
  92.  
  93. @Override
  94. public void run() {
  95. isRuning = true;
  96. byte[] input = null;
  97. long pts = 0;
  98. long generateIndex = 0;
  99.  
  100. while (isRuning) {
  101. //访问MainActivity用来缓冲待解码数据的队列
  102. if (MainActivity.YUVQueue.size() >0){
  103. //从缓冲队列中取出一帧
  104. input = MainActivity.YUVQueue.poll();
  105. byte[] yuv420sp = new byte[m_width*m_height*3/2];
  106. //把待编码的视频帧转换为YUV420格式
  107. NV21ToNV12(input,yuv420sp,m_width,m_height);
  108. input = yuv420sp;
  109. }
  110. if (input != null) {
  111. try {
  112. long startMs = System.currentTimeMillis();
  113. //编码器输入缓冲区
  114. ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
  115. //编码器输出缓冲区
  116. ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
  117. int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
  118. if (inputBufferIndex >= 0) {
  119. pts = computePresentationTime(generateIndex);
  120. ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
  121. inputBuffer.clear();
  122. //把转换后的YUV420格式的视频帧放到编码器输入缓冲区中
  123. inputBuffer.put(input);
  124. mediaCodec.queueInputBuffer(inputBufferIndex,input.length,pts,0);
  125. generateIndex += 1;
  126. }
  127.  
  128. MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
  129. int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,TIMEOUT_USEC);
  130. while (outputBufferIndex >= 0) {
  131. //Log.i("AvcEncoder","Get H264 Buffer Success! flag = "+bufferInfo.flags+",pts = "+bufferInfo.presentationTimeUs+"");
  132. ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
  133. byte[] outData = new byte[bufferInfo.size];
  134. outputBuffer.get(outData);
  135. if(bufferInfo.flags == BUFFER_FLAG_CODEC_CONFIG){
  136. configbyte = new byte[bufferInfo.size];
  137. configbyte = outData;
  138. }else if(bufferInfo.flags == BUFFER_FLAG_KEY_FRAME){
  139. byte[] keyframe = new byte[bufferInfo.size + configbyte.length];
  140. System.arraycopy(configbyte,keyframe,configbyte.length);
  141. //把编码后的视频帧从编码器输出缓冲区中拷贝出来
  142. System.arraycopy(outData,configbyte.length,outData.length);
  143.  
  144. outputStream.write(keyframe,keyframe.length);
  145. }else{
  146. //写到文件
  147. outputStream.write(outData,outData.length);
  148. }
  149.  
  150. mediaCodec.releaSEOutputBuffer(outputBufferIndex,false);
  151. outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,TIMEOUT_USEC);
  152. }
  153.  
  154. } catch (Throwable t) {
  155. t.printStackTrace();
  156. }
  157. } else {
  158. try {
  159. Thread.sleep(500);
  160. } catch (InterruptedException e) {
  161. e.printStackTrace();
  162. }
  163. }
  164. }
  165. }
  166. });
  167. EncoderThread.start();
  168.  
  169. }
  170.  
  171. private void NV21ToNV12(byte[] nv21,byte[] nv12,int height){
  172. if(nv21 == null || nv12 == null)return;
  173. int framesize = width*height;
  174. int i = 0,j = 0;
  175. System.arraycopy(nv21,nv12,framesize);
  176. for(i = 0; i < framesize; i++){
  177. nv12[i] = nv21[i];
  178. }
  179. for (j = 0; j < framesize/2; j+=2)
  180. {
  181. nv12[framesize + j-1] = nv21[j+framesize];
  182. }
  183. for (j = 0; j < framesize/2; j+=2)
  184. {
  185. nv12[framesize + j] = nv21[j+framesize-1];
  186. }
  187. }
  188.  
  189. /**
  190. * Generates the presentation time for frame N,in microseconds.
  191. */
  192. private long computePresentationTime(long frameIndex) {
  193. return 132 + frameIndex * 1000000 / m_framerate;
  194. }
  195. }

3.activity_main.xml

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent" >
  4.  
  5. <SurfaceView
  6. android:id="@+id/surfaceview"
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent"/>
  9.  
  10. </RelativeLayout>

4.添加权限

  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  2. <uses-permission android:name="android.permission.CAMERA" />
  3. <uses-permission android:name="android.permission.INTERNET" />

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

猜你在找的Android相关文章