如题所述
Android ç¨MediaCodecå®ç°è§é¢ç¡¬è§£ç
æ¬æåä½ è®²è¿°å¦ä½ç¨androidæ åçAPI ï¼MediaCodecï¼å®ç°è§é¢ç硬件ç¼è§£ç ãä¾ç¨å°ä»æå头ééè§é¢å¼å§ï¼ç¶åè¿è¡H264ç¼ç ï¼å解ç ï¼ç¶åæ¾ç¤ºãæå°å°½é讲å¾ç®çèæ¸ æ°ï¼ä¸å±ç¤ºé£äºä¸ç¸å ³ç代ç ãä½æ¯ï¼æä¸å»ºè®®ä½ 读è¿ç¯æç« ï¼ä¹ä¸å»ºè®®ä½ å¼åè¿ç±»åºç¨ï¼èåºè¯¥è½¬èå¼åä¸äºæ³é±¼ãæé¸ãå ¶ä¹èèçç¨åºã好å§ï¼ä¸é¢çå 容æ¯åç»é£äºæ§è¿·ä¸æç人çï¼çå®ä¹åä¹è®¸ä½ ä¼åææç说æ³ï¼Androidåªæ¯ä¸ä¸ªç©å ·ï¼å¾é¾ææå®æ¥åé è°±çåºç¨ã
1ãä»æå头ééè§é¢
å¯ä»¥éè¿æå头Previewçåè°ï¼æ¥è·åè§é¢æ°æ®ã
é¦å å建æå头ï¼å¹¶è®¾ç½®åæ°ï¼
[java] view plaincopy
cam = Camera.open();
cam.setPreviewDisplay(holder);
Camera.Parameters parameters = cam.getParameters();
parameters.setFlashMode("off"); // æ éªå ç¯
parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
parameters.setPreviewFormat(ImageFormat.YV12);
parameters.setPictureSize(camWidth, camHeight);
parameters.setPreviewSize(camWidth, camHeight);
//è¿ä¸¤ä¸ªå±æ§ å¦æè¿ä¸¤ä¸ªå±æ§è®¾ç½®çåçå®ææºçä¸ä¸æ ·æ¶ï¼å°±ä¼æ¥é
cam.setParameters(parameters);
宽度åé«åº¦å¿ é¡»æ¯æå头æ¯æç尺寸ï¼å¦åä¼æ¥éãè¦è·å¾æææ¯æç尺寸ï¼å¯ç¨getSupportedPreviewSizesï¼è¿éä¸å累述ãæ®è¯´ææçåæ°å¿ é¡»è®¾å ¨ï¼æ¼æä¸ä¸ªå°±å¯è½æ¥éï¼ä¸è¿åªæ¯æ®è¯´ï¼æåªè®¾äºå 个å±æ§ä¹æ²¡åºéã ç¶åå°±å¼å§Previewäºï¼
[java] view plaincopy
buf = new byte[camWidth * camHeight * 3 / 2];
cam.addCallbackBuffer(buf);
cam.setPreviewCallbackWithBuffer(this);
cam.startPreview();
setPreviewCallbackWithBufferæ¯å¾æå¿ è¦çï¼ä¸ç¶æ¯æ¬¡åè°ç³»ç»é½éæ°åé ç¼å²åºï¼æçä¼å¾ä½ã
å¨onPreviewFrameä¸å°±å¯ä»¥è·å¾åå§çå¾çäºï¼å½ç¶ï¼this è¯å®è¦ implements PreviewCallbackäºï¼ãè¿éæ们æ¯æå®ä¼ ç»ç¼ç å¨ï¼
[java] view plaincopy
public void onPreviewFrame(byte[] data, Camera camera) {
if (frameListener != null) {
frameListener.onFrame(data, 0, data.length, 0);
}
cam.addCallbackBuffer(buf);
}
2ãç¼ç
é¦å è¦åå§åç¼ç å¨ï¼
[java] view plaincopy
mediaCodec = MediaCodec.createEncoderByType("Video/AVC");
MediaFormat mediaFormat = MediaFormat.createVideoFormat(type, width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
ç¶åå°±æ¯ç»ä»åæ°æ®äºï¼è¿éçæ°æ®æ¯æ¥èªæå头çï¼
[java] view plaincopy
public void onFrame(byte[] buf, int offset, int length, int flag) {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0)
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(buf, offset, length);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
if (frameListener != null)
frameListener.onFrame(outputBuffer, 0, length, flag);
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
å ææ¥èªæå头çæ°æ®åç»å®ï¼ç¶åä»å®éé¢åå缩好çæ°æ®åç»è§£ç å¨ã
3ã解ç åæ¾ç¤º
é¦å åå§å解ç å¨ï¼
[java] view plaincopy
mediaCodec = MediaCodec.createDecoderByType("Video/AVC");
MediaFormat mediaFormat = MediaFormat.createVideoFormat(mime, width, height);
mediaCodec.configure(mediaFormat, surface, null, 0);
mediaCodec.start();
è¿ééè¿ç»è§£ç å¨ä¸ä¸ªsurfaceï¼è§£ç å¨å°±è½ç´æ¥æ¾ç¤ºç»é¢ã
ç¶åå°±æ¯å¤çæ°æ®äºï¼
[java] view plaincopy
public void onFrame(byte[] buf, int offset, int length, int flag) {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(buf, offset, length);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, length, mCount * 1000000 / FRAME_RATE, 0);
mCount++;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
}
queueInputBuffer第ä¸ä¸ªåæ°æ¯æ¶é´æ³ï¼å ¶å®æä¹åé½æ æè°ï¼åªè¦æ¯ææ¶é´çº¿æ§å¢å çå°±å¯ä»¥ï¼è¿éå°±é便å¼ä¸ä¸ªäºãåé¢ä¸æ®µç代ç å°±æ¯æç¼å²åºç»éæ¾æï¼å 为æ们ç´æ¥è®©è§£ç å¨æ¾ç¤ºï¼å°±ä¸éè¦è§£ç åºæ¥çæ°æ®äºï¼ä½æ¯å¿ é¡»è¦è¿ä¹éæ¾ä¸ä¸ï¼å¦å解ç å¨å§ç»ç»ä½ ççï¼å å就该ä¸å¤ç¨äºã
好äºï¼å°ç°å¨ï¼åºæ¬ä¸å°±å¯ä»¥äºãå¦æä½ è¿æ°å¤å¥½ï¼ç°å¨å°±è½çå°è§é¢äºï¼æ¯å¦å¨æçä¸æææºä¸è¿æ ·å°±å¯ä»¥äºãä½æ¯ï¼æè¯è¿å ä¸ªå ¶ä»å¹³å°ï¼å¤æ°é½ä¸å¯ä»¥ï¼æ»æ¯æåç§åæ ·çé®é¢ï¼å¦æè¦å¼åä¸ä¸ªä¸ä¾èµå¹³å°çåºç¨ï¼è¿æå¾å¤çé®é¢è¦è§£å³ã说说æéå°çä¸äºæ åµï¼
1ãè§é¢å°ºå¯¸
ä¸è¬é½è½æ¯æ176X144/352X288è¿ç§å°ºå¯¸ï¼ä½æ¯å¤§ä¸äºçï¼640X480å°±æå¾å¤æºåä¸è¡äºï¼è³äºä¸ºä»ä¹ï¼æä¹ä¸ç¥éãå½ç¶ï¼è¿ä¸ªå°ºå¯¸å¿ é¡»åæå头é¢è§ç尺寸ä¸è´ï¼é¢è§ç尺寸å¯ä»¥æ举ä¸ä¸ã
2ãé¢è²ç©ºé´
æ ¹æ®ANdroid SDKææ¡£ï¼ç¡®ä¿ææ硬件平å°é½æ¯æçé¢è²ï¼å¨æå头é¢è§è¾åºæ¯YUV12ï¼å¨ç¼ç å¨è¾å ¥æ¯COLOR_FormatYUV420Planarï¼ä¹å°±æ¯åé¢ä»£ç ä¸è®¾ç½®çé£æ ·ã ä¸è¿ï¼ææ¡£ç»ç©¶æ¯ææ¡£ï¼å¦åå®åå°±ä¸æ¯å®åã
å¨æçå¹³å°ä¸ï¼è¿ä¸¤ä¸ªé¢è²æ ¼å¼æ¯ä¸æ ·çï¼æå头çè¾åºå¯ä»¥ç´æ¥ä½ä¸ºç¼ç å¨çè¾å ¥ãä¹æçå¹³å°ï¼ä¸¤ä¸ªæ¯ä¸ä¸æ ·çï¼åè å°±æ¯YUV12ï¼åè çäºI420ï¼éè¦æåè çUVåéé¢ åä¸ä¸ãä¸é¢ç代ç æçä¸é«ï¼å¯ä¾åèã
[java] view plaincopy
byte[] i420bytes = null;
private byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
if (i420bytes == null)
i420bytes = new byte[yv12bytes.length];
for (int i = 0; i < width*height; i++)
i420bytes[i] = yv12bytes[i];
for (int i = width*height; i < width*height + (width/2*height/2); i++)
i420bytes[i] = yv12bytes[i + (width/2*height/2)];
for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)
i420bytes[i] = yv12bytes[i - (width/2*height/2)];
return i420bytes;
}
è¿éçå°é¾æ¯ï¼æä¸ç¥éææ ·å»å¤ææ¯å¦éè¦è¿ä¸ªè½¬æ¢ãæ®è¯´ï¼Android 4.3ä¸ç¨åä»æå头çPreViewéé¢åå¾åï¼é¿å¼äºè¿ä¸ªé®é¢ãè¿éæ个ä¾åï¼è½ç¶æ没读ï¼ä½çèµ·æ¥æºå害çæ ·åï¼åºè¯¥ä¸ä¼æéå§ï¼è§ååºç¶ï¼ãhttp://bigflake.com/mediacodec/CameraToMpegTest.java.txt
3ãè¾å ¥è¾åºç¼å²åºçæ ¼å¼
SDKé并没æè§å®æ ¼å¼ï¼ä½æ¯ï¼è¿ç§æ åµH264çæ ¼å¼åºæ¬ä¸å°±æ¯éå½Bãä½æ¯ï¼ä¹ææ¯è¾æç¹è²çï¼å®å°±æ¯ä¸å¸¦é£ä¸ªStartCodeï¼å°±æ¯é£ä¸ª0x000001ï¼æå¾æä»ç¼ç å¨ç¼åºæ¥çä¸è¥¿éç»ä»ç解ç å¨ï¼ä»èªå·±é½è§£ä¸åºæ¥ãè¿å¥½ï¼æ们å¯ä»¥èªå·±å ã
[java] view plaincopy
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size + 3];
outputBuffer.get(outData, 3, bufferInfo.size);
if (frameListener != null) {
if ((outData[3]==0 && outData[4]==0 && outData[5]==1)
|| (outData[3]==0 && outData[4]==0 && outData[5]==0 && outData[6]==1))
{
frameListener.onFrame(outData, 3, outData.length-3, bufferInfo.flags);
}
else
{
outData[0] = 0;
outData[1] = 0;
outData[2] = 1;
frameListener.onFrame(outData, 0, outData.length, bufferInfo.flags);
}
}
4ãææ¶åä¼æ»å¨dequeueInputBuffer(-1)ä¸é¢
æ¬æåä½ è®²è¿°å¦ä½ç¨androidæ åçAPI ï¼MediaCodecï¼å®ç°è§é¢ç硬件ç¼è§£ç ãä¾ç¨å°ä»æå头ééè§é¢å¼å§ï¼ç¶åè¿è¡H264ç¼ç ï¼å解ç ï¼ç¶åæ¾ç¤ºãæå°å°½é讲å¾ç®çèæ¸ æ°ï¼ä¸å±ç¤ºé£äºä¸ç¸å ³ç代ç ãä½æ¯ï¼æä¸å»ºè®®ä½ 读è¿ç¯æç« ï¼ä¹ä¸å»ºè®®ä½ å¼åè¿ç±»åºç¨ï¼èåºè¯¥è½¬èå¼åä¸äºæ³é±¼ãæé¸ãå ¶ä¹èèçç¨åºã好å§ï¼ä¸é¢çå 容æ¯åç»é£äºæ§è¿·ä¸æç人çï¼çå®ä¹åä¹è®¸ä½ ä¼åææç说æ³ï¼Androidåªæ¯ä¸ä¸ªç©å ·ï¼å¾é¾ææå®æ¥åé è°±çåºç¨ã
1ãä»æå头ééè§é¢
å¯ä»¥éè¿æå头Previewçåè°ï¼æ¥è·åè§é¢æ°æ®ã
é¦å å建æå头ï¼å¹¶è®¾ç½®åæ°ï¼
[java] view plaincopy
cam = Camera.open();
cam.setPreviewDisplay(holder);
Camera.Parameters parameters = cam.getParameters();
parameters.setFlashMode("off"); // æ éªå ç¯
parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
parameters.setPreviewFormat(ImageFormat.YV12);
parameters.setPictureSize(camWidth, camHeight);
parameters.setPreviewSize(camWidth, camHeight);
//è¿ä¸¤ä¸ªå±æ§ å¦æè¿ä¸¤ä¸ªå±æ§è®¾ç½®çåçå®ææºçä¸ä¸æ ·æ¶ï¼å°±ä¼æ¥é
cam.setParameters(parameters);
宽度åé«åº¦å¿ é¡»æ¯æå头æ¯æç尺寸ï¼å¦åä¼æ¥éãè¦è·å¾æææ¯æç尺寸ï¼å¯ç¨getSupportedPreviewSizesï¼è¿éä¸å累述ãæ®è¯´ææçåæ°å¿ é¡»è®¾å ¨ï¼æ¼æä¸ä¸ªå°±å¯è½æ¥éï¼ä¸è¿åªæ¯æ®è¯´ï¼æåªè®¾äºå 个å±æ§ä¹æ²¡åºéã ç¶åå°±å¼å§Previewäºï¼
[java] view plaincopy
buf = new byte[camWidth * camHeight * 3 / 2];
cam.addCallbackBuffer(buf);
cam.setPreviewCallbackWithBuffer(this);
cam.startPreview();
setPreviewCallbackWithBufferæ¯å¾æå¿ è¦çï¼ä¸ç¶æ¯æ¬¡åè°ç³»ç»é½éæ°åé ç¼å²åºï¼æçä¼å¾ä½ã
å¨onPreviewFrameä¸å°±å¯ä»¥è·å¾åå§çå¾çäºï¼å½ç¶ï¼this è¯å®è¦ implements PreviewCallbackäºï¼ãè¿éæ们æ¯æå®ä¼ ç»ç¼ç å¨ï¼
[java] view plaincopy
public void onPreviewFrame(byte[] data, Camera camera) {
if (frameListener != null) {
frameListener.onFrame(data, 0, data.length, 0);
}
cam.addCallbackBuffer(buf);
}
2ãç¼ç
é¦å è¦åå§åç¼ç å¨ï¼
[java] view plaincopy
mediaCodec = MediaCodec.createEncoderByType("Video/AVC");
MediaFormat mediaFormat = MediaFormat.createVideoFormat(type, width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
ç¶åå°±æ¯ç»ä»åæ°æ®äºï¼è¿éçæ°æ®æ¯æ¥èªæå头çï¼
[java] view plaincopy
public void onFrame(byte[] buf, int offset, int length, int flag) {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0)
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(buf, offset, length);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
if (frameListener != null)
frameListener.onFrame(outputBuffer, 0, length, flag);
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
å ææ¥èªæå头çæ°æ®åç»å®ï¼ç¶åä»å®éé¢åå缩好çæ°æ®åç»è§£ç å¨ã
3ã解ç åæ¾ç¤º
é¦å åå§å解ç å¨ï¼
[java] view plaincopy
mediaCodec = MediaCodec.createDecoderByType("Video/AVC");
MediaFormat mediaFormat = MediaFormat.createVideoFormat(mime, width, height);
mediaCodec.configure(mediaFormat, surface, null, 0);
mediaCodec.start();
è¿ééè¿ç»è§£ç å¨ä¸ä¸ªsurfaceï¼è§£ç å¨å°±è½ç´æ¥æ¾ç¤ºç»é¢ã
ç¶åå°±æ¯å¤çæ°æ®äºï¼
[java] view plaincopy
public void onFrame(byte[] buf, int offset, int length, int flag) {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(buf, offset, length);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, length, mCount * 1000000 / FRAME_RATE, 0);
mCount++;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
}
queueInputBuffer第ä¸ä¸ªåæ°æ¯æ¶é´æ³ï¼å ¶å®æä¹åé½æ æè°ï¼åªè¦æ¯ææ¶é´çº¿æ§å¢å çå°±å¯ä»¥ï¼è¿éå°±é便å¼ä¸ä¸ªäºãåé¢ä¸æ®µç代ç å°±æ¯æç¼å²åºç»éæ¾æï¼å 为æ们ç´æ¥è®©è§£ç å¨æ¾ç¤ºï¼å°±ä¸éè¦è§£ç åºæ¥çæ°æ®äºï¼ä½æ¯å¿ é¡»è¦è¿ä¹éæ¾ä¸ä¸ï¼å¦å解ç å¨å§ç»ç»ä½ ççï¼å å就该ä¸å¤ç¨äºã
好äºï¼å°ç°å¨ï¼åºæ¬ä¸å°±å¯ä»¥äºãå¦æä½ è¿æ°å¤å¥½ï¼ç°å¨å°±è½çå°è§é¢äºï¼æ¯å¦å¨æçä¸æææºä¸è¿æ ·å°±å¯ä»¥äºãä½æ¯ï¼æè¯è¿å ä¸ªå ¶ä»å¹³å°ï¼å¤æ°é½ä¸å¯ä»¥ï¼æ»æ¯æåç§åæ ·çé®é¢ï¼å¦æè¦å¼åä¸ä¸ªä¸ä¾èµå¹³å°çåºç¨ï¼è¿æå¾å¤çé®é¢è¦è§£å³ã说说æéå°çä¸äºæ åµï¼
1ãè§é¢å°ºå¯¸
ä¸è¬é½è½æ¯æ176X144/352X288è¿ç§å°ºå¯¸ï¼ä½æ¯å¤§ä¸äºçï¼640X480å°±æå¾å¤æºåä¸è¡äºï¼è³äºä¸ºä»ä¹ï¼æä¹ä¸ç¥éãå½ç¶ï¼è¿ä¸ªå°ºå¯¸å¿ é¡»åæå头é¢è§ç尺寸ä¸è´ï¼é¢è§ç尺寸å¯ä»¥æ举ä¸ä¸ã
2ãé¢è²ç©ºé´
æ ¹æ®ANdroid SDKææ¡£ï¼ç¡®ä¿ææ硬件平å°é½æ¯æçé¢è²ï¼å¨æå头é¢è§è¾åºæ¯YUV12ï¼å¨ç¼ç å¨è¾å ¥æ¯COLOR_FormatYUV420Planarï¼ä¹å°±æ¯åé¢ä»£ç ä¸è®¾ç½®çé£æ ·ã ä¸è¿ï¼ææ¡£ç»ç©¶æ¯ææ¡£ï¼å¦åå®åå°±ä¸æ¯å®åã
å¨æçå¹³å°ä¸ï¼è¿ä¸¤ä¸ªé¢è²æ ¼å¼æ¯ä¸æ ·çï¼æå头çè¾åºå¯ä»¥ç´æ¥ä½ä¸ºç¼ç å¨çè¾å ¥ãä¹æçå¹³å°ï¼ä¸¤ä¸ªæ¯ä¸ä¸æ ·çï¼åè å°±æ¯YUV12ï¼åè çäºI420ï¼éè¦æåè çUVåéé¢ åä¸ä¸ãä¸é¢ç代ç æçä¸é«ï¼å¯ä¾åèã
[java] view plaincopy
byte[] i420bytes = null;
private byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
if (i420bytes == null)
i420bytes = new byte[yv12bytes.length];
for (int i = 0; i < width*height; i++)
i420bytes[i] = yv12bytes[i];
for (int i = width*height; i < width*height + (width/2*height/2); i++)
i420bytes[i] = yv12bytes[i + (width/2*height/2)];
for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)
i420bytes[i] = yv12bytes[i - (width/2*height/2)];
return i420bytes;
}
è¿éçå°é¾æ¯ï¼æä¸ç¥éææ ·å»å¤ææ¯å¦éè¦è¿ä¸ªè½¬æ¢ãæ®è¯´ï¼Android 4.3ä¸ç¨åä»æå头çPreViewéé¢åå¾åï¼é¿å¼äºè¿ä¸ªé®é¢ãè¿éæ个ä¾åï¼è½ç¶æ没读ï¼ä½çèµ·æ¥æºå害çæ ·åï¼åºè¯¥ä¸ä¼æéå§ï¼è§ååºç¶ï¼ãhttp://bigflake.com/mediacodec/CameraToMpegTest.java.txt
3ãè¾å ¥è¾åºç¼å²åºçæ ¼å¼
SDKé并没æè§å®æ ¼å¼ï¼ä½æ¯ï¼è¿ç§æ åµH264çæ ¼å¼åºæ¬ä¸å°±æ¯éå½Bãä½æ¯ï¼ä¹ææ¯è¾æç¹è²çï¼å®å°±æ¯ä¸å¸¦é£ä¸ªStartCodeï¼å°±æ¯é£ä¸ª0x000001ï¼æå¾æä»ç¼ç å¨ç¼åºæ¥çä¸è¥¿éç»ä»ç解ç å¨ï¼ä»èªå·±é½è§£ä¸åºæ¥ãè¿å¥½ï¼æ们å¯ä»¥èªå·±å ã
[java] view plaincopy
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size + 3];
outputBuffer.get(outData, 3, bufferInfo.size);
if (frameListener != null) {
if ((outData[3]==0 && outData[4]==0 && outData[5]==1)
|| (outData[3]==0 && outData[4]==0 && outData[5]==0 && outData[6]==1))
{
frameListener.onFrame(outData, 3, outData.length-3, bufferInfo.flags);
}
else
{
outData[0] = 0;
outData[1] = 0;
outData[2] = 1;
frameListener.onFrame(outData, 0, outData.length, bufferInfo.flags);
}
}
4ãææ¶åä¼æ»å¨dequeueInputBuffer(-1)ä¸é¢
温馨提示:答案为网友推荐,仅供参考