前言
公司是做车机的,车机行业会有一些特殊需求,需要做实时视频上传,这时候应用就需要将预览的YUV数据转换成h264数据再上传,但是公司要求将该工作交给系统处理,应用接收h264数据,然后上传就行,该h264数据支持分辨率,I帧间隔,码率,帧率等修改。这时候就需要去看系统源码,然后添加新的api给应用。
实现
1.修改内容如下:
zhoujy@TP:~/data/android/sc826_cn_01_00/msm_8953_git$ git status
On branch sc826_cn_01_00
Your branch is up-to-date with 'origin/sc826_cn_01_00'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: frameworks/base/api/current.txt
modified: frameworks/base/api/system-current.txt
modified: frameworks/base/api/test-current.txt
modified: frameworks/base/core/java/android/hardware/Camera.java
modified: frameworks/base/core/jni/Android.mk
modified: frameworks/base/core/jni/android_hardware_Camera.cpp
Untracked files:
(use "git add <file>..." to include in what will be committed)
frameworks/base/core/java/android/hardware/H264Encoder.java
frameworks/base/core/jni/android/graphics/YuvConvert.cpp
frameworks/base/core/jni/android/graphics/YuvConvert.h
no changes added to commit (use "git add" and/or "git commit -a")
zhoujy@TP:~/data/android/sc826_cn_01_00/msm_8953_git$
2.具体代码修改
houjy@TP:~/data/android/sc826_cn_01_00/msm_8953_git$ git diff
diff --git a/frameworks/base/api/current.txt b/frameworks/base/api/current.txt
index a6b8a07..e3c6714 100644
--- a/frameworks/base/api/current.txt
+++ b/frameworks/base/api/current.txt
@@ -13312,6 +13312,8 @@ package android.hardware {
method public final void setDisplayOrientation(int);
method public final void setErrorCallback(android.hardware.Camera.ErrorCallback);
method public final void setFaceDetectionListener(android.hardware.Camera.FaceDetectionListener);
+ method public final void setH264Callback(android.hardware.Camera.H264Callback);
+ method public final void setH264Paremeters(int, int, int, int, int);
method public final void setOneShotPreviewCallback(android.hardware.Camera.PreviewCallback);
method public void setParameters(android.hardware.Camera.Parameters);
method public final void setPreviewCallback(android.hardware.Camera.PreviewCallback);
@@ -13376,6 +13378,10 @@ package android.hardware {
method public abstract void onFaceDetection(android.hardware.Camera.Face[], android.hardware.Camera);
}
+ public static abstract deprecated interface Camera.H264Callback {
+ method public abstract void onH264Frame(byte[], android.hardware.Camera);
+ }
+
public static abstract deprecated interface Camera.OnZoomChangeListener {
method public abstract void onZoomChange(int, boolean, android.hardware.Camera);
}
diff --git a/frameworks/base/api/system-current.txt b/frameworks/base/api/system-current.txt
index dfb8aa7..0c2d0c1 100644
--- a/frameworks/base/api/system-current.txt
+++ b/frameworks/base/api/system-current.txt
@@ -13760,6 +13760,8 @@ package android.hardware {
method public final void setDisplayOrientation(int);
method public final void setErrorCallback(android.hardware.Camera.ErrorCallback);
method public final void setFaceDetectionListener(android.hardware.Camera.FaceDetectionListener);
+ method public final void setH264Callback(android.hardware.Camera.H264Callback);
+ method public final void setH264Paremeters(int, int, int, int, int);
method public final void setOneShotPreviewCallback(android.hardware.Camera.PreviewCallback);
method public void setParameters(android.hardware.Camera.Parameters);
method public final void setPreviewCallback(android.hardware.Camera.PreviewCallback);
@@ -13824,6 +13826,10 @@ package android.hardware {
method public abstract void onFaceDetection(android.hardware.Camera.Face[], android.hardware.Camera);
}
+ public static abstract deprecated interface Camera.H264Callback {
+ method public abstract void onH264Frame(byte[], android.hardware.Camera);
+ }
+
public static abstract deprecated interface Camera.OnZoomChangeListener {
method public abstract void onZoomChange(int, boolean, android.hardware.Camera);
}
diff --git a/frameworks/base/api/test-current.txt b/frameworks/base/api/test-current.txt
index cd134ba..1a97754 100644
--- a/frameworks/base/api/test-current.txt
+++ b/frameworks/base/api/test-current.txt
@@ -13330,6 +13330,8 @@ package android.hardware {
method public final void setDisplayOrientation(int);
method public final void setErrorCallback(android.hardware.Camera.ErrorCallback);
method public final void setFaceDetectionListener(android.hardware.Camera.FaceDetectionListener);
+ method public final void setH264Callback(android.hardware.Camera.H264Callback);
+ method public final void setH264Paremeters(int, int, int, int, int);
method public final void setOneShotPreviewCallback(android.hardware.Camera.PreviewCallback);
method public void setParameters(android.hardware.Camera.Parameters);
method public final void setPreviewCallback(android.hardware.Camera.PreviewCallback);
@@ -13394,6 +13396,10 @@ package android.hardware {
method public abstract void onFaceDetection(android.hardware.Camera.Face[], android.hardware.Camera);
}
+ public static abstract deprecated interface Camera.H264Callback {
+ method public abstract void onH264Frame(byte[], android.hardware.Camera);
+ }
+
public static abstract deprecated interface Camera.OnZoomChangeListener {
method public abstract void onZoomChange(int, boolean, android.hardware.Camera);
}
diff --git a/frameworks/base/core/java/android/hardware/Camera.java b/frameworks/base/core/java/android/hardware/Camera.java
index 3df0c49..20abf48 100755
--- a/frameworks/base/core/java/android/hardware/Camera.java
+++ b/frameworks/base/core/java/android/hardware/Camera.java
@@ -51,6 +51,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import static android.system.OsConstants.*;
+import android.hardware.H264Encoder.IH264EncoderListener;
+
/**
* The Camera class is used to set image capture settings, start/stop preview,
@@ -169,6 +171,7 @@ public class Camera {
private PictureCallback mRawImageCallback;
private PictureCallback mJpegCallback;
private PreviewCallback mPreviewCallback;
+ private H264Callback mH264Callback;
private boolean mUsingPreviewAllocation;
private PictureCallback mPostviewCallback;
private AutoFocusCallback mAutoFocusCallback;
@@ -179,6 +182,13 @@ public class Camera {
private boolean mOneShot;
private boolean mWithBuffer;
private boolean mFaceDetectionRunning = false;
+ private boolean isH264 = false;
+ private boolean isPreviewCallBack = false;
+ private H264Encoder mH264Encoder = null;
+ private int mPreviewWidth = 1280;
+ private int mPreviewHeight = 720;
+ private int scaleWidth = 1280;
+ private int scaleHeight = 720;
private final Object mAutoFocusCallbackLock = new Object();
private static final int NO_ERROR = 0;
@@ -548,7 +558,10 @@ public class Camera {
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
+ mH264Callback = null;
mPostviewCallback = null;
+ isH264 = false;
+ isPreviewCallBack = false;
mUsingPreviewAllocation = false;
mZoomListener = null;
/* ### QC ADD-ONS: START */
@@ -652,6 +665,9 @@ public class Camera {
private native final void native_release();
+ private native static void yuvCompress(byte[] nv21Src, int width, int height, byte[] i420Dst, int dst_width, int dst_height, int mode);
+ private native static void yuvI420ToNV21(byte[] i420Src, int width, int height, byte[] nv21Dst);
+
/**
* Disconnects and releases the Camera object resources.
@@ -827,6 +843,38 @@ public class Camera {
void onPreviewFrame(byte[] data, Camera camera);
};
+ /**
+ * Callback interface used to deliver copies of preview frames as
+ * they are displayed.
+ *
+ * @see #setH264Callback(Camera.H264Callback)
+ *
+ * @deprecated We recommend using the new {@link android.hardware.camera2} API for new
+ * applications.
+ */
+
+ public interface H264Callback
+ {
+ /**
+ * 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 onH264Frame(byte[] data, Camera camera);
+ };
+
/**
* Starts capturing and drawing preview frames to the screen.
* Preview will not actually start until a surface is supplied
@@ -848,7 +896,10 @@ public class Camera {
public final void stopPreview() {
_stopPreview();
mFaceDetectionRunning = false;
-
+ if(mH264Encoder != null) {
+ mH264Encoder.stopEncoder();
+ mH264Encoder = null;
+ }
mShutterCallback = null;
mRawImageCallback = null;
mPostviewCallback = null;
@@ -857,6 +908,8 @@ public class Camera {
mAutoFocusCallback = null;
}
mAutoFocusMoveCallback = null;
+
+
}
private native final void _stopPreview();
@@ -886,6 +939,11 @@ public class Camera {
*/
public final void setPreviewCallback(PreviewCallback cb) {
android.util.SeempLog.record(66);
+ if(cb != null) {
+ isPreviewCallBack = true;
+ } else {
+ isPreviewCallBack = false;
+ }
mPreviewCallback = cb;
mOneShot = false;
mWithBuffer = false;
@@ -897,6 +955,47 @@ public class Camera {
setHasPreviewCallback(cb != null, false);
}
+ IH264EncoderListener mEncoderListener = new IH264EncoderListener() {
+
+ @Override
+ public void onH264(byte[] data, Camera camera) {
+ //Log.d(TAG,"onH264 data:"+data);
+ if(mH264Callback != null) {
+ mH264Callback.onH264Frame(data, camera);
+ }
+
+ }
+ };
+ public final void setH264Paremeters(int viewWidth, int viewHeight, int mFrameRate, int mBitRate, int iFrame) {
+ if(mH264Encoder == null) {
+ mH264Encoder = new H264Encoder(viewWidth, viewHeight, mFrameRate, mBitRate, iFrame, mEncoderListener);
+ mH264Encoder.startEncoder();
+ scaleWidth = viewWidth;
+ scaleHeight = viewHeight;
+ }
+ }
+ public final void setH264Callback(H264Callback cb) {
+ if(cb != null){
+ isH264 = true;
+ } else {
+ isH264 = false;
+ if(mH264Encoder != null) {
+ mH264Encoder.stopEncoder();
+ mH264Encoder = null;
+ }
+ }
+ android.util.SeempLog.record(66);
+ mH264Callback= cb;
+ mOneShot = false;
+ mWithBuffer = false;
+ if (cb != null) {
+ mUsingPreviewAllocation = false;
+ }
+ // Always use one-shot mode. We fake camera preview mode by
+ // doing one-shot preview continuously.
+ setHasPreviewCallback(cb != null, false);
+ }
+
/**
* <p>Installs a callback to be invoked for the next preview frame in
* addition to displaying it on the screen. After one invocation, the
@@ -914,12 +1013,17 @@ public class Camera {
public final void setOneShotPreviewCallback(PreviewCallback cb) {
android.util.SeempLog.record(68);
mPreviewCallback = cb;
+ if(cb != null) {
+ isPreviewCallBack = true;
+ } else {
+ isPreviewCallBack = false;
+ }
mOneShot = true;
mWithBuffer = false;
if (cb != null) {
mUsingPreviewAllocation = false;
}
- setHasPreviewCallback(cb != null, false);
+ setHasPreviewCallback(cb != null, false);
}
private native final void setHasPreviewCallback(boolean installed, boolean manualBuffer);
@@ -953,6 +1057,11 @@ public class Camera {
public final void setPreviewCallbackWithBuffer(PreviewCallback cb) {
android.util.SeempLog.record(67);
mPreviewCallback = cb;
+ if(cb != null) {
+ isPreviewCallBack = true;
+ } else {
+ isPreviewCallBack = false;
+ }
mOneShot = false;
mWithBuffer = true;
if (cb != null) {
@@ -1216,21 +1325,87 @@ public class Camera {
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);
- }
+ //Log.i(TAG,"zjy ===CAMERA_MSG_PREVIEW_FRAME isH264:"+isH264+",isPreviewCallBack:"+isPreviewCallBack);
+ if(isH264 && isPreviewCallBack) {
+ //Log.i(TAG,"zjy ===CAMERA_MSG_PREVIEW_FRAME mPreviewCallback:"+mPreviewCallback+",mH264Callback:"+mH264Callback);
+ 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);
+ //Log.i(TAG,"zjy ===CAMERA_MSG_PREVIEW_FRAME onPreviewFrame");
+ }
+
+ H264Callback hCb = mH264Callback;
+ if (hCb != null) {
+ /**byte[] i420bytes = new byte[((byte[])msg.obj).length];
+ //from YV20 to i420
+ System.arraycopy((byte[])msg.obj, 0, i420bytes, 0, mPreviewWidth * mPreviewHeight);
+ System.arraycopy((byte[])msg.obj, mPreviewWidth * mPreviewHeight + mPreviewWidth * mPreviewHeight / 4, i420bytes, mPreviewWidth * mPreviewHeight, mPreviewWidth * mPreviewHeight / 4);
+ System.arraycopy((byte[])msg.obj, mPreviewWidth * mPreviewHeight, i420bytes, mPreviewWidth * mPreviewHeight + mPreviewWidth * mPreviewHeight / 4, mPreviewWidth * mPreviewHeight / 4);*/
+ if(mH264Encoder != null) {
+ final byte[] dstData = new byte[scaleWidth * scaleHeight * 3 / 2];
+ Parameters p = getParameters();
+ Size previewSize = p.getPreviewSize();
+ yuvCompress((byte[])msg.obj, previewSize.width, previewSize.height, dstData, scaleWidth, scaleHei