First version of Android camera

This commit is contained in:
Mathias Westerdahl 2018-05-18 16:51:13 +02:00
parent 57ef591ca0
commit 5fd504cc14
10 changed files with 803 additions and 15 deletions

141
AndroidManifest.xml Normal file
View 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) -->

View File

@ -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

View 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;
};

View 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);
}
};

View 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);
}

View File

@ -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)

View 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

View File

@ -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

View File

@ -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();

View File

@ -23,6 +23,7 @@ bundle_identifier = com.defold.camera
[android]
package = com.defold.camera
manifest = /AndroidManifest.xml
[osx]
bundle_identifier = com.defold.camera