mirror of
https://github.com/defold/extension-camera
synced 2025-06-28 10:57:43 +02:00
First version of Android camera
This commit is contained in:
parent
57ef591ca0
commit
5fd504cc14
141
AndroidManifest.xml
Normal file
141
AndroidManifest.xml
Normal file
@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- BEGIN_INCLUDE(manifest) -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="{{android.package}}"
|
||||
android:versionCode="{{android.version_code}}"
|
||||
android:versionName="{{project.version}}"
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-feature android:required="true" android:glEsVersion="0x00020000" />
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="22" />
|
||||
<application
|
||||
{{#has-icons?}}
|
||||
android:icon="@drawable/icon"
|
||||
{{/has-icons?}}
|
||||
android:label="{{project.title}}" android:hasCode="true" android:debuggable="false">
|
||||
|
||||
<!-- For Local Notifications -->
|
||||
<receiver android:name="com.defold.push.LocalNotificationReceiver" >
|
||||
</receiver>
|
||||
|
||||
<!-- For GCM (push) -->
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
<!-- For Facebook -->
|
||||
<meta-data android:name="com.facebook.sdk.ApplicationName"
|
||||
android:value="{{project.title}}" />
|
||||
|
||||
<activity android:name="com.dynamo.android.DefoldActivity"
|
||||
android:label="{{project.title}}"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:screenOrientation="{{orientation-support}}"
|
||||
android:launchMode="singleTask">
|
||||
<meta-data android:name="android.app.lib_name"
|
||||
android:value="{{exe-name}}" />
|
||||
{{#android.push_field_title}}
|
||||
<meta-data
|
||||
android:name="com.defold.push.field_title"
|
||||
android:value="{{android.push_field_title}}" />
|
||||
{{/android.push_field_title}}
|
||||
{{#android.push_field_text}}
|
||||
<meta-data
|
||||
android:name="com.defold.push.field_text"
|
||||
android:value="{{android.push_field_text}}" />
|
||||
{{/android.push_field_text}}
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.dynamo.android.DispatcherActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||
<activity android:name="com.facebook.FacebookActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
|
||||
android:label="{{project.title}}" />
|
||||
<activity android:name="com.defold.iap.IapGooglePlayActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
|
||||
android:label="IAP">
|
||||
</activity>
|
||||
|
||||
<!-- For Local Notifications -->
|
||||
<activity android:name="com.defold.push.LocalPushDispatchActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize">
|
||||
<intent-filter>
|
||||
<action android:name="com.defold.push.FORWARD" />
|
||||
<category android:name="com.defold.push" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- For GCM (push) -->
|
||||
<activity android:name="com.defold.push.PushDispatchActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="com.defold.push.FORWARD" />
|
||||
<category android:name="com.defold.push" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<receiver
|
||||
android:name="com.defold.push.GcmBroadcastReceiver"
|
||||
android:permission="com.google.android.c2dm.permission.SEND" >
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
<action android:name="com.defold.push.FORWARD" />
|
||||
<category android:name="com.defold.push" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- For IAC Invocations -->
|
||||
<activity android:name="com.defold.iac.IACActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="{{android.package}}" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service android:name="com.defold.adtruth.InstallReceiver"/>
|
||||
<receiver
|
||||
android:name="com.defold.adtruth.InstallReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.vending.INSTALL_REFERRER" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- For Amazon IAP -->
|
||||
<receiver android:name="com.amazon.device.iap.ResponseReceiver" >
|
||||
<intent-filter>
|
||||
<action android:name="com.amazon.inapp.purchasing.NOTIFY" android:permission="com.amazon.inapp.purchasing.Permission.NOTIFY" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- For GCM (push) -->
|
||||
<!-- NOTE: Package name from actual app here! -->
|
||||
<permission android:name="{{android.package}}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<!-- NOTE: Package name from actual app here! -->
|
||||
<uses-permission android:name="{{android.package}}.permission.C2D_MESSAGE" />
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
</manifest>
|
||||
<!-- END_INCLUDE(manifest) -->
|
11
README.md
11
README.md
@ -44,7 +44,7 @@ Returns true if the capture starts well
|
||||
if camera.start_capture(camera.CAMERA_TYPE_BACK, camera.CAPTURE_QUALITY_HIGH) then
|
||||
-- do stuff
|
||||
end
|
||||
|
||||
|
||||
## camera.stop_capture()
|
||||
|
||||
Stops a previously started capture session
|
||||
@ -56,12 +56,15 @@ Gets the info from the current capture session
|
||||
local info = camera.get_info()
|
||||
print("width", info.width)
|
||||
print("height", info.height)
|
||||
|
||||
|
||||
## camera.get_frame()
|
||||
|
||||
Retrieves the camera pixel buffer
|
||||
This buffer has one stream named "rgb", and is of type buffer.VALUE_TYPE_UINT8 and has the value count of 1
|
||||
|
||||
self.cameraframe = camera.get_frame()
|
||||
|
||||
|
||||
|
||||
|
||||
# Credits
|
||||
|
||||
The android version was based on the code from: https://github.com/necula/native-camera
|
||||
|
30
camera/src/android/Camera.h
Normal file
30
camera/src/android/Camera.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
class Camera
|
||||
{
|
||||
public:
|
||||
typedef void (*FrameUpdateCallback)(void* priv, void* data, int width, int height, int numChannels);
|
||||
typedef void (*PhotoSavedCallback)(void* priv, bool success);
|
||||
|
||||
virtual ~Camera();
|
||||
|
||||
static Camera* GetCamera(void* callbackData, FrameUpdateCallback frameUpdateCB, PhotoSavedCallback photoSavedCB);
|
||||
//static Vector2 GetFrameSize();
|
||||
static int GetFrameWidth();
|
||||
static int GetFrameHeight();
|
||||
|
||||
virtual bool Initialize() = 0;
|
||||
virtual void Deinitialize() = 0;
|
||||
virtual bool Start() = 0;
|
||||
virtual void Stop() = 0;
|
||||
virtual void Update() = 0;
|
||||
//virtual void TakePhoto(const char* path) = 0;
|
||||
//virtual void SetFocusPoint(const Vector2& focusPoint) = 0;
|
||||
|
||||
FrameUpdateCallback m_frameUpdateCB;
|
||||
PhotoSavedCallback m_photoSavedCB;
|
||||
void* m_callbackData;
|
||||
|
||||
//bool m_takePhoto;
|
||||
//std::string m_photoPath;
|
||||
};
|
224
camera/src/android/Camera.java
Normal file
224
camera/src/android/Camera.java
Normal file
@ -0,0 +1,224 @@
|
||||
package com.defold.android.camera;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.CameraInfo;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.SurfaceTexture; // API 11
|
||||
|
||||
import android.view.Surface;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
class AndroidCamera
|
||||
{
|
||||
public Camera camera;
|
||||
public SurfaceTexture surface;
|
||||
public boolean newFrame;
|
||||
|
||||
public static String photoPath;
|
||||
|
||||
public static Context context;
|
||||
|
||||
static native void frameUpdate(int[] data);
|
||||
static native void photoSaved(long callbackData, boolean success);
|
||||
|
||||
public long callbackData;
|
||||
|
||||
|
||||
public static AndroidCamera getCamera(Context _context)
|
||||
{
|
||||
context = _context;
|
||||
AndroidCamera mc = new AndroidCamera();
|
||||
return mc;
|
||||
}
|
||||
|
||||
public AndroidCamera()
|
||||
{
|
||||
init(context);
|
||||
}
|
||||
|
||||
public void setCallbackData(long callbackData)
|
||||
{
|
||||
this.callbackData = callbackData;
|
||||
}
|
||||
|
||||
public void init(final Context context)
|
||||
{
|
||||
surface = new SurfaceTexture(0);
|
||||
|
||||
CameraInfo info = new CameraInfo();
|
||||
int cameraId = -1;
|
||||
int numberOfCameras = Camera.getNumberOfCameras();
|
||||
|
||||
for(int i = 0; i < numberOfCameras; i++)
|
||||
{
|
||||
Camera.getCameraInfo(i, info);
|
||||
if(info.facing == CameraInfo.CAMERA_FACING_BACK)
|
||||
{
|
||||
cameraId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(cameraId == -1)
|
||||
return;
|
||||
|
||||
camera = Camera.open(cameraId);
|
||||
|
||||
Camera.Parameters params = camera.getParameters();
|
||||
params.setPreviewSize(640, 480);
|
||||
params.setPictureSize(640, 480);
|
||||
params.setPictureFormat(PixelFormat.JPEG);
|
||||
params.setJpegQuality(90);
|
||||
camera.setParameters(params);
|
||||
|
||||
final Activity activity = (Activity)context;
|
||||
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
|
||||
|
||||
camera.setPreviewCallback(new PreviewCallback() {
|
||||
public void onPreviewFrame(byte[] data, Camera arg1) {
|
||||
|
||||
boolean flip = false;
|
||||
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();;
|
||||
|
||||
if(rotation == Surface.ROTATION_180 || rotation == Surface.ROTATION_270)
|
||||
flip = true;
|
||||
|
||||
int[] pixels = convertYUV420_NV21toARGB8888(data, 640, 480, flip);
|
||||
frameUpdate(pixels);
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
camera.setPreviewTexture(surface);
|
||||
}
|
||||
catch(IOException ioe)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/*public void takePhoto(final String photoPath)
|
||||
{
|
||||
camera.takePicture(null, null, new PictureCallback() {
|
||||
public void onPictureTaken(byte [] rawData, Camera camera) {
|
||||
try {
|
||||
if (rawData != null) {
|
||||
int rawDataLength = rawData.length;
|
||||
|
||||
String dirStr = "";
|
||||
int pos = photoPath.lastIndexOf("/", photoPath.length() - 1);
|
||||
if(pos == -1)
|
||||
return;
|
||||
dirStr = photoPath.substring(0, pos);
|
||||
|
||||
File dir = new File(dirStr);
|
||||
dir.mkdirs();
|
||||
|
||||
File rawoutput = new File(photoPath);
|
||||
rawoutput.createNewFile();
|
||||
FileOutputStream outstream = new FileOutputStream(rawoutput);
|
||||
|
||||
boolean flip = false;
|
||||
int rotation = Utils.getRotation();
|
||||
if(rotation == Surface.ROTATION_180 || rotation == Surface.ROTATION_270)
|
||||
flip = true;
|
||||
if(flip)
|
||||
{
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(rawData, 0, rawData.length);
|
||||
ByteArrayOutputStream rotatedStream = new ByteArrayOutputStream();
|
||||
|
||||
// Rotate the Bitmap
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(180);
|
||||
|
||||
// We rotate the same Bitmap
|
||||
bitmap = Bitmap.createBitmap(bitmap, 0, 0, 640, 480, matrix, false);
|
||||
|
||||
// We dump the rotated Bitmap to the stream
|
||||
bitmap.compress(CompressFormat.JPEG, 90, rotatedStream);
|
||||
|
||||
rawData = rotatedStream.toByteArray();
|
||||
}
|
||||
|
||||
outstream.write(rawData);
|
||||
|
||||
photoSaved(callbackData, true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w("", "[CAMERA] takePhoto error " + e.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}*/
|
||||
|
||||
public void startPreview()
|
||||
{
|
||||
if(camera == null)
|
||||
init(context);
|
||||
camera.startPreview();
|
||||
}
|
||||
|
||||
public void stopPreview()
|
||||
{
|
||||
camera.stopPreview();
|
||||
camera.release();
|
||||
camera = null;
|
||||
}
|
||||
|
||||
public static int[] convertYUV420_NV21toARGB8888(byte [] data, int width, int height, boolean flip) {
|
||||
int size = width*height;
|
||||
int offset = size;
|
||||
int[] pixels = new int[size];
|
||||
int u, v, y1, y2, y3, y4;
|
||||
|
||||
int startPos = 0;
|
||||
int helperIdx = -1;
|
||||
if(flip)
|
||||
{
|
||||
startPos = size - 1;
|
||||
helperIdx = 1;
|
||||
}
|
||||
|
||||
// i along Y and the final pixels
|
||||
// k along pixels U and V
|
||||
for(int i=0, k=0; i < size; i+=2, k+=2) {
|
||||
y1 = data[i ]&0xff;
|
||||
y2 = data[i+1]&0xff;
|
||||
y3 = data[width+i ]&0xff;
|
||||
y4 = data[width+i+1]&0xff;
|
||||
|
||||
v = data[offset+k ]&0xff;
|
||||
u = data[offset+k+1]&0xff;
|
||||
v = v-128;
|
||||
u = u-128;
|
||||
|
||||
pixels[startPos - helperIdx*i ] = convertYUVtoARGB(y1, u, v);
|
||||
pixels[startPos - helperIdx*(i+1)] = convertYUVtoARGB(y2, u, v);
|
||||
pixels[startPos - helperIdx*(width+i) ] = convertYUVtoARGB(y3, u, v);
|
||||
pixels[startPos - helperIdx*(width+i+1)] = convertYUVtoARGB(y4, u, v);
|
||||
|
||||
if (i!=0 && (i+2)%width==0)
|
||||
i += width;
|
||||
}
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
// Alt: https://github.com/Jaa-c/android-camera-demo/blob/master/src/com/jaa/camera/CameraSurfaceView.java
|
||||
private static int convertYUVtoARGB(int y, int u, int v) {
|
||||
int r = y + (int)(1.772f*v);
|
||||
int g = y - (int)(0.344f*v + 0.714f*u);
|
||||
int b = y + (int)(1.402f*u);
|
||||
r = r>255? 255 : r<0 ? 0 : r;
|
||||
g = g>255? 255 : g<0 ? 0 : g;
|
||||
b = b>255? 255 : b<0 ? 0 : b;
|
||||
return 0xff000000 | r | (g<<8) | (b<<16);
|
||||
}
|
||||
};
|
256
camera/src/android/CameraAndroid.cpp
Normal file
256
camera/src/android/CameraAndroid.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
#include "Camera.h"
|
||||
#include <dmsdk/sdk.h> // dmGraphics::GetNativeAndroidActivity()
|
||||
|
||||
static jclass g_cameraClass = 0;
|
||||
static jmethodID g_initMethodId = 0;
|
||||
static jmethodID g_startPreviewMethodId = 0;
|
||||
static jmethodID g_stopPreviewMethodId = 0;
|
||||
static jmethodID g_takePhotoMethodId = 0;
|
||||
static jmethodID g_getCameraMethodId = 0;
|
||||
static jmethodID g_setCallbackDataMethodId = 0;
|
||||
static jobject g_cameraObject = 0;
|
||||
|
||||
static jint g_data[640*480];
|
||||
static bool g_frameLock = false;
|
||||
|
||||
class PCamera : public Camera
|
||||
{
|
||||
public:
|
||||
|
||||
enum PhotoSavedState
|
||||
{
|
||||
PhotoSaved_Failed,
|
||||
PhotoSaved_OK,
|
||||
PhotoSaved_Waiting
|
||||
};
|
||||
|
||||
PCamera();
|
||||
virtual ~PCamera();
|
||||
|
||||
bool Initialize();
|
||||
void Deinitialize();
|
||||
bool Start();
|
||||
void Stop();
|
||||
void Update();
|
||||
//void TakePhoto(const char* path);
|
||||
//void SetFocusPoint(const Vector2& focusPoint);
|
||||
|
||||
void PhotoSavedCB(bool success);
|
||||
|
||||
|
||||
private:
|
||||
bool m_initialized;
|
||||
PhotoSavedState m_photoSavedState;
|
||||
};
|
||||
|
||||
PCamera::PCamera()
|
||||
{
|
||||
m_initialized = false;
|
||||
//m_takePhoto = false;
|
||||
m_photoSavedState = PhotoSaved_Waiting;
|
||||
}
|
||||
|
||||
PCamera::~PCamera()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static JNIEnv* Attach()
|
||||
{
|
||||
JNIEnv* env;
|
||||
JavaVM* vm = dmGraphics::GetNativeAndroidJavaVM();
|
||||
vm->AttachCurrentThread(&env, NULL);
|
||||
return env;
|
||||
}
|
||||
|
||||
static bool Detach(JNIEnv* env)
|
||||
{
|
||||
bool exception = (bool) env->ExceptionCheck();
|
||||
env->ExceptionClear();
|
||||
JavaVM* vm = dmGraphics::GetNativeAndroidJavaVM();
|
||||
vm->DetachCurrentThread();
|
||||
return !exception;
|
||||
}
|
||||
|
||||
static jclass GetClass(JNIEnv* env, const char* classname)
|
||||
{
|
||||
jclass activity_class = env->FindClass("android/app/NativeActivity");
|
||||
jmethodID get_class_loader = env->GetMethodID(activity_class,"getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
jobject cls = env->CallObjectMethod(dmGraphics::GetNativeAndroidActivity(), get_class_loader);
|
||||
jclass class_loader = env->FindClass("java/lang/ClassLoader");
|
||||
jmethodID find_class = env->GetMethodID(class_loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
|
||||
jstring str_class_name = env->NewStringUTF(classname);
|
||||
jclass outcls = (jclass)env->CallObjectMethod(cls, find_class, str_class_name);
|
||||
env->DeleteLocalRef(str_class_name);
|
||||
return outcls;
|
||||
}
|
||||
|
||||
bool PCamera::Initialize()
|
||||
{
|
||||
JNIEnv* env = Attach();
|
||||
if(!env)
|
||||
return false;
|
||||
|
||||
if(!g_cameraClass)
|
||||
{
|
||||
jclass tmp = GetClass(env, "com.defold.android.camera/AndroidCamera");
|
||||
g_cameraClass = (jclass)env->NewGlobalRef(tmp);
|
||||
if(!g_cameraClass)
|
||||
{
|
||||
dmLogError("Could not find class 'com.defold.android.camera/AndroidCamera'.");
|
||||
Detach(env);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!g_getCameraMethodId)
|
||||
{
|
||||
g_getCameraMethodId = env->GetStaticMethodID(g_cameraClass, "getCamera", "(Landroid/content/Context;)Lcom/defold/android/camera/AndroidCamera;");
|
||||
if(!g_getCameraMethodId)
|
||||
{
|
||||
dmLogError("Could not get static method 'getCamera'.");
|
||||
Detach(env);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!g_cameraObject)
|
||||
{
|
||||
jobject tmp1 = env->CallStaticObjectMethod(g_cameraClass, g_getCameraMethodId, dmGraphics::GetNativeAndroidActivity());
|
||||
g_cameraObject = (jobject)env->NewGlobalRef(tmp1);
|
||||
}
|
||||
|
||||
if(!g_startPreviewMethodId)
|
||||
g_startPreviewMethodId = env->GetMethodID(g_cameraClass, "startPreview", "()V");
|
||||
assert(g_startPreviewMethodId);
|
||||
|
||||
if(!g_stopPreviewMethodId)
|
||||
g_stopPreviewMethodId = env->GetMethodID(g_cameraClass, "stopPreview", "()V");
|
||||
assert(g_stopPreviewMethodId);
|
||||
|
||||
// if(!g_takePhotoMethodId)
|
||||
// g_takePhotoMethodId = env->GetMethodID(g_cameraClass, "takePhoto", "(Ljava/lang/String;)V");
|
||||
// assert(g_takePhotoMethodId);
|
||||
|
||||
if(!g_setCallbackDataMethodId)
|
||||
g_setCallbackDataMethodId = env->GetMethodID(g_cameraClass, "setCallbackData", ("(J)V"));
|
||||
assert(g_setCallbackDataMethodId);
|
||||
|
||||
env->CallVoidMethod(g_cameraObject, g_setCallbackDataMethodId, (long long)this);
|
||||
|
||||
m_initialized = true;
|
||||
Detach(env);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PCamera::Deinitialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool PCamera::Start()
|
||||
{
|
||||
JNIEnv* env = Attach();
|
||||
env->CallVoidMethod(g_cameraObject, g_startPreviewMethodId);
|
||||
Detach(env);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PCamera::Stop()
|
||||
{
|
||||
JNIEnv* env = Attach();
|
||||
env->CallVoidMethod(g_cameraObject, g_stopPreviewMethodId);
|
||||
Detach(env);
|
||||
}
|
||||
|
||||
void PCamera::Update()
|
||||
{
|
||||
if(!m_initialized && !Initialize())
|
||||
return;
|
||||
|
||||
if(g_frameLock)
|
||||
{
|
||||
m_frameUpdateCB(m_callbackData, (void*)g_data, 640, 480, 4);
|
||||
g_frameLock = false;
|
||||
}
|
||||
|
||||
// if(m_takePhoto)
|
||||
// {
|
||||
// if(m_photoSavedState != PhotoSaved_Waiting)
|
||||
// {
|
||||
// m_takePhoto = false;
|
||||
// m_photoSavedState = PhotoSaved_Waiting;
|
||||
|
||||
// m_photoSavedCB(m_callbackData, m_photoSavedState);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// void PCamera::TakePhoto(const char* path)
|
||||
// {
|
||||
// m_takePhoto = true;
|
||||
|
||||
// jstring jPath = g_env->NewStringUTF(path);
|
||||
// g_env->CallVoidMethod(g_cameraObject, g_takePhotoMethodId, jPath);
|
||||
// g_env->DeleteLocalRef(jPath);
|
||||
// }
|
||||
|
||||
// void PCamera::SetFocusPoint(const Vector2& focusPoint)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
void PCamera::PhotoSavedCB(bool success)
|
||||
{
|
||||
m_photoSavedState = success ? PhotoSaved_OK : PhotoSaved_Failed;
|
||||
}
|
||||
|
||||
Camera* Camera::GetCamera(void* callbackData, FrameUpdateCallback frameUpdateCB, PhotoSavedCallback photoSavedCB)
|
||||
{
|
||||
PCamera *camera = new PCamera;
|
||||
if(!camera)
|
||||
return 0;
|
||||
|
||||
camera->m_frameUpdateCB = frameUpdateCB;
|
||||
camera->m_photoSavedCB = photoSavedCB;
|
||||
camera->m_callbackData = callbackData;
|
||||
|
||||
return camera;
|
||||
}
|
||||
|
||||
Camera::~Camera()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Vector2 Camera::GetFrameSize()
|
||||
// {
|
||||
// return Vector2(640, 480);
|
||||
// }
|
||||
|
||||
|
||||
int Camera::GetFrameWidth() { return 640; }
|
||||
int Camera::GetFrameHeight() { return 480; }
|
||||
|
||||
extern "C"
|
||||
{
|
||||
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_frameUpdate(JNIEnv * env, jobject jobj, jintArray data);
|
||||
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_photoSaved(JNIEnv * env, jobject jobj, jlong callbackData, jboolean success);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_frameUpdate(JNIEnv * env, jobject jobj, jintArray data)
|
||||
{
|
||||
if(!g_frameLock)
|
||||
{
|
||||
env->GetIntArrayRegion(data, 0, 640*480, g_data);
|
||||
g_frameLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_photoSaved(JNIEnv * env, jobject jobj, jlong callbackData, jboolean success)
|
||||
{
|
||||
PCamera* c = (PCamera*)callbackData;
|
||||
if(c)
|
||||
c->PhotoSavedCB(success);
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
#define DLIB_LOG_DOMAIN LIB_NAME
|
||||
#include <dmsdk/sdk.h>
|
||||
|
||||
#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_OSX)
|
||||
#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_OSX) || defined(DM_PLATFORM_ANDROID)
|
||||
|
||||
#include "camera_private.h"
|
||||
|
||||
@ -94,7 +94,7 @@ static int GetInfo(lua_State* L)
|
||||
static int GetFrame(lua_State* L)
|
||||
{
|
||||
DM_LUA_STACK_CHECK(L, 1);
|
||||
lua_rawgeti(L,LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef);
|
||||
lua_rawgeti(L,LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -130,23 +130,29 @@ static void LuaInit(lua_State* L)
|
||||
assert(top == lua_gettop(L));
|
||||
}
|
||||
|
||||
dmExtension::Result AppInitializeCamera(dmExtension::AppParams* params)
|
||||
static dmExtension::Result AppInitializeCamera(dmExtension::AppParams* params)
|
||||
{
|
||||
return dmExtension::RESULT_OK;
|
||||
}
|
||||
|
||||
dmExtension::Result InitializeCamera(dmExtension::Params* params)
|
||||
static dmExtension::Result InitializeCamera(dmExtension::Params* params)
|
||||
{
|
||||
LuaInit(params->m_L);
|
||||
return dmExtension::RESULT_OK;
|
||||
}
|
||||
|
||||
dmExtension::Result AppFinalizeCamera(dmExtension::AppParams* params)
|
||||
static dmExtension::Result UpdateCamera(dmExtension::Params* params)
|
||||
{
|
||||
CameraPlatform_UpdateCapture();
|
||||
return dmExtension::RESULT_OK;
|
||||
}
|
||||
|
||||
static dmExtension::Result AppFinalizeCamera(dmExtension::AppParams* params)
|
||||
{
|
||||
return dmExtension::RESULT_OK;
|
||||
}
|
||||
|
||||
dmExtension::Result FinalizeCamera(dmExtension::Params* params)
|
||||
static dmExtension::Result FinalizeCamera(dmExtension::Params* params)
|
||||
{
|
||||
return dmExtension::RESULT_OK;
|
||||
}
|
||||
@ -165,6 +171,11 @@ static dmExtension::Result InitializeCamera(dmExtension::Params* params)
|
||||
return dmExtension::RESULT_OK;
|
||||
}
|
||||
|
||||
static dmExtension::Result UpdateCamera(dmExtension::Params* params)
|
||||
{
|
||||
return dmExtension::RESULT_OK;
|
||||
}
|
||||
|
||||
static dmExtension::Result AppFinalizeCamera(dmExtension::AppParams* params)
|
||||
{
|
||||
return dmExtension::RESULT_OK;
|
||||
@ -178,4 +189,4 @@ static dmExtension::Result FinalizeCamera(dmExtension::Params* params)
|
||||
#endif // platforms
|
||||
|
||||
|
||||
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeCamera, AppFinalizeCamera, InitializeCamera, 0, 0, FinalizeCamera)
|
||||
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeCamera, AppFinalizeCamera, InitializeCamera, UpdateCamera, 0, FinalizeCamera)
|
||||
|
116
camera/src/camera_android.cpp
Normal file
116
camera/src/camera_android.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include <dmsdk/sdk.h>
|
||||
#include "camera_private.h"
|
||||
#include "android/Camera.h"
|
||||
|
||||
#if defined(DM_PLATFORM_ANDROID)
|
||||
|
||||
struct AndroidCamera
|
||||
{
|
||||
dmBuffer::HBuffer m_VideoBuffer;
|
||||
Camera* m_Camera;
|
||||
|
||||
AndroidCamera() : m_VideoBuffer(0), m_Camera(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
AndroidCamera g_Camera;
|
||||
|
||||
static void FrameUpdateCallback(void* _ctx, void* _data, int width, int height, int numChannels)
|
||||
{
|
||||
AndroidCamera* ctx = (AndroidCamera*)_ctx;
|
||||
uint8_t* out;
|
||||
uint32_t outsize;
|
||||
dmBuffer::GetBytes(g_Camera.m_VideoBuffer, (void**)&out, &outsize);
|
||||
|
||||
uint32_t* data = (uint32_t*)_data;
|
||||
for( int y = 0; y < height; ++y)
|
||||
{
|
||||
for( int x = 0; x < width; ++x)
|
||||
{
|
||||
// We get the image in landscape mode, so we flip it to portrait mode
|
||||
int index = (width-x-1)*height*3 + (height-y-1)*3;
|
||||
|
||||
// RGB <- ARGB
|
||||
uint32_t argb = data[y*width+x];
|
||||
|
||||
out[index+0] = (argb>>0)&0xFF; // R
|
||||
out[index+1] = (argb>>8)&0xFF; // G
|
||||
out[index+2] = (argb>>16)&0xFF; // B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PhotoSavedCallback(void* ctx, bool success)
|
||||
{
|
||||
(void)ctx;
|
||||
(void)success;
|
||||
}
|
||||
|
||||
|
||||
int CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams)
|
||||
{
|
||||
if (g_Camera.m_Camera) {
|
||||
dmLogError("Camera already started!");
|
||||
return 0;
|
||||
}
|
||||
g_Camera.m_Camera = Camera::GetCamera(&g_Camera, FrameUpdateCallback, PhotoSavedCallback);
|
||||
if (!g_Camera.m_Camera) {
|
||||
dmLogError("Camera failed to start");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!g_Camera.m_Camera->Initialize()) {
|
||||
dmLogError("Camera failed to initialize");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!g_Camera.m_Camera->Start()) {
|
||||
dmLogError("Camera failed to initialize");
|
||||
return 0;
|
||||
}
|
||||
|
||||
outparams.m_Width = (uint32_t)g_Camera.m_Camera->GetFrameWidth();
|
||||
outparams.m_Height = (uint32_t)g_Camera.m_Camera->GetFrameHeight();
|
||||
|
||||
// As default behavior, we want portrait mode
|
||||
if (outparams.m_Width > outparams.m_Height) {
|
||||
uint32_t tmp = outparams.m_Width;
|
||||
outparams.m_Width = outparams.m_Height;
|
||||
outparams.m_Height = tmp;
|
||||
}
|
||||
|
||||
uint32_t size = outparams.m_Width * outparams.m_Height;
|
||||
dmBuffer::StreamDeclaration streams_decl[] = {
|
||||
{dmHashString64("rgb"), dmBuffer::VALUE_TYPE_UINT8, 3}
|
||||
};
|
||||
|
||||
dmBuffer::Create(size, streams_decl, 1, buffer);
|
||||
|
||||
g_Camera.m_VideoBuffer = *buffer;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CameraPlatform_StopCapture()
|
||||
{
|
||||
if (g_Camera.m_Camera) {
|
||||
g_Camera.m_Camera->Stop();
|
||||
g_Camera.m_Camera->Deinitialize();
|
||||
delete g_Camera.m_Camera;
|
||||
}
|
||||
g_Camera.m_Camera = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CameraPlatform_UpdateCapture()
|
||||
{
|
||||
if (!g_Camera.m_Camera) {
|
||||
dmLogError("Camera has not been started");
|
||||
return 0;
|
||||
}
|
||||
g_Camera.m_Camera->Update();
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // DM_PLATFORM_ANDROID
|
@ -121,8 +121,8 @@ IOSCamera g_Camera;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)captureOutput:(AVCaptureOutput *)captureOutput
|
||||
didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||
- (void)captureOutput:(AVCaptureOutput *)captureOutput
|
||||
didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||
fromConnection:(AVCaptureConnection *)connection
|
||||
{
|
||||
|
||||
@ -256,7 +256,7 @@ IOSCamera g_Camera;
|
||||
|
||||
static CMVideoDimensions FlipCoords(AVCaptureVideoDataOutput* output, const CMVideoDimensions& in)
|
||||
{
|
||||
CMVideoDimensions out = in;
|
||||
CMVideoDimensions out = in;
|
||||
#if defined(DM_PLATFORM_IOS)
|
||||
AVCaptureConnection* conn = [output connectionWithMediaType:AVMediaTypeVideo];
|
||||
switch (conn.videoOrientation) {
|
||||
@ -274,7 +274,7 @@ static CMVideoDimensions FlipCoords(AVCaptureVideoDataOutput* output, const CMVi
|
||||
|
||||
|
||||
- ( BOOL ) startCamera: (AVCaptureDevicePosition) cameraPosition
|
||||
quality: (CaptureQuality)quality
|
||||
quality: (CaptureQuality)quality
|
||||
{
|
||||
// 1. Find the back camera
|
||||
if ( ![ self findCamera: cameraPosition ] )
|
||||
@ -398,4 +398,9 @@ int CameraPlatform_StopCapture()
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CameraPlatform_UpdateCapture()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // DM_PLATFORM_IOS/DM_PLATFORM_OSX
|
@ -24,3 +24,4 @@ struct CameraInfo
|
||||
|
||||
extern int CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams);
|
||||
extern int CameraPlatform_StopCapture();
|
||||
extern int CameraPlatform_UpdateCapture();
|
||||
|
@ -23,6 +23,7 @@ bundle_identifier = com.defold.camera
|
||||
|
||||
[android]
|
||||
package = com.defold.camera
|
||||
manifest = /AndroidManifest.xml
|
||||
|
||||
[osx]
|
||||
bundle_identifier = com.defold.camera
|
||||
|
Loading…
x
Reference in New Issue
Block a user