[RK3288][Android6.0] 一个例子看MediaCodec使用流程

来源:互联网 发布:c语言基础课程教学视频 编辑:程序博客网 时间:2024/05/25 08:13

Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92

目录

    • 编码过程
    • 主要步骤
    • 例子源代码
      • 主代码部分
      • 编码部分
    • 参考

一个使用MediaCodec的例子,正好可以从例子看编码的过程,可以借鉴参考。

编码过程:

从Camera preview callback里拿数据 -> 数据格式转换 -> 编码输入 -> 处理 -> 编码输出


主要步骤:

以下是例子使用MeidaCodec的主要步骤,我把它摘出来了,详细部分见后面源代码。

  • mediaCodec = MediaCodec.createEncoderByType("video/avc");

编码类型是avc

  • MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width,height);

根据宽高创建MediaFormat,设置参数需要MediaFormat.

  • mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
    MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);

根据当前需求设置参数

  • mediaCodec.configure(mediaFormat, null, null,
    MediaCodec.CONFIGURE_FLAG_ENCODE);

参数2表示编码后输出到哪个surface,这里编码直接输出到buffer,所以可以为NULL。
参数4设置MediaCodec.CONFIGURE_FLAG_ENCODE表示配置成编码器。

  • mediaCodec.start();

开始运行

  • avcCodec.offerEncoder(arg0,h264);

Camera preview callback拿到数据arg0后送到编码器,编码完成后输出到h264缓存里。
swapYV12toI420(input, yuv420, m_width, m_height);
由于camera输出的数据格式和编码器支持的输入数据格式不一致,需要先转换。

  • mediaCodec.getInputBuffers(); inputBufferIndex =
    mediaCodec.dequeueInputBuffer(-1); ByteBuffer inputBuffer =
    inputBuffers[inputBufferIndex];

获取输入空闲buffer,然后得到空闲buffer中的一个index,这样就可以得到要使用的buffer了

  • inputBuffer.put(yuv420);
    mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0,
    0);

输入入队准备后就开始编码处理了

  • ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
    outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
    outputBuffer = outputBuffers[outputBufferIndex];

同样的方式,编码处理完成取出编码后的数据buffer

  • mediaCodec.releaseOutputBuffer(outputBufferIndex, false);

当前buffer用好了就释放掉给下一轮编码使用

  • FileOut.write(output,0,pos);

编码后的数据可以做拿去解码,网络发送等,这里就写到文件保存下来。


例子源代码:

主代码部分:

package com.example.com.rk.dec_enc;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import android.graphics.ImageFormat;import android.hardware.Camera;import android.hardware.Camera.PreviewCallback;import android.media.AudioManager;import android.media.MediaPlayer;import android.os.Bundle;import android.annotation.SuppressLint;import android.app.Activity;import android.util.Log;import android.view.Menu;import android.view.SurfaceHolder;import android.view.SurfaceHolder.Callback;import android.view.SurfaceView;import android.view.View;@SuppressLint("NewApi") public class MainActivity extends Activity implements PreviewCallback {    AvcEncoder avcCodec = null;    AvcDecoder avcDecodec = null;    boolean avcDecFlag = false;    boolean avcEncFlag = false;    //boolean RecordCameraFrameDataFlag = true;    boolean RecordCameraFrameDataFlag = false;    public Camera m_camera;      SurfaceView   m_prevewview;    SurfaceHolder m_surfaceHolder;    SurfaceView   mDecSurfaceView;    SurfaceHolder mDecSurfaceHolder;    MediaPlayer mMediaPlayer;    private SurfaceHolder.Callback mSurfaceCallback;    int width = 1280;    int height = 720;    int framerate = 30;    int bitrate = 500000;    FileOutputStream FileOut = null;     byte[] h264 = new byte[width*height*3/2];    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        m_prevewview = (SurfaceView) findViewById(R.id.SurfaceViewPlay);        mDecSurfaceView = (SurfaceView) findViewById(R.id.SurfaceViewPlay_Dec);        mSurfaceCallback = new SurfaceHolder.Callback(){            @Override            public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,                    int arg3) {                // TODO Auto-generated method stub            }            @Override            public void surfaceCreated(SurfaceHolder arg0) {                // TODO Auto-generated method stub                Log.d("Hery", "arg0  =" + arg0);                mDecSurfaceHolder = mDecSurfaceView.getHolder(); // Bind SurfaceView. get SurfaceHolder context                m_surfaceHolder = m_prevewview.getHolder(); // Bind SurfaceView get SurfaceHolder context                mDecSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);                m_surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);                boolean m_surfaceHolderisCreat = m_surfaceHolder.isCreating();                Log.d("Hery", "m_surfaceHolder  =" + m_surfaceHolderisCreat);                boolean mmDecSurfaceHolderisCreat = mDecSurfaceHolder.isCreating();                Log.d("Hery", "mmDecSurfaceHolderisCreat  =" + mmDecSurfaceHolderisCreat);                if(mmDecSurfaceHolderisCreat == true && (avcDecodec== null) && (avcDecFlag == false))                {                    Log.d("Hery", "Create AvcDecoder");                    avcDecodec = new AvcDecoder(width,height,mDecSurfaceHolder);                    avcDecFlag = true;                }                if(m_surfaceHolderisCreat == true && (avcCodec == null) && (avcEncFlag == false))                {                    Log.d("Hery", "Create Camera");                    avcCodec = new AvcEncoder(width,height,framerate,bitrate);                    avcEncFlag = true;                    m_camera = Camera.open();                    try {                        m_camera.setPreviewDisplay(m_surfaceHolder);                    } catch (IOException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    Camera.Parameters parameters = m_camera.getParameters();                    parameters.setPreviewSize(width, height);                    parameters.setPictureSize(width, height);                    parameters.setPreviewFormat(ImageFormat.YV12);                    m_camera.setParameters(parameters);                     m_camera.setPreviewCallback((PreviewCallback)MainActivity.this);                    m_camera.startPreview();                    }            }            @Override            public void surfaceDestroyed(SurfaceHolder arg0) {                // TODO Auto-generated method stub                Log.d("Hery","surfaceDestroyed");            }        };        mDecSurfaceView.getHolder().addCallback(mSurfaceCallback);        m_prevewview.getHolder().addCallback(mSurfaceCallback);        m_prevewview.setVisibility(View.VISIBLE);        mDecSurfaceView.setVisibility(View.VISIBLE);        if(RecordCameraFrameDataFlag)        {            try {                FileOut = new FileOutputStream(new File("/sdcard/app_camera.yuv"));            } catch (FileNotFoundException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }    @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;    }    @Override    public void onPreviewFrame(byte[] arg0, Camera arg1) {        //Log.d("Hery", "onPreviewFrame");        if(RecordCameraFrameDataFlag)        {            try {                FileOut.write(arg0,0,arg0.length);            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        // TODO Auto-generated method stub        int size = avcCodec.offerEncoder(arg0,h264);        avcDecodec.pushData(h264,size);    }   }

编码部分:

package com.example.com.rk.dec_enc;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import android.annotation.SuppressLint;import android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaFormat;import android.util.Log;@SuppressLint("NewApi") public class AvcEncoder {    private MediaCodec mediaCodec;    int m_width;    int m_height;    //boolean RecordEncDataFlag = true;    boolean RecordEncDataFlag = false;    byte[] m_info = null;    FileOutputStream FileOut = null;     private byte[] yuv420 = null;     public AvcEncoder(int width, int height, int framerate, int bitrate) {         Log.d("Hery", "AvcEncoder IN");        m_width  = width;        m_height = height;        yuv420 = new byte[width*height*3/2];        mediaCodec = MediaCodec.createEncoderByType("video/avc");        MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);        mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);        mediaCodec.start();        if(RecordEncDataFlag)        {            try {                FileOut = new FileOutputStream(new File("/sdcard/app_camera_enc.h264"));            } catch (FileNotFoundException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }    public void close() {        try {            mediaCodec.stop();            mediaCodec.release();        } catch (Exception e){             e.printStackTrace();        }        try {            FileOut.close();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    public int offerEncoder(byte[] input, byte[] output)     {           //Log.d("......................................................Hery", "Encoder in");        int pos = 0;        swapYV12toI420(input, yuv420, m_width, m_height);        try {            ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();            ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();            int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);            //Log.d("......................................................Hery", "inputBufferIndex = " +inputBufferIndex);            if (inputBufferIndex >= 0)             {                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];                inputBuffer.clear();                inputBuffer.put(yuv420);                mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0);            }            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();            int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);            //Log.d("......................................................Hery", "outputBufferIndex = " +outputBufferIndex);            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;                }                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);                         System.arraycopy(outData, 0, output, pos, outData.length);                         pos+=outData.length;                     }                      else                      {                              return -1;                     }                      }                mediaCodec.releaseOutputBuffer(outputBufferIndex, false);                outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);            }            if(output[4] == 0x65) //key frame            {                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();        }        //Log.d("......................................................Hery", "Encoder out");        if(RecordEncDataFlag)        {            try {                FileOut.write(output,0,pos);            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        return pos;    }    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);      } }

参考:

Android中直播视频技术探究之—基础知识大纲介绍

阅读全文
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 天猫精灵方糖连不上网怎么办 设置隐私相片里没什么都没有怎么办 我的手机丢了里面有隐私相片怎么办 苹果5s的id关了怎么办 用op手机快手拍视频打不开怎么办 苹果8p用流量下载不了软件怎么办 流量下载不了内存大的游戏怎么办 苹果6s开机密码忘记了怎么办 咸鱼买东西没寄买家申请退款怎么办 淘宝商品缺货又不想下架怎么办 房产代理商不给我结佣金怎么办 天猫客服遇到脾气不好的客户怎么办 美团外卖点的食品与描述不符怎么办 淘宝极速退款后买家又不想退怎么办 宝贝破损买家退回运费很高怎么办 信而富额度变0了怎么办 申请淘京猫代理时资料填错了怎么办 苹果手机能上网但微信不能用怎么办 卧室壁纸贴的太花了怎么办 贴完墙纸接头处看着是黑色的怎么办 把所有内容放在一张纸上怎么办 孩子脸上被蚊香烧了留下了疤怎么办 微信怎么修改支付密码忘了怎么办 去网鱼网咖上网没带身份证怎么办 淘宝买家号忘了账号和密码怎么办 80多岁的老人前列腺疼怎么办啊 新浪微博发二维码让我入群我怎么办 队友送的太崩了打野应该怎么办 该商品不支持在当前地区销售怎么办 此商品不支持在当前地区销售怎么办 村淘商品在淘宝没展现怎么办 qq音乐不小心充了会员怎么办 古奇的包五金磨掉色了怎么办 淘宝购物津贴买的东西退款怎么办 淘宝买的东西质量太差怎么办 咸鱼上买的东西有问题怎么办 咸鱼买到的东西有问题怎么办 天猫超市买的东西有问题怎么办 满白天的宝宝睡觉总哭怎么办 京东退货显示在售后检测要怎么办 装修公司定金交了公司关门怎么办