android 5.0 mediacodec demo

来源:互联网 发布:苏联经济数据 编辑:程序博客网 时间:2024/05/15 17:08

最近在高通8974A android5.0 平台调试mediacodec硬件编解码,发现之前在android 4.1上可以用的代码报错不能用了。经过分析和网上搜索解决了,现贴出来。

demo的功能就是显示camera 的预览图像,从camera回调里拿到yuv数据,然后送给mediacodec编码,输出的编码数据给到mediacodec解码,解码后的图像

显示出来。


package com.example.mediacodectest;


import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.WindowManager;




import java.io.IOException;


import java.nio.ByteBuffer;


import java.util.Iterator;


import java.util.LinkedList;


import java.util.List;


import java.util.Queue;


import android.graphics.ImageFormat;
import android.graphics.PixelFormat;


import android.hardware.Camera;


import android.hardware.Camera.Parameters;


import android.hardware.Camera.Size;


import android.media.MediaCodec;
import android.media.MediaCodecList;


import android.media.MediaCodecInfo;


import android.media.MediaFormat;


import android.util.Log;


import android.view.SurfaceHolder;


import android.view.SurfaceView;


import android.view.View;


import android.view.View.OnClickListener;


import android.widget.Button;


public class MainActivity extends Activity implements OnClickListener {


/** Called when the activity is first created. */
    private SurfaceView CamSurfaceView = null;  
    private SurfaceHolder CamSurfaceHolder = null;
    private SurfaceView DecSurfaceView = null; 
    private SurfaceHolder DecSurfaceHolder = null;
    private String TAG = "MediaCodecTestActivity";
    private Camera camera ;
    private int cameraId = 1;
    private int width = 640;
    private int height = 480;
    private int fps = 25;
    private int bitrate = 1024000;
    private int m_nPacksPutIn = 0;


    private int runstate=0;
    private Queue<byte[]> encqueue=null;
    private Queue<byte[]> decqueue=null;


    private String videoformat263= "video/3gpp";
    private String videoformatvp8= "video/x-vnd.on2.vp8";
    private String videoformat264= "video/avc";
    private final  long kTimeOutUs = -1;//5000;
//private MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
 
    //true:use queue ,two thread encode and decode
    //false:one thread encode and decode
    private boolean rmode = true;


    @Override
    protected void onCreate(Bundle savedInstanceState){


    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        Button btnStartDec = (Button)findViewById(R.id.start);
        Button btnStopDec = (Button)findViewById(R.id.stop); 
        CamSurfaceView =(SurfaceView) this.findViewById(R.id.cameraview);
        DecSurfaceView =(SurfaceView) this.findViewById(R.id.decodeview);
        Log.d(TAG,"init surfaceview ,cam:"+CamSurfaceView+"  dec:"+DecSurfaceView);
        CamSurfaceHolder = CamSurfaceView.getHolder(); 
        CamSurfaceHolder.addCallback(new CamSufaceListener()); 
        CamSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
CamSurfaceView.setVisibility(View.VISIBLE);
DecSurfaceHolder = DecSurfaceView.getHolder();  
DecSurfaceHolder.addCallback(new DecSufaceListener());  
DecSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
        DecSurfaceView.setVisibility(View.VISIBLE);
btnStartDec.setOnClickListener(this);
        btnStopDec.setOnClickListener(this);
        encqueue = new LinkedList<byte[]>();  
        decqueue = new LinkedList<byte[]>();                  


    }


    /*


    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {  


    int key = event.getKeyCode(); 
    int keyaction = event.getAction();


    //Log.i(TAG, "[test] dispatchKeyEvent  event = " + event);  


    if (key == KeyEvent.KEYCODE_BACK ) { 
        Log.i(TAG, " catch BACK event!! keyaction: "+keyaction); 
        return true;  
    }  
    
    if (key == KeyEvent.KEYCODE_MENU) { 
        Log.i(TAG, " catch MENU event!! return true! ");  
        return true;  
    } 


    return super.dispatchKeyEvent(event);  


}
    @Override  
    public void onAttachedToWindow()  
    {  
      // TODO Auto-generated method stub  
      this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);     
      super.onAttachedToWindow();  
    } 
    
    public boolean onKeyUp(int keyCode, KeyEvent event)  
    {  
         switch(keyCode)  
         {  
            case KeyEvent.KEYCODE_MENU:  
                Log.d(TAG,"MENU key up test!");  
                break;  
            case KeyEvent.KEYCODE_BACK:  
                Log.d(TAG,"BACK key up test!");  
                break; 
            case KeyEvent.KEYCODE_HOME:  
                Log.d(TAG,"HOME key up test!");  
                break;
         }  
         return super.onKeyUp(keyCode, event);  
    }  */




@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


    public void onClick(View v) {
   // TODO Auto-generated method stub
   switch (v.getId()) {
   case R.id.start:   
    start();
    break;   


   case R.id.stop:
    stop();   
    break;


   default:
    break;
   }
    }




private int init()
    {    
   Log.d(TAG,"dxp--init");
   cameraInit();
        mediaEncInit();
        mediaDecInit();

   return 0;


    }


    private int uninit()
    {
   Log.d(TAG,"dxp--uninit");
   mediaEncUninit();
   mediaDecUninit();
   cameraUninit();

   return 0;


    }


    private int start()
    {
    if(runstate ==1)return -1;
init();
   Log.d(TAG,"dxp--start");
runstate = 1;
cameraStart();
   mediaEncStart();
   mediaDecStart();

   return 0;


    }


    private int stop()
    {
    if(runstate ==0)return -1;
   Log.d(TAG,"dxp--stop");
   runstate = 0;
   mediaEncStop();
   mediaDecStop();
   cameraStop();
uninit();
   return 0;


    }


    @Override
    protected void onDestroy() {
   // TODO Auto-generated method stub
   super.onDestroy();
stop();
   uninit();


    }


    public byte[] copy(byte[] rSource) {


   byte[] aResult = new byte[rSource.length];
   System.arraycopy(rSource, 0, aResult, 0, aResult.length);


   return aResult;


    }




    ///==============================================
    ///for camera start


    public int cameraInit()
    {    
   camera = Camera.open(cameraId);
   if(camera==null){
    Log.d(TAG, "open camera object fail " );
    return -1;
   }
   
   Camera.Parameters parameters = camera.getParameters();
   List<Size> sizes;
    sizes = parameters.getSupportedPreviewSizes();
    Log.i(TAG, "==Cam supported SizeList of camera ==");
    for(Size temp:sizes)
    Log.i(TAG, temp.width+", "+temp.height);
   //parameters.setRotation(90);
    // 横竖屏镜头自动调整      
    if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE)       
    {  
    Log.d(TAG, "set camera direction when portrait");
    parameters.set("orientation", "portrait");       
    parameters.set("rotation", 90); // 镜头角度转90度(默认摄像头是横拍)        
    camera.setDisplayOrientation(90);   
    } else// 如果是横屏      
    {    
    Log.d(TAG, "set camera direction when landscape");
    parameters.set("orientation", "landscape");       
    camera.setDisplayOrientation(0);       
   
   
   parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
   Size PreviewSizes = parameters.getPreviewSize();
   //width =PreviewSizes.width;
   //height = PreviewSizes.height;
   Log.d(TAG,"dxp-- camera get size:"+PreviewSizes.width+" ,"+PreviewSizes.height);
Log.d(TAG,"dxp-- camera previw size:"+width+" ,"+height);
parameters.setPreviewSize(width, height);
   parameters.setPreviewFormat(ImageFormat.NV21);
   parameters.setPreviewFrameRate(fps); 
   camera.setParameters(parameters); 
   camera.autoFocus(null);
   //camera.setDisplayOrientation(90);
   
   camera.setPreviewCallback(new Camera.PreviewCallback() {

   public void onPreviewFrame(byte[] data, Camera camera) {
   Log.d(TAG, "dxp-- onPreviewFrame length:"+data.length );
    if(rmode){   
    synchronized(encqueue){
    encqueue.offer(data);
    }
    }else{
    EncoderFrame(data);
    }
   }
   });
       


   return 0;
    }


    public void cameraStart()
    {
    if(camera==null)return;
    try {
camera.setPreviewDisplay(CamSurfaceHolder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
    camera.startPreview();


    }


    public void cameraStop()
    {
if(camera==null)return;
    camera.stopPreview();


    }


    public void cameraUninit()
    {
    if(camera == null)return;
   camera.setPreviewCallback(null);
   camera.stopPreview();
   camera.release();
   camera = null;


    }


    private final class CamSufaceListener implements SurfaceHolder.Callback{



   public void surfaceCreated(SurfaceHolder holder) {//Surface锟斤拷锟斤拷录锟斤拷拇锟斤拷锟?
   CamSurfaceHolder = holder;
   //cameraInit();
   Log.d(TAG,"test-- camera surfaceCreated!");
        }         


        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//Surface锟侥憋拷锟铰硷拷锟侥达拷锟斤拷
       CamSurfaceHolder = holder;
       //cameraStart();  
       start();
Log.d(TAG,"dxp-- surfaceChanged:"+width+" ,"+height);
        }     


        public void surfaceDestroyed(SurfaceHolder holder) {//Surface锟斤拷锟绞憋拷拇锟斤拷锟?
       //cameraStop();
       stop();
       CamSurfaceHolder = null;  
       Log.d(TAG,"test-- camera surfaceDestroyed!");
   }
    }




    ///for camera end
    ///==============================================
    ///for mediacodec encoder start


    private MediaCodec enccodec; 
    private EncThread et;


private MediaCodecInfo selectCodec(){
boolean found = false;
int numCodecs = MediaCodecList.getCodecCount();
Log.d(TAG, "--dxp-- numCodecs:" + numCodecs);
MediaCodecInfo codecInfo = null;
for (int i = 0; i < numCodecs ; i++) {
MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
if (!info.isEncoder()) {
continue;
}

String[] types = info.getSupportedTypes();


for (int j = 0; j < types.length && !found; j++) {
if (types[j].equals(videoformat264)){
Log.d(TAG, "--dxp-- codec:" + info.getName());
Log.d(TAG, "--dxp-- can be used!" );
found = true;
codecInfo = info;
break;
}
//Log.d(TAG, "--dxp-- support:" + types[j]);
}


}

return codecInfo;
}


    public int mediaEncInit()
    {
    Log.d(TAG,"test-- mediaEncInit 1");
    MediaCodecInfo info = selectCodec();
    Log.d(TAG, "--dxp--we use codec:" + info.getName());
    //enccodec = MediaCodec.createEncoderByType(videoformat264); 
    enccodec = MediaCodec.createByCodecName(info.getName());
    MediaFormat mediaFormat = MediaFormat.createVideoFormat(videoformat264, width, height);    
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);        
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, fps);  
        /*
         * public static final int COLOR_FormatYUV420Planar            = 19;
         * public static final int COLOR_FormatYUV420PackedPlanar      = 20;
         * public static final int COLOR_FormatYUV420SemiPlanar        = 21;
         * public static final int COLOR_FormatYUV420PackedSemiPlanar  = 39;
         * public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
         * public static final int COLOR_FormatYUV420Flexible            = 0x7F420888;
         * public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
         * */
        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);      
        enccodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        MediaFormat outputFormat = enccodec.getOutputFormat();
        return 0;


    }


    public void mediaEncStart()


    {
    Log.d(TAG,"test-- mediaEncStart ");
    if(enccodec == null)return;
    enccodec.start();
    if(rmode){   
   et= new EncThread();
   et.start();
    }


    }


    public void mediaEncStop()
    {
    Log.d(TAG,"test-- mediaEncStop ");       
if(enccodec == null)return;
if(rmode){
et.interrupt();
    }
    enccodec.stop();
    }


    public void mediaEncUninit()
    {
    Log.d(TAG,"test-- mediaEncUninit ");
    if(enccodec==null)return;
   enccodec.release();
   enccodec=null;


    }


    private class EncThread extends Thread {


        public void run() {
        byte[] yuvdata = null;
       while(runstate==1){
        synchronized(encqueue){
        yuvdata = encqueue.poll();
        }
   if(yuvdata!=null){
       //Log.d(TAG, "dxp-- enc thread");
       EncoderFrame(yuvdata);
       yuvdata = null;
       }
       
   try {
    Thread.sleep(10);
   } catch (InterruptedException e) {

        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.d(TAG, "dxp-- enc thread sleep exception");
       }
       }   
        }
    }


    public void EncoderFrame(byte[] input) {
//Log.d(TAG, "dxp-- EncoderFrame");
    final long kTimeOutUs = 100;
    if(enccodec==null)return;


        try {
        ByteBuffer[] inputBuffers = enccodec.getInputBuffers();
       ByteBuffer[] outputBuffers = enccodec.getOutputBuffers();
            
            int inputBufferIndex = enccodec.dequeueInputBuffer(kTimeOutUs);
            //Log.d(TAG, "dxp-- inputBufferIndex:"+inputBufferIndex);
            if (inputBufferIndex >= 0) {
               
                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
           inputBuffer.clear();
           int wh = width*height/4;
           int length = width*height*3/2;
           
           inputBuffer.put(input, 0 , length);                
                Log.d(TAG, "dxp-- inputBufferIndex:"+inputBufferIndex+",len:"+length);
                m_nPacksPutIn ++;
           long presentationTimeUs = m_nPacksPutIn * 1000000 / fps;
           enccodec.queueInputBuffer(inputBufferIndex, 0, length, presentationTimeUs, 0);
                
            }


            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            int outputBufferIndex = enccodec.dequeueOutputBuffer(bufferInfo,kTimeOutUs);
            //Log.d(TAG, "dxp-- outputBufferIndex:"+outputBufferIndex);
            while (outputBufferIndex >= 0) {
            ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
            //MediaFormat bufferFormat = enccodec.getOutputFormat(); // option A
                byte[] outData = new byte[bufferInfo.size];
                Log.d(TAG, "dxp-- outputBufferIndex:"+outputBufferIndex+",size:"+bufferInfo.size);
                outputBuffer.get(outData);
Log.d(TAG,  "dxp-- encode outdata[4]:"+Integer.toHexString(outData[4]));

                if(rmode){
               synchronized(decqueue){
               decqueue.offer(outData);
               }
                }else{
                DecodeFrame(outData);
                }
          
                enccodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = enccodec.dequeueOutputBuffer(bufferInfo, kTimeOutUs);


            }


        } catch (Throwable t) {
            t.printStackTrace();


        }


    }


    ///formediacodec encoder end


    ///==============================================


    ///for mediacodec decoder start


    private MediaCodec deccodec; 
    private DecThread dt;




    public int mediaDecInit()
    {
    Log.d(TAG,"test-- mediaDecInit ");
    deccodec = MediaCodec.createDecoderByType(videoformat264);
    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);


        //mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
        //mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, fps);
        //mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
        //mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
    deccodec.configure(mediaFormat, DecSurfaceHolder.getSurface(), null, 0);


    return 0;


    }


    public void mediaDecStart()
    {
    Log.d(TAG,"test-- mediaDecStart ");
if(deccodec==null){
Log.d(TAG,"test-- mediaDecStart  err!");
return;
}
   deccodec.start();
   if(rmode){
    dt= new DecThread();
    dt.start();
    }


    }


    public void mediaDecStop()
    {
    Log.d(TAG,"test-- mediaDecStop ");
if(deccodec==null)return;    
    if(rmode){
    dt.interrupt();
    }
deccodec.stop();
    }


    public void mediaDecUninit()
    {
    if(deccodec==null)return;
    deccodec.release();
    deccodec=null;


    }


    private class DecThread extends Thread  {


        public void run() {
        byte[] outdata = null;
       while(runstate==1){
        //Log.d(TAG, "dxp-- dec thread");
        synchronized(decqueue){
        outdata = decqueue.poll();
        }
       if(outdata!=null){       
       DecodeFrame(outdata);
       outdata = null;
       }

       try {
   Thread.sleep(10);

} catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
}


       }                


        }


    }


    public void DecodeFrame(byte[] input) {
    Log.d(TAG, "dxp-- DecodeFrame input:"+input.length);
    if(deccodec==null)return;


        try {
            
            int inputBufferIndex = deccodec.dequeueInputBuffer(kTimeOutUs);//-1
            if (inputBufferIndex >= 0) {
            //fill data to queue
                ByteBuffer[] inputBuffer = deccodec.getInputBuffers();
                inputBuffer[inputBufferIndex].clear();
                inputBuffer[inputBufferIndex].put(input);
                //push data to mediacodec
                deccodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0);


            }


            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            int outputBufferIndex = deccodec.dequeueOutputBuffer(bufferInfo,0);
            if (outputBufferIndex >= 0) {
                ByteBuffer outputBuffer[] = deccodec.getOutputBuffers();
                byte[] outData = new byte[bufferInfo.size];
                outputBuffer[outputBufferIndex].get(outData);
                //outputStream.write(outData, 0, outData.length);
                Log.d(TAG, "dxp-- dec out datalen:"+outData.length);


                deccodec.releaseOutputBuffer(outputBufferIndex, true/*if render*/);
                outputBufferIndex = deccodec.dequeueOutputBuffer(bufferInfo, 0);
bufferInfo = null;


            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            ByteBuffer outputBuffer[] = deccodec.getOutputBuffers();


            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                // Subsequent data will conform to new format.
                MediaFormat format = deccodec.getOutputFormat();


            }


        } catch (Throwable t) {
            t.printStackTrace();
        }
    }


    private final class DecSufaceListener implements SurfaceHolder.Callback{


   public void surfaceChanged(SurfaceHolder holder, int format, int width,

   int height) {

   // TODO Auto-generated method stub
   Log.d(TAG, "dec surfaceChanged");
   DecSurfaceHolder = holder;
   //mediaEncStart();
   //mediaDecStart();

   }
   
   public void surfaceCreated(SurfaceHolder holder) {

   // TODO Auto-generated method stub
   Log.d(TAG, "dec surfaceCreated");
   DecSurfaceHolder = holder;  
   //mediaEncInit();
   //mediaDecInit();

   }


   public void surfaceDestroyed(SurfaceHolder holder) {

   // TODO Auto-generated method stub
   Log.d(TAG, "dec surfaceDestroyed");
   DecSurfaceHolder = null;
   //mediaEncStop();
   //mediaDecStop();
   //mediaEncUninit();
   //mediaDecUninit();     

   }

    }






    ///for mediacodec decoder end


    ///==============================================
}

原创粉丝点击