本文为看雪论坛优秀文章
看雪论坛作者ID:熊猫吃鱼
起因
流程
实战
代码片段
重写的方法:
surfaceChanged(SurfaceHolder holderformatwidthheight){}
surfaceCreated(SurfaceHolder holder){}
surfaceDestroyed(SurfaceHolder holder) {}
SurfaceHolder holder = mSurfaceView.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
if (mCamera != null) {
mCamera.stopPreview();
mSurfaceView = null;
mSurfaceHolder = null;
}
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(arg0);
mSurfaceHolder = arg0;
}
} catch (IOException exception) {
Log.e(TAG, "Error setting up preview display", exception);
}
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
if (mCamera == null)
return;
//设置参数
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(640, 480);
parameters.setPictureSize(640, 480);
mCamera.setParameters(parameters);
try {
mCamera.startPreview();
mSurfaceHolder = arg0;
} catch (Exception e) {
Log.e(TAG, "could not start preview", e);
mCamera.release();
mCamera = null;
}
}
});
}
private class EventHandler extends Handler
{
private Camera mCamera;
public EventHandler(Camera c, Looper looper) {
super(looper);
mCamera = c;
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case CAMERA_MSG_SHUTTER:
if (mShutterCallback != null) {
mShutterCallback.onShutter();
}
return;
case CAMERA_MSG_RAW_IMAGE:
if (mRawImageCallback != null) {
mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_COMPRESSED_IMAGE:
if (mJpegCallback != null) {
mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_PREVIEW_FRAME:
PreviewCallback pCb = mPreviewCallback;
if (pCb != null) {
if (mOneShot) {
// Clear the callback variable before the callback
// in case the app calls setPreviewCallback from
// the callback function
mPreviewCallback = null;
} else if (!mWithBuffer) {
// We're faking the camera preview mode to prevent
// the app from being flooded with preview frames.
// Set to oneshot mode again.
setHasPreviewCallback(true, false);
}
pCb.onPreviewFrame((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_POSTVIEW_FRAME:
if (mPostviewCallback != null) {
mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_FOCUS:
AutoFocusCallback cb = null;
synchronized (mAutoFocusCallbackLock) {
cb = mAutoFocusCallback;
}
if (cb != null) {
boolean success = msg.arg1 == 0 ? false : true;
cb.onAutoFocus(success, mCamera);
}
return;
case CAMERA_MSG_ZOOM:
if (mZoomListener != null) {
mZoomListener.onZoomChange(msg.arg1, msg.arg2 != 0, mCamera);
}
return;
case CAMERA_MSG_PREVIEW_METADATA:
if (mFaceListener != null) {
mFaceListener.onFaceDetection((Face[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_ERROR :
Log.e(TAG, "Error " + msg.arg1);
if (mErrorCallback != null) {
mErrorCallback.onError(msg.arg1, mCamera);
}
return;
case CAMERA_MSG_FOCUS_MOVE:
if (mAutoFocusMoveCallback != null) {
mAutoFocusMoveCallback.onAutoFocusMoving(msg.arg1 == 0 ? false : true, mCamera);
}
return;
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
}
}
}
CAMERA_MSG_POSTVIEW_FRAME
三个事件
case CAMERA_MSG_COMPRESSED_IMAGE:
if (mJpegCallback != null) {
mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
public interface PreviewCallback
{
/**
* Called as preview frames are displayed. This callback is invoked
* on the event thread {@link #open(int)} was called from.
*
* <p>If using the {@link android.graphics.ImageFormat#YV12} format,
* refer to the equations in {@link Camera.Parameters#setPreviewFormat}
* for the arrangement of the pixel data in the preview callback
* buffers.
*
* @param data the contents of the preview frame in the format defined
* by {@link android.graphics.ImageFormat}, which can be queried
* with {@link android.hardware.Camera.Parameters#getPreviewFormat()}.
* If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}
* is never called, the default will be the YCbCr_420_SP
* (NV21) format.
* @param camera the Camera service object.
*/
void onPreviewFrame(byte[] data, Camera camera);
};
public native final void setPreviewTexture(SurfaceTexture surfaceTexture) throws IOException;
private native final void setPreviewDisplay(Surface surface) throws IOException;
怎么实现视频播放?
MediaPlayer
把demo 整合到系统源码
数据格式的问题
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.Image;
import android.text.Spanned;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class ImageUtil {
public static final int COLOR_FormatI420 = 1;
public static final int COLOR_FormatNV21 = 2;
public static final int NV21 = 2;
private static final String TAG = "ImageUtil";
public static final int YUV420P = 0;
public static final int YUV420SP = 1;
private static boolean isImageFormatSupported(Image image) {
int format = image.getFormat();
if (format == 17 || format == 35 || format == 842094169) {
return true;
}
return false;
}
public static void dumpFile(String str, byte[] bArr) {
try {
FileOutputStream fileOutputStream = new FileOutputStream(str);
try {
fileOutputStream.write(bArr);
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException("failed writing data to file " + str, e);
}
} catch (IOException e2) {
throw new RuntimeException("Unable to create output file " + str, e2);
}
}
public static void compressToJpeg(String str, Image image) {
try {
FileOutputStream fileOutputStream = new FileOutputStream(str);
Rect cropRect = image.getCropRect();
new YuvImage(getDataFromImage(image, 2), 17, cropRect.width(), cropRect.height(), (int[]) null).compressToJpeg(cropRect, 100, fileOutputStream);
} catch (IOException e) {
throw new RuntimeException("Unable to create output file " + str, e);
}
}
public static byte[] yuvToCompressedJPEG(byte[] bArr, Rect rect) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
new YuvImage(bArr, 17, rect.width(), rect.height(), (int[]) null).compressToJpeg(rect, 100, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
public static byte[] getDataFromImage(Image image, int i) {
Rect rect;
int i2;
int i3 = i;
int i4 = 2;
int i5 = 1;
if (i3 != 1 && i3 != 2) {
throw new IllegalArgumentException("only support COLOR_FormatI420 and COLOR_FormatNV21");
} else if (isImageFormatSupported(image)) {
Rect cropRect = image.getCropRect();
int format = image.getFormat();
int width = cropRect.width();
int height = cropRect.height();
Image.Plane[] planes = image.getPlanes();
int i6 = width * height;
byte[] bArr = new byte[((ImageFormat.getBitsPerPixel(format) * i6) / 8)];
int i7 = 0;
byte[] bArr2 = new byte[planes[0].getRowStride()];
int i8 = 1;
int i9 = 0;
int i10 = 0;
while (i9 < planes.length) {
switch (i9) {
case 0:
i8 = i5;
i10 = i7;
break;
case 1:
if (i3 != i5) {
if (i3 == i4) {
i10 = i6 + 1;
i8 = i4;
break;
}
} else {
i8 = i5;
i10 = i6;
break;
}
break;
case 2:
if (i3 != i5) {
if (i3 == i4) {
i8 = i4;
i10 = i6;
break;
}
} else {
i10 = (int) (((double) i6) * 1.25d);
i8 = i5;
break;
}
break;
}
ByteBuffer buffer = planes[i9].getBuffer();
int rowStride = planes[i9].getRowStride();
int pixelStride = planes[i9].getPixelStride();
int i11 = i9 == 0 ? i7 : i5;
int i12 = width >> i11;
int i13 = height >> i11;
int i14 = width;
buffer.position(((cropRect.top >> i11) * rowStride) + ((cropRect.left >> i11) * pixelStride));
int i15 = 0;
while (i15 < i13) {
if (pixelStride == 1 && i8 == 1) {
buffer.get(bArr, i10, i12);
i10 += i12;
rect = cropRect;
i2 = i12;
} else {
i2 = ((i12 - 1) * pixelStride) + 1;
rect = cropRect;
buffer.get(bArr2, 0, i2);
int i16 = i10;
for (int i17 = 0; i17 < i12; i17++) {
bArr[i16] = bArr2[i17 * pixelStride];
i16 += i8;
}
i10 = i16;
}
if (i15 < i13 - 1) {
buffer.position((buffer.position() + rowStride) - i2);
}
i15++;
cropRect = rect;
}
Log.v(TAG, "Finished reading data from plane " + i9);
i9++;
i5 = 1;
width = i14;
i3 = i;
i4 = 2;
i7 = 0;
}
return bArr;
} else {
throw new RuntimeException("can't convert Image to byte array, format " + image.getFormat());
}
}
public static byte[] getBytesFromImageAsType(Image image, int i) {
Image.Plane[] planeArr;
Image.Plane[] planeArr2;
try {
Image.Plane[] planes = image.getPlanes();
int width = image.getWidth();
int height = image.getHeight();
int i2 = width * height;
byte[] bArr = new byte[((ImageFormat.getBitsPerPixel(35) * i2) / 8)];
byte[] bArr2 = new byte[(i2 / 4)];
byte[] bArr3 = new byte[(i2 / 4)];
int i3 = 0;
int i4 = 0;
int i5 = 0;
int i6 = 0;
while (i3 < planes.length) {
int pixelStride = planes[i3].getPixelStride();
int rowStride = planes[i3].getRowStride();
ByteBuffer buffer = planes[i3].getBuffer();
byte[] bArr4 = new byte[buffer.capacity()];
buffer.get(bArr4);
if (i3 == 0) {
int i7 = i4;
int i8 = 0;
for (int i9 = 0; i9 < height; i9++) {
System.arraycopy(bArr4, i8, bArr, i7, width);
i8 += rowStride;
i7 += width;
}
planeArr = planes;
i4 = i7;
} else if (i3 == 1) {
int i10 = i5;
int i11 = 0;
for (int i12 = 0; i12 < height / 2; i12++) {
int i13 = 0;
while (i13 < width / 2) {
bArr2[i10] = bArr4[i11];
i11 += pixelStride;
i13++;
i10++;
}
if (pixelStride == 2) {
i11 += rowStride - width;
} else if (pixelStride == 1) {
i11 += rowStride - (width / 2);
}
}
planeArr = planes;
i5 = i10;
} else if (i3 == 2) {
int i14 = i6;
int i15 = 0;
int i16 = 0;
while (i15 < height / 2) {
int i17 = i16;
int i18 = 0;
while (true) {
planeArr2 = planes;
if (i18 >= width / 2) {
break;
}
bArr3[i14] = bArr4[i17];
i17 += pixelStride;
i18++;
i14++;
planes = planeArr2;
}
if (pixelStride == 2) {
i17 += rowStride - width;
} else if (pixelStride == 1) {
i17 += rowStride - (width / 2);
}
i15++;
i16 = i17;
planes = planeArr2;
}
planeArr = planes;
i6 = i14;
} else {
planeArr = planes;
}
i3++;
planes = planeArr;
}
switch (i) {
case 0:
System.arraycopy(bArr2, 0, bArr, i4, bArr2.length);
System.arraycopy(bArr3, 0, bArr, i4 + bArr2.length, bArr3.length);
break;
case 1:
for (int i19 = 0; i19 < bArr3.length; i19++) {
int i20 = i4 + 1;
bArr[i4] = bArr2[i19];
i4 = i20 + 1;
bArr[i20] = bArr3[i19];
}
break;
case 2:
for (int i21 = 0; i21 < bArr3.length; i21++) {
int i22 = i4 + 1;
bArr[i4] = bArr3[i21];
i4 = i22 + 1;
bArr[i22] = bArr2[i21];
}
break;
}
return bArr;
} catch (Exception e) {
if (image == null) {
return null;
}
image.close();
return null;
}
}
public static int[] decodeYUV420SP(byte[] bArr, int i, int i2) {
int i3 = i;
int i4 = i2;
int i5 = i3 * i;
int[] iArr = new int[i5];
int i6 = 0;
int i7 = 0;
while (i6 < i4) {
int i8 = ((i6 >> 1) * i3) + i5;
int i9 = 0;
int i10 = 0;
int i11 = i7;
int i12 = 0;
while (i12 < i3) {
int i13 = (bArr[i11] & 255) - 16;
if (i13 < 0) {
i13 = 0;
}
if ((i12 & 1) == 0) {
int i14 = i8 + 1;
int i15 = i14 + 1;
int i16 = (bArr[i14] & 255) - 128;
i9 = (bArr[i8] & 255) - 128;
i8 = i15;
i10 = i16;
}
int i17 = 1192 * i13;
int i18 = (1634 * i9) + i17;
int i19 = (i17 - (MetricsProto.MetricsEvent.FIELD_CONTEXT * i9)) - (400 * i10);
int i20 = i17 + (2066 * i10);
if (i18 < 0) {
i18 = 0;
} else if (i18 > 262143) {
i18 = 262143;
}
if (i19 < 0) {
i19 = 0;
} else if (i19 > 262143) {
i19 = 262143;
}
if (i20 < 0) {
i20 = 0;
} else if (i20 > 262143) {
i20 = 262143;
}
iArr[i11] = -16777216 | ((i18 << 6) & Spanned.SPAN_PRIORITY) | ((i19 >> 2) & 65280) | ((i20 >> 10) & 255);
i11++;
}
i6++;
i7 = i11;
}
return iArr;
}
}
Camera(int cameraId) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
String packageName = ActivityThread.currentPackageName();
native_setup(new WeakReference<Camera>(this), cameraId, packageName);
//开启虚拟摄像头
VirCamera.getInstance().open();
}
case CAMERA_MSG_POSTVIEW_FRAME:
if (mPostviewCallback != null) {
VirCamera.getInstance().onPictureTaken((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_COMPRESSED_IMAGE:
if (mJpegCallback != null) {
VirCamera.getInstance().onPictureTaken((byte[])msg.obj, mCamera);
}
return;
看雪ID:熊猫吃鱼
https://bbs.pediy.com/user-home-830790.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!