1. 程式人生 > >【Android】Android Camera實時資料採集及通過MediaCodec硬編碼編碼資料的流程

【Android】Android Camera實時資料採集及通過MediaCodec硬編碼編碼資料的流程

// video device.
private Camera camera;
private MediaCodec vencoder;
private MediaCodecInfo vmci;
private MediaCodec.BufferInfo vebi;
private byte[] vbuffer;
// video camera settings.
private Camera.Size vsize;
private int vcolor;
private int vbitrate_kbps = 300;
private final static int VFPS = 20;
private
final static int VGOP = 5; private final static int VWIDTH = 640; private final static int VHEIGHT = 480; /* 首先需要初始化MediaCodec的配置 */ private void initMediaCodec() { // choose the right vencoder, perfer qcom then google. vcolor = chooseVideoEncoder(); // vencoder yuv to 264 es stream. // requires sdk level 16+, Android 4.1, 4.1.1, the JELLY_BEAN
try { vencoder = MediaCodec.createByCodecName(vmci.getName()); } catch (IOException e) { Log.e(TAG, "create vencoder failed."); e.printStackTrace(); return; } vebi = new MediaCodec.BufferInfo(); // setup the vencoder. // @see https://developer.android.com/reference/android/media/MediaCodec.html
MediaFormat vformat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, vsize.width, vsize.height); vformat.setInteger(MediaFormat.KEY_COLOR_FORMAT, vcolor); vformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0); vformat.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * vbitrate_kbps); vformat.setInteger(MediaFormat.KEY_FRAME_RATE, VFPS); vformat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, VGOP); Log.i(TAG, String.format("vencoder %s, color=%d, bitrate=%d, fps=%d, gop=%d, size=%dx%d", vmci.getName(), vcolor, vbitrate_kbps, VFPS, VGOP, vsize.width, vsize.height)); // the following error can be ignored: // 1. the storeMetaDataInBuffers error: // [OMX.qcom.video.encoder.avc] storeMetaDataInBuffers (output) failed w/ err -2147483648 // @see http://bigflake.com/mediacodec/#q12 vencoder.configure(vformat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); vencoder.start(); } // for the vbuffer for YV12(android YUV), @see below: // https://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat(int) // https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12 private int getYuvBuffer(int width, int height) { // stride = ALIGN(width, 16) int stride = (int) Math.ceil(width / 16.0) * 16; // y_size = stride * height int y_size = stride * height; // c_stride = ALIGN(stride/2, 16) int c_stride = (int) Math.ceil(width / 32.0) * 16; // c_size = c_stride * height/2 int c_size = c_stride * height / 2; // size = y_size + c_size * 2 return y_size + c_size * 2; } // choose the video encoder by name. private MediaCodecInfo chooseVideoEncoder(String name, MediaCodecInfo def) { int nbCodecs = MediaCodecList.getCodecCount(); for (int i = 0; i < nbCodecs; i++) { MediaCodecInfo mci = MediaCodecList.getCodecInfoAt(i); if (!mci.isEncoder()) { continue; } String[] types = mci.getSupportedTypes(); for (int j = 0; j < types.length; j++) { if (types[j].equalsIgnoreCase(VCODEC)) { //Log.i(TAG, String.format("vencoder %s types: %s", mci.getName(), types[j])); if (name == null) { return mci; } if (mci.getName().contains(name)) { return mci; } } } } return def; } // choose the right supported color format. @see below: // https://developer.android.com/reference/android/media/MediaCodecInfo.html // https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities.html private int chooseVideoEncoder() { // choose the encoder "video/avc": // 1. select one when type matched. // 2. perfer google avc. // 3. perfer qcom avc. vmci = chooseVideoEncoder(null, null); //vmci = chooseVideoEncoder("google", vmci); //vmci = chooseVideoEncoder("qcom", vmci); int matchedColorFormat = 0; MediaCodecInfo.CodecCapabilities cc = vmci.getCapabilitiesForType(VCODEC); for (int i = 0; i < cc.colorFormats.length; i++) { int cf = cc.colorFormats[i]; Log.i(TAG, String.format("vencoder %s supports color fomart 0x%x(%d)", vmci.getName(), cf, cf)); // choose YUV for h.264, prefer the bigger one. // corresponding to the color space transform in onPreviewFrame if ((cf >= cc.COLOR_FormatYUV420Planar && cf <= cc.COLOR_FormatYUV420SemiPlanar)) { if (cf > matchedColorFormat) { matchedColorFormat = cf; } } } for (int i = 0; i < cc.profileLevels.length; i++) { MediaCodecInfo.CodecProfileLevel pl = cc.profileLevels[i]; Log.i(TAG, String.format("vencoder %s support profile %d, level %d", vmci.getName(), pl.profile, pl.level)); } Log.i(TAG, String.format("vencoder %s choose color format 0x%x(%d)", vmci.getName(), matchedColorFormat, matchedColorFormat)); return matchedColorFormat; }