Android硬件编码

来源:互联网 发布:minecraftpe凡家物语js 编辑:程序博客网 时间:2024/06/14 18:40

Android设备用AudioRecord采集的实时音频可以不需要编码在网络中直接传输,而对于摄像头采集的实时视频数据最好通过编码后再进行网络传输,下面的代码主要采用MediaCodec进行硬件编码视频数据。编码时,针对具体设备需要设置相对应的参数

 

activity_main.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <Button        android:id="@+id/text_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"     android:text="hello world"        />    <SurfaceView        android:id="@+id/surfaceView"        android:layout_width="352dp"        android:layout_gravity="center"        android:layout_height="288dp" />    <SurfaceView        android:id="@+id/surfaceView1"        android:layout_width="352dp"        android:layout_gravity="center"        android:layout_height="288dp" /></LinearLayout> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.RECORD_AUDIO" />     <uses-permission android:name="android.permission.CAMERA" />    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>    <uses-permission android:name="android.permission.WAKE_LOCK"/> package com.xtxk.camerademon; import android.annotation.SuppressLint;import android.app.Activity;import android.content.pm.ActivityInfo;import android.graphics.ImageFormat;import android.hardware.Camera;import android.hardware.Camera.PreviewCallback;import android.os.Bundle;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceHolder.Callback;import android.view.SurfaceView;import android.view.View;import android.view.View.OnClickListener;import android.view.Window;import android.view.WindowManager;import android.widget.Button;  public class MainActivity extends Activity { private SurfaceView surfaceView;private Camera camera;private SurfaceHolder surfaceHolder;private Camera.Parameters mParameters = null;@SuppressLint("InlinedApi")private int mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;//不同手机有不同的匹配颜色private int width = 352;private int height = 288;private int mFrameRate = 20;private int bitrate = 2500000;byte[] h264 = new byte[width*height*3/2];private AvcEncode avcEncode;private Button button; int a = 1;    @SuppressWarnings("deprecation")@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,        WindowManager.LayoutParams.FLAG_FULLSCREEN);        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);        setContentView(R.layout.activity_main);                button = (Button) findViewById(R.id.text_name);        FileOperator.createFile(FileOperator.fileName);        avcEncode = new AvcEncode(width, height, mFrameRate, bitrate);        surfaceView = (SurfaceView) findViewById(R.id.surfaceView);        surfaceHolder = surfaceView.getHolder();        surfaceHolder.setFixedSize(width, height);        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        surfaceHolder.addCallback(new SurfaceCallback());                button.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){// TODO 自动生成的方法存根camera.startPreview();}});    }            private final class SurfaceCallback implements Callback, PreviewCallback{ @SuppressLint("NewApi") @Overridepublic void surfaceCreated(SurfaceHolder holder){// TODO 自动生成的方法存根try {if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {                camera = Camera.open();            } else {                camera = Camera.open(mCameraId);            }                camera.setPreviewDisplay(surfaceHolder);                //camera.setDisplayOrientation(90);                mParameters = camera.getParameters();                mParameters.setPreviewSize(width, height);                mParameters.setPictureSize(width, height);                //此处颜色设置与后面要匹配 否则颜色会出现变化                mParameters.setPreviewFormat(ImageFormat.YV12);                camera.setParameters(mParameters);                camera.setPreviewCallback(this);                //camera.startPreview();                                            } catch (Exception e)            {                Log.e("TEST", "setPreviewDisplay fail " + e.getMessage());            }} @Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height){// TODO 自动生成的方法存根} @Overridepublic void surfaceDestroyed(SurfaceHolder holder){// TODO 自动生成的方法存根camera.setPreviewCallback(null);camera.stopPreview();camera.release();camera = null;avcEncode.close();} @Overridepublic void onPreviewFrame(byte[] data, Camera camera){// TODO 自动生成的方法存根//System.out.println("--------------onPreviewFrame-----------------------");//h264 = avcEncode.offerEncode(data, h264);h264 = avcEncode.offerEncode(data, h264);//保存成.h264文件,将每一帧数据追加写在一个文件里面FileOperator.addToFile(h264, FileOperator.fileName);}    }} package com.xtxk.camerademon; import java.nio.ByteBuffer; import android.annotation.SuppressLint;import android.annotation.TargetApi;import android.media.CamcorderProfile;import android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaFormat;import android.os.Build; @SuppressLint("NewApi")public class AvcEncode{private MediaCodec mediaCodec;private int width;private int height;byte[] m_info = null;private byte[] yuv420 = null;protected byte[] pps;    protected byte[] sps;@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @SuppressLint("NewApi")public AvcEncode(int width, int height, int framerate, int bitrate){this.width = width;this.height = height;yuv420 = new byte[width*height*3/2];mediaCodec = MediaCodec.createEncoderByType("video/avc");  MediaFormat mediaFormat = null;if(CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)){mediaFormat = MediaFormat.createVideoFormat("video/avc", 352, 288);}else{mediaFormat = MediaFormat.createVideoFormat("video/avc", 352, 288);}mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 700000);  mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 10);  //根据手机设置不同的颜色参数mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);      //mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar);mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);   mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);  mediaCodec.start();}public void close(){try{mediaCodec.stop();mediaCodec.release();}catch (Exception e){// TODO 自动生成的 catch 块e.printStackTrace();}}long mCount = 0;public byte[] offerEncode(byte[] input, byte[] output){int pos = 0;  swapYV12toI420(input, yuv420, width, height);  try {  ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();  ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers(); int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);   if (inputBufferIndex >= 0)   {  ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];  inputBuffer.clear();  inputBuffer.put(yuv420);  mediaCodec.queueInputBuffer(inputBufferIndex, 0, yuv420.length, 0, 0);  }MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();   int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,10000);   while (outputBufferIndex >= 0)   {  ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];  byte[] outData = new byte[bufferInfo.size];  outputBuffer.get(outData); if(m_info != null)  {                 System.arraycopy(outData, 0,  output, pos, outData.length);  pos += outData.length;  /*System.out.println("里面");for(int i = 0; i < output.length; i++){System.out.println(output[i]+" ");}*/}else{ByteBuffer spsPpsBuffer = ByteBuffer.wrap(outData);    if (spsPpsBuffer.getInt() == 0x00000001)   {    m_info = new byte[outData.length];  System.arraycopy(outData, 0, m_info, 0, outData.length);  }     }mediaCodec.releaseOutputBuffer(outputBufferIndex, false);  outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);  }if(output[4] == 0x65){System.arraycopy(output,0,yuv420,0,pos);System.arraycopy(m_info,0,output,0,m_info.length);System.arraycopy(yuv420,0,output,m_info.length,pos);pos += m_info.length;} }catch (Throwable t) {  t.printStackTrace();  }  return output;}private void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width, int height)   {        System.arraycopy(yv12bytes,0,i420bytes,0,width*height);System.arraycopy(yv12bytes, width*height+width*height/4, i420bytes, width*height,width*height/4);  System.arraycopy(yv12bytes, width*height, i420bytes, width*height+width*height/4,width*height/4);    }public byte[] CompressBuffer(byte[] yuvBuff, byte[] h264Buff){int pos = 0;  //swapYV12toI420(yuvBuff, yuv420);  try {  ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();  ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers(); int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);   if (inputBufferIndex >= 0)   {  ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];  inputBuffer.clear();  inputBuffer.put(yuvBuff);  mediaCodec.queueInputBuffer(inputBufferIndex, 0, yuv420.length, mCount *1000/10,0);  mCount++;}MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();   int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,10000);   while (outputBufferIndex >= 0)   {  ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];  byte[] outData = new byte[bufferInfo.size];  outputBuffer.get(outData); if(m_info != null)  {                 System.arraycopy(outData, 0,  h264Buff, pos, outData.length);  pos += outData.length;  }else{ByteBuffer spsPpsBuffer = ByteBuffer.wrap(outData);    if (spsPpsBuffer.getInt() == 0x00000001)   {    m_info = new byte[outData.length];  System.arraycopy(outData, 0, m_info, 0, outData.length);  }      }mediaCodec.releaseOutputBuffer(outputBufferIndex, false);  outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);  }if(h264Buff[4] == 0x65){System.arraycopy(h264Buff,0,yuv420,0,pos);System.arraycopy(m_info,0,h264Buff,0,m_info.length);System.arraycopy(yuv420,0,h264Buff,m_info.length,pos);pos += m_info.length;}}catch (Throwable t) {  t.printStackTrace();  }  return h264Buff;} } package com.xtxk.camerademon; import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException; import android.os.Environment; public class FileOperator{//public static String fileName = getSDPath()+ "/" + "chenhan.h264";public static String fileName = "/data/data/com.xtxk.camerademon/chenhan.h264";public static void addToFile(byte[] content, String file){BufferedOutputStream out = null;try{out = new BufferedOutputStream(new FileOutputStream(file, true));out.write(content);}catch (Exception e){// TODO 自动生成的 catch 块e.printStackTrace();}finally{try{out.close();}catch (Exception e){// TODO 自动生成的 catch 块e.printStackTrace();}}}public static String getSDPath(){File sdDir = null;boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);if(sdCardExist){sdDir = Environment.getExternalStorageDirectory();}return sdDir.toString();}public static void createFile(String fileName){File file = new File(fileName);System.out.println("文件路径1:" + fileName + file.exists());if(file.exists()){file.delete();}try{file.createNewFile();}catch (IOException e){// TODO 自动生成的 catch 块e.printStackTrace();}System.out.println("文件路径2:" + fileName);}}
需要相对应的解码播放器才能打开该文件,本人用的是ffmpeg

0 0