mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Add camera/location support for iOS
Add front camera support for Android Allow to change the active camera in-game
This commit is contained in:
parent
1d6d66ac43
commit
5fbf2d7713
@ -745,6 +745,10 @@ elseif(IOS)
|
||||
ios/ViewController.h
|
||||
ios/iOSCoreAudio.mm
|
||||
ios/iOSCoreAudio.h
|
||||
ios/CameraHelper.mm
|
||||
ios/CameraHelper.h
|
||||
ios/LocationHelper.mm
|
||||
ios/LocationHelper.h
|
||||
ios/PPSSPPUIApplication.h
|
||||
ios/PPSSPPUIApplication.mm
|
||||
ios/SmartKeyboardMap.cpp
|
||||
@ -755,7 +759,7 @@ elseif(IOS)
|
||||
ios/iCade/iCadeReaderView.m
|
||||
ios/iCade/iCadeState.h
|
||||
)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation")
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreVideo -framework CoreMedia" )
|
||||
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController")
|
||||
endif()
|
||||
@ -770,7 +774,8 @@ elseif(IOS)
|
||||
set_source_files_properties(ios/PPSSPPUIApplication.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/iCade/iCadeReaderView.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/main.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
|
||||
set_source_files_properties(ios/CameraHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/LocationHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
|
||||
set(TargetBin PPSSPP)
|
||||
elseif(USING_QT_UI)
|
||||
|
@ -707,9 +707,7 @@ static ConfigSetting graphicsSettings[] = {
|
||||
#ifdef _WIN32
|
||||
ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false),
|
||||
#endif
|
||||
#if (defined(_WIN32) && !PPSSPP_PLATFORM(UWP)) || PPSSPP_PLATFORM(LINUX)
|
||||
ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", true, false),
|
||||
#endif
|
||||
ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false),
|
||||
ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, 1, true, true),
|
||||
ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true),
|
||||
|
@ -169,6 +169,7 @@ void __KernelShutdown()
|
||||
kernelObjects.Clear();
|
||||
|
||||
__UsbCamShutdown();
|
||||
__UsbGpsShutdown();
|
||||
|
||||
__AudioCodecShutdown();
|
||||
__VideoPmpShutdown();
|
||||
|
@ -205,8 +205,18 @@ static int sceUsbCamSetupStillEx(u32 paramAddr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbCamAutoImageReverseSW(int rev) {
|
||||
INFO_LOG(HLE, "UNIMPL sceUsbCamAutoImageReverseSW");
|
||||
static int sceUsbCamAutoImageReverseSW(int on) {
|
||||
INFO_LOG(HLE, "UNIMPL sceUsbCamAutoImageReverseSW: %d", on);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbCamGetLensDirection() {
|
||||
INFO_LOG(HLE, "UNIMPL sceUsbCamGetLensDirection");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbCamSetReverseMode(int reverseflags) {
|
||||
INFO_LOG(HLE, "UNIMPL sceUsbCamSetReverseMode %d", reverseflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -244,7 +254,7 @@ const HLEFunction sceUsbCam[] =
|
||||
|
||||
{ 0XF93C4669, &WrapI_I<sceUsbCamAutoImageReverseSW>, "sceUsbCamAutoImageReverseSW", 'i', "i" },
|
||||
{ 0X11A1F128, nullptr, "sceUsbCamGetAutoImageReverseState", '?', "" },
|
||||
{ 0X4C34F553, nullptr, "sceUsbCamGetLensDirection", '?', "" },
|
||||
{ 0X4C34F553, &WrapI_V<sceUsbCamGetLensDirection>, "sceUsbCamGetLensDirection", 'i', "" },
|
||||
|
||||
{ 0X383E9FA8, nullptr, "sceUsbCamGetSaturation", '?', "" },
|
||||
{ 0X6E205974, nullptr, "sceUsbCamSetSaturation", '?', "" },
|
||||
@ -259,7 +269,7 @@ const HLEFunction sceUsbCam[] =
|
||||
{ 0X2BCD50C0, nullptr, "sceUsbCamGetEvLevel", '?', "" },
|
||||
{ 0X1D686870, nullptr, "sceUsbCamSetEvLevel", '?', "" },
|
||||
{ 0XD5279339, nullptr, "sceUsbCamGetReverseMode", '?', "" },
|
||||
{ 0X951BEDF5, nullptr, "sceUsbCamSetReverseMode", '?', "" },
|
||||
{ 0X951BEDF5, &WrapI_I<sceUsbCamSetReverseMode>, "sceUsbCamSetReverseMode", 'i', "i" },
|
||||
{ 0X9E8AAF8D, nullptr, "sceUsbCamGetZoom", '?', "" },
|
||||
{ 0XC484901F, nullptr, "sceUsbCamSetZoom", '?', "" },
|
||||
{ 0XAA7D94BA, nullptr, "sceUsbCamGetAntiFlicker", '?', "" },
|
||||
@ -275,7 +285,9 @@ void Register_sceUsbCam()
|
||||
}
|
||||
|
||||
std::vector<std::string> Camera::getDeviceList() {
|
||||
#if PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
return __cameraGetDeviceList();
|
||||
#elif PPSSPP_PLATFORM(LINUX)
|
||||
return __v4l_getDeviceList();
|
||||
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
|
||||
if (winCamera) {
|
||||
@ -291,7 +303,7 @@ int Camera::startCapture() {
|
||||
INFO_LOG(HLE, "%s resolution: %dx%d", __FUNCTION__, width, height);
|
||||
|
||||
config->mode = Camera::Mode::Video;
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
System_SendMessage("camera_command", "startVideo");
|
||||
#elif PPSSPP_PLATFORM(LINUX)
|
||||
__v4l_startCapture(width, height);
|
||||
@ -312,7 +324,7 @@ int Camera::startCapture() {
|
||||
|
||||
int Camera::stopCapture() {
|
||||
INFO_LOG(HLE, "%s", __FUNCTION__);
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
System_SendMessage("camera_command", "stopVideo");
|
||||
#elif PPSSPP_PLATFORM(LINUX)
|
||||
__v4l_stopCapture();
|
||||
@ -328,6 +340,13 @@ int Camera::stopCapture() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Camera::onCameraDeviceChange() {
|
||||
if (config != nullptr && config->mode == Camera::Mode::Video) {
|
||||
stopCapture();
|
||||
startCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::pushCameraImage(long long length, unsigned char* image) {
|
||||
std::lock_guard<std::mutex> lock(videoBufferMutex);
|
||||
if (!videoBuffer) {
|
||||
|
@ -117,6 +117,7 @@ namespace Camera {
|
||||
} Config;
|
||||
|
||||
std::vector<std::string> getDeviceList();
|
||||
void onCameraDeviceChange();
|
||||
int startCapture();
|
||||
int stopCapture();
|
||||
void pushCameraImage(long long length, unsigned char *image);
|
||||
|
@ -43,6 +43,15 @@ void __UsbGpsDoState(PointerWrap &p) {
|
||||
p.Do(gpsStatus);
|
||||
}
|
||||
|
||||
void __UsbGpsShutdown() {
|
||||
gpsStatus = GPS_STATE_OFF;
|
||||
System_SendMessage("gps_command", "close");
|
||||
};
|
||||
|
||||
static int sceUsbGpsGetInitDataLocation(u32 addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbGpsGetState(u32 stateAddr) {
|
||||
if (Memory::IsValidAddress(stateAddr)) {
|
||||
Memory::Write_U32(gpsStatus, stateAddr);
|
||||
@ -79,7 +88,7 @@ const HLEFunction sceUsbGps[] =
|
||||
{
|
||||
{0X268F95CA, nullptr, "sceUsbGpsSetInitDataLocation", '?', "" },
|
||||
{0X31F95CDE, nullptr, "sceUsbGpsGetPowerSaveMode", '?', "" },
|
||||
{0X54D26AA4, nullptr, "sceUsbGpsGetInitDataLocation", '?', "" },
|
||||
{0X54D26AA4, &WrapI_U<sceUsbGpsGetInitDataLocation>, "sceUsbGpsGetInitDataLocation", 'i', "x" },
|
||||
{0X63D1F89D, nullptr, "sceUsbGpsResetInitialPosition", '?', "" },
|
||||
{0X69E4AAA8, nullptr, "sceUsbGpsSaveInitData", '?', "" },
|
||||
{0X6EED4811, &WrapI_V<sceUsbGpsClose>, "sceUsbGpsClose", 'i', "" },
|
||||
|
@ -21,6 +21,7 @@ void Register_sceUsbGps();
|
||||
|
||||
void __UsbGpsInit();
|
||||
void __UsbGpsDoState(PointerWrap &p);
|
||||
void __UsbGpsShutdown();
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
|
@ -192,9 +192,10 @@ int __v4l_startCapture(int ideal_width, int ideal_height) {
|
||||
frmsize.index++;
|
||||
if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
|
||||
INFO_LOG(HLE, "V4L2: frame size supported: %dx%d", frmsize.discrete.width, frmsize.discrete.height);
|
||||
if (fmt.fmt.pix.width != 0 && fmt.fmt.pix.height != 0) {
|
||||
continue;
|
||||
} else if (frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height) {
|
||||
if (frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height
|
||||
&& fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0
|
||||
|| frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height
|
||||
&& frmsize.discrete.width < fmt.fmt.pix.width && frmsize.discrete.height < fmt.fmt.pix.height) {
|
||||
fmt.fmt.pix.width = frmsize.discrete.width;
|
||||
fmt.fmt.pix.height = frmsize.discrete.height;
|
||||
}
|
||||
|
@ -263,13 +263,12 @@ void GameSettingsScreen::CreateViews() {
|
||||
softwareGPU->SetEnabled(false);
|
||||
}
|
||||
|
||||
#if (defined(_WIN32) && !PPSSPP_PLATFORM(UWP)) || PPSSPP_PLATFORM(LINUX)
|
||||
std::vector<std::string> cameraList = Camera::getDeviceList();
|
||||
if (cameraList.size() >= 1) {
|
||||
graphicsSettings->Add(new ItemHeader(gr->T("Camera")));
|
||||
PopupMultiChoiceDynamic *cameraChoice = graphicsSettings->Add(new PopupMultiChoiceDynamic(&g_Config.sCameraDevice, gr->T("Camera Device"), cameraList, nullptr, screenManager()));
|
||||
cameraChoice->OnChoice.Handle(this, &GameSettingsScreen::OnCameraDeviceChange);
|
||||
}
|
||||
#endif
|
||||
|
||||
graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control")));
|
||||
static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"};
|
||||
@ -1200,6 +1199,11 @@ UI::EventReturn GameSettingsScreen::OnRenderingDevice(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnCameraDeviceChange(UI::EventParams& e) {
|
||||
Camera::onCameraDeviceChange();
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) {
|
||||
I18NCategory *a = GetI18NCategory("Audio");
|
||||
if (g_Config.sAudioDevice == a->T("Auto")) {
|
||||
|
@ -97,6 +97,7 @@ private:
|
||||
UI::EventReturn OnRenderingMode(UI::EventParams &e);
|
||||
UI::EventReturn OnRenderingBackend(UI::EventParams &e);
|
||||
UI::EventReturn OnRenderingDevice(UI::EventParams &e);
|
||||
UI::EventReturn OnCameraDeviceChange(UI::EventParams& e);
|
||||
UI::EventReturn OnAudioDevice(UI::EventParams &e);
|
||||
UI::EventReturn OnJitAffectingSetting(UI::EventParams &e);
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
@ -1358,7 +1358,7 @@ void NativeShutdown() {
|
||||
// I think we handle most globals correctly or correct-enough now.
|
||||
}
|
||||
|
||||
void PushNewGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long long time) {
|
||||
void SetGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long long time) {
|
||||
GPS::setGpsData(latitude, longitude, altitude, speed, bearing, time);
|
||||
}
|
||||
|
||||
|
@ -921,12 +921,40 @@ extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDesiredBackbufferHei
|
||||
return desiredBackbufferSizeY;
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_pushNewGpsData(JNIEnv *, jclass,
|
||||
jfloat latitude, jfloat longitude, jfloat altitude, jfloat speed, jfloat bearing, jlong time) {
|
||||
PushNewGpsData(latitude, longitude, altitude, speed, bearing, time);
|
||||
|
||||
std::vector<std::string> __cameraGetDeviceList() {
|
||||
jclass cameraClass = findClass("org/ppsspp/ppsspp/CameraHelper");
|
||||
jmethodID deviceListMethod = getEnv()->GetStaticMethodID(cameraClass, "getDeviceList", "()Ljava/util/ArrayList;");
|
||||
jobject deviceListObject = getEnv()->CallStaticObjectMethod(cameraClass, deviceListMethod);
|
||||
jclass arrayListClass = getEnv()->FindClass("java/util/ArrayList");
|
||||
jmethodID arrayListSize = getEnv()->GetMethodID(arrayListClass, "size", "()I");
|
||||
jmethodID arrayListGet = getEnv()->GetMethodID(arrayListClass, "get", "(I)Ljava/lang/Object;");
|
||||
|
||||
jint arrayListObjectLen = getEnv()->CallIntMethod(deviceListObject, arrayListSize);
|
||||
std::vector<std::string> deviceListVector;
|
||||
|
||||
for (int i=0; i < arrayListObjectLen; i++) {
|
||||
jstring dev = static_cast<jstring>(getEnv()->CallObjectMethod(deviceListObject, arrayListGet, i));
|
||||
const char* cdev = getEnv()->GetStringUTFChars(dev, nullptr);
|
||||
deviceListVector.push_back(cdev);
|
||||
getEnv()->ReleaseStringUTFChars(dev, cdev);
|
||||
getEnv()->DeleteLocalRef(dev);
|
||||
}
|
||||
return deviceListVector;
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_pushCameraImage(JNIEnv *env, jclass,
|
||||
extern "C" jint Java_org_ppsspp_ppsspp_NativeApp_getSelectedCamera(JNIEnv *, jclass) {
|
||||
int cameraId = 0;
|
||||
sscanf(g_Config.sCameraDevice.c_str(), "%d:", &cameraId);
|
||||
return cameraId;
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setGpsDataAndroid(JNIEnv *, jclass,
|
||||
jfloat latitude, jfloat longitude, jfloat altitude, jfloat speed, jfloat bearing, jlong time) {
|
||||
SetGpsData(latitude, longitude, altitude, speed, bearing, time);
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_pushCameraImageAndroid(JNIEnv *env, jclass,
|
||||
jbyteArray image) {
|
||||
|
||||
if (image != NULL) {
|
||||
|
@ -15,6 +15,7 @@ import android.view.WindowManager;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@TargetApi(23)
|
||||
@ -24,6 +25,7 @@ class CameraHelper {
|
||||
private Display mDisplay;
|
||||
private Camera mCamera = null;
|
||||
private boolean mIsCameraRunning = false;
|
||||
private int mCameraFacing = 0;
|
||||
private int mCameraOrientation = 0;
|
||||
private Camera.Size mPreviewSize = null;
|
||||
private long mLastFrameTime = 0;
|
||||
@ -38,8 +40,12 @@ class CameraHelper {
|
||||
case Surface.ROTATION_180: displayDegrees = 180; break;
|
||||
case Surface.ROTATION_270: displayDegrees = 270; break;
|
||||
}
|
||||
if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
return (mCameraOrientation + displayDegrees) % 360;
|
||||
} else {
|
||||
return (mCameraOrientation - displayDegrees + 360) % 360;
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] rotateNV21(final byte[] input, final int inWidth, final int inHeight,
|
||||
final int outWidth, final int outHeight, final int rotation) {
|
||||
@ -117,7 +123,7 @@ class CameraHelper {
|
||||
// convert to Jpeg
|
||||
Rect crop = new Rect(0, 0, targetW, targetH);
|
||||
yuvImage.compressToJpeg(crop, 80, baos);
|
||||
NativeApp.pushCameraImage(baos.toByteArray());
|
||||
NativeApp.pushCameraImageAndroid(baos.toByteArray());
|
||||
try {
|
||||
baos.close();
|
||||
} catch (IOException e) {
|
||||
@ -132,14 +138,29 @@ class CameraHelper {
|
||||
mSurfaceTexture = new SurfaceTexture(10);
|
||||
}
|
||||
|
||||
static ArrayList<String> getDeviceList() {
|
||||
ArrayList<String> deviceList = new ArrayList<>();
|
||||
int nrCam = Camera.getNumberOfCameras();
|
||||
for (int index = 0; index < nrCam; index++) {
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(index, info);
|
||||
String devName = index + ":" + (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK ? "Back Camera" : "Front Camera");
|
||||
deviceList.add(devName);
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
void startCamera() {
|
||||
Log.d(TAG, "startCamera");
|
||||
try {
|
||||
Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
|
||||
Camera.getCameraInfo(0, info);
|
||||
int cameraId = NativeApp.getSelectedCamera();
|
||||
Log.d(TAG, "startCamera: " + cameraId);
|
||||
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraId, info);
|
||||
mCameraFacing = info.facing;
|
||||
mCameraOrientation = info.orientation;
|
||||
|
||||
mCamera = Camera.open();
|
||||
mCamera = Camera.open(cameraId);
|
||||
Camera.Parameters param = mCamera.getParameters();
|
||||
|
||||
// Set preview size
|
||||
|
@ -50,12 +50,13 @@ class LocationHelper implements LocationListener {
|
||||
public void onLocationChanged(Location location) {
|
||||
float latitude = (float) location.getLatitude();
|
||||
float longitude = (float) location.getLongitude();
|
||||
// Android altitude is in meters above the WGS 84 reference ellipsoid
|
||||
float altitude = (float) location.getAltitude();
|
||||
float speed = location.getSpeed();
|
||||
float bearing = location.getBearing();
|
||||
long time = location.getTime() / 1000; // ms to s !!
|
||||
|
||||
NativeApp.pushNewGpsData(latitude, longitude, altitude, speed, bearing, time);
|
||||
NativeApp.setGpsDataAndroid(latitude, longitude, altitude, speed, bearing, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,7 +51,7 @@ public class NativeApp {
|
||||
|
||||
public static native String queryConfig(String queryName);
|
||||
|
||||
public static native void pushNewGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long time);
|
||||
|
||||
public static native void pushCameraImage(byte[] image);
|
||||
public static native int getSelectedCamera();
|
||||
public static native void setGpsDataAndroid(float latitude, float longitude, float altitude, float speed, float bearing, long time);
|
||||
public static native void pushCameraImageAndroid(byte[] image);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// The Native App API.
|
||||
//
|
||||
@ -174,5 +175,6 @@ std::string System_GetProperty(SystemProperty prop);
|
||||
int System_GetPropertyInt(SystemProperty prop);
|
||||
bool System_GetPropertyBool(SystemProperty prop);
|
||||
|
||||
void PushNewGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long long time);
|
||||
std::vector<std::string> __cameraGetDeviceList();
|
||||
void SetGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long long time);
|
||||
void PushCameraImage(long long length, unsigned char* image);
|
||||
|
17
ios/CameraHelper.h
Normal file
17
ios/CameraHelper.h
Normal file
@ -0,0 +1,17 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@protocol CameraFrameDelegate <NSObject>
|
||||
@required
|
||||
- (void) PushCameraImageIOS:(long long)len buffer:(unsigned char*)data;
|
||||
@end
|
||||
|
||||
@interface CameraHelper : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate>
|
||||
|
||||
@property (nonatomic, strong) id<CameraFrameDelegate> delegate;
|
||||
|
||||
- (int) checkPermission;
|
||||
- (void) startVideo;
|
||||
- (void) stopVideo;
|
||||
|
||||
@end
|
144
ios/CameraHelper.mm
Normal file
144
ios/CameraHelper.mm
Normal file
@ -0,0 +1,144 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "Core/Config.h"
|
||||
#import "CameraHelper.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface CameraHelper() {
|
||||
AVCaptureSession *captureSession;
|
||||
AVCaptureVideoPreviewLayer *previewLayer;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CameraHelper
|
||||
|
||||
std::vector<std::string> __cameraGetDeviceList() {
|
||||
std::vector<std::string> deviceList;
|
||||
for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
deviceList.push_back([device.localizedName UTF8String]);
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
NSString *getSelectedCamera() {
|
||||
NSString *selectedCamera = [NSString stringWithCString:g_Config.sCameraDevice.c_str() encoding:[NSString defaultCStringEncoding]];
|
||||
return selectedCamera;
|
||||
}
|
||||
|
||||
-(int) checkPermission {
|
||||
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
NSLog(@"CameraHelper::checkPermission %ld", (long)status);
|
||||
|
||||
switch (status) {
|
||||
case AVAuthorizationStatusNotDetermined: {
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
if (granted) {
|
||||
NSLog(@"camera permission granted");
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self startVideo];
|
||||
});
|
||||
} else {
|
||||
NSLog(@"camera permission denied");
|
||||
}
|
||||
}];
|
||||
return 1;
|
||||
}
|
||||
case AVAuthorizationStatusRestricted:
|
||||
case AVAuthorizationStatusDenied: {
|
||||
NSLog(@"camera permission denied");
|
||||
return 1;
|
||||
}
|
||||
case AVAuthorizationStatusAuthorized: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void) startVideo {
|
||||
NSLog(@"CameraHelper::startVideo");
|
||||
if ([self checkPermission]) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSError *error = nil;
|
||||
|
||||
captureSession = [[AVCaptureSession alloc] init];
|
||||
captureSession.sessionPreset = AVCaptureSessionPresetMedium;
|
||||
|
||||
AVCaptureDeviceInput *videoInput = nil;
|
||||
NSString *selectedCamera = getSelectedCamera();
|
||||
for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
if ([device.localizedName isEqualToString:selectedCamera]) {
|
||||
videoInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
|
||||
}
|
||||
}
|
||||
if (videoInput == nil || error) {
|
||||
NSLog(@"selectedCamera error; try default device");
|
||||
|
||||
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
|
||||
if (videoDevice == nil) {
|
||||
NSLog(@"videoDevice error");
|
||||
return;
|
||||
}
|
||||
videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
|
||||
if (videoInput == nil) {
|
||||
NSLog(@"videoInput error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
[captureSession addInput:videoInput];
|
||||
|
||||
AVCaptureVideoDataOutput *videoOutput = [[AVCaptureVideoDataOutput alloc] init];
|
||||
videoOutput.videoSettings = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey: (id)kCVPixelBufferPixelFormatTypeKey];
|
||||
|
||||
[captureSession addOutput:videoOutput];
|
||||
|
||||
dispatch_queue_t queue = dispatch_queue_create("cameraQueue", NULL);
|
||||
[videoOutput setSampleBufferDelegate:self queue:queue];
|
||||
|
||||
previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
|
||||
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
|
||||
[previewLayer setFrame:CGRectMake(0, 0, 480, 272)];
|
||||
|
||||
[captureSession startRunning];
|
||||
});
|
||||
}
|
||||
|
||||
-(void) stopVideo {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[captureSession stopRunning];
|
||||
});
|
||||
}
|
||||
|
||||
- (void) captureOutput:(AVCaptureOutput *)captureOutput
|
||||
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||
fromConnection:(AVCaptureConnection *)connection {
|
||||
CGImageRef cgImage = [self imageFromSampleBuffer:sampleBuffer];
|
||||
UIImage *theImage = [UIImage imageWithCGImage: cgImage];
|
||||
CGImageRelease(cgImage);
|
||||
NSData *imageData = UIImageJPEGRepresentation(theImage, 0.6);
|
||||
|
||||
[self.delegate PushCameraImageIOS:imageData.length buffer:(unsigned char*)imageData.bytes];
|
||||
}
|
||||
|
||||
- (CGImageRef) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer {
|
||||
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
CVPixelBufferLockBaseAddress(imageBuffer,0);
|
||||
void* baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
|
||||
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
|
||||
size_t width = CVPixelBufferGetWidth(imageBuffer);
|
||||
size_t height = CVPixelBufferGetHeight(imageBuffer);
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
|
||||
CGImageRef newImage = CGBitmapContextCreateImage(newContext);
|
||||
CGContextRelease(newContext);
|
||||
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
@end
|
18
ios/LocationHelper.h
Normal file
18
ios/LocationHelper.h
Normal file
@ -0,0 +1,18 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
@protocol LocationHandlerDelegate <NSObject>
|
||||
@required
|
||||
- (void) SetGpsDataIOS:(CLLocation*)newLocation;
|
||||
@end
|
||||
|
||||
@interface LocationHelper : NSObject<CLLocationManagerDelegate> {
|
||||
CLLocationManager *locationManager;
|
||||
}
|
||||
|
||||
@property(nonatomic,strong) id<LocationHandlerDelegate> delegate;
|
||||
|
||||
- (void) startLocationUpdates;
|
||||
- (void) stopLocationUpdates;
|
||||
|
||||
@end
|
34
ios/LocationHelper.mm
Normal file
34
ios/LocationHelper.mm
Normal file
@ -0,0 +1,34 @@
|
||||
#import "LocationHelper.h"
|
||||
|
||||
@interface LocationHelper()
|
||||
@end
|
||||
|
||||
@implementation LocationHelper
|
||||
|
||||
-(id) init {
|
||||
NSLog(@"LocationHelper::init");
|
||||
locationManager = [[CLLocationManager alloc] init];
|
||||
[locationManager setDelegate:self];
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) startLocationUpdates {
|
||||
NSLog(@"LocationHelper::startLocationUpdates");
|
||||
if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
|
||||
[locationManager requestWhenInUseAuthorization];
|
||||
}
|
||||
[locationManager startUpdatingLocation];
|
||||
}
|
||||
|
||||
-(void) stopLocationUpdates {
|
||||
NSLog(@"LocationHelper::stopLocationUpdates");
|
||||
[locationManager stopUpdatingLocation];
|
||||
}
|
||||
|
||||
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
|
||||
for (id location in locations) {
|
||||
[self.delegate SetGpsDataIOS:location];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -4,6 +4,12 @@
|
||||
<dict>
|
||||
<key>UISupportsDocumentBrowser</key>
|
||||
<true/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Your location may be used to emulate Go!Explore, a GPS accessory</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Your camera may be used to emulate Go!Cam, a camera accessory</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Your microphone may be used to emulate Go!Cam/Talkman, a microphone accessory</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
|
@ -6,11 +6,18 @@
|
||||
#import <GameController/GameController.h>
|
||||
#endif
|
||||
#import "iCade/iCadeReaderView.h"
|
||||
#import "CameraHelper.h"
|
||||
#import "LocationHelper.h"
|
||||
|
||||
@interface ViewController : GLKViewController <iCadeEventDelegate>
|
||||
@interface ViewController : GLKViewController <iCadeEventDelegate,
|
||||
LocationHandlerDelegate, CameraFrameDelegate>
|
||||
|
||||
- (void)shutdown;
|
||||
|
||||
@end
|
||||
|
||||
extern __unsafe_unretained ViewController* sharedViewController;
|
||||
void startVideo();
|
||||
void stopVideo();
|
||||
void startLocation();
|
||||
void stopLocation();
|
||||
|
@ -84,6 +84,8 @@ static bool threadStopped = false;
|
||||
|
||||
__unsafe_unretained ViewController* sharedViewController;
|
||||
static GraphicsContext *graphicsContext;
|
||||
static CameraHelper *cameraHelper;
|
||||
static LocationHelper *locationHelper;
|
||||
|
||||
@interface ViewController () {
|
||||
std::map<uint16_t, uint16_t> iCadeToKeyMap;
|
||||
@ -203,6 +205,12 @@ static GraphicsContext *graphicsContext;
|
||||
[self.view addSubview:volume];
|
||||
[self.view bringSubviewToFront:volume];
|
||||
|
||||
cameraHelper = [[CameraHelper alloc] init];
|
||||
[cameraHelper setDelegate:self];
|
||||
|
||||
locationHelper = [[LocationHelper alloc] init];
|
||||
[locationHelper setDelegate:self];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
NativeInitGraphics(graphicsContext);
|
||||
|
||||
@ -667,6 +675,33 @@ static GraphicsContext *graphicsContext;
|
||||
}
|
||||
#endif
|
||||
|
||||
void startVideo() {
|
||||
[cameraHelper startVideo];
|
||||
}
|
||||
|
||||
void stopVideo() {
|
||||
[cameraHelper stopVideo];
|
||||
}
|
||||
|
||||
-(void) PushCameraImageIOS:(long long)len buffer:(unsigned char*)data {
|
||||
PushCameraImage(len, data);
|
||||
}
|
||||
|
||||
void startLocation() {
|
||||
[locationHelper startLocationUpdates];
|
||||
}
|
||||
|
||||
void stopLocation() {
|
||||
[locationHelper stopLocationUpdates];
|
||||
}
|
||||
|
||||
-(void) SetGpsDataIOS:(CLLocation *)newLocation {
|
||||
NSLog(@"SetGpsDataIOS: speed: %f", newLocation.speed); // m/s
|
||||
SetGpsData(newLocation.coordinate.latitude, newLocation.coordinate.longitude,
|
||||
newLocation.altitude, 0 /* speed */, 0 /* bearing */,
|
||||
(long long)newLocation.timestamp.timeIntervalSince1970);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void OpenDirectory(const char *path) {
|
||||
|
12
ios/main.mm
12
ios/main.mm
@ -112,6 +112,18 @@ void System_SendMessage(const char *command, const char *parameter) {
|
||||
// [sharedViewController shutdown];
|
||||
// exit(0);
|
||||
// });
|
||||
} else if (!strcmp(command, "camera_command")) {
|
||||
if (!strcmp(parameter, "startVideo")) {
|
||||
startVideo();
|
||||
} else if (!strcmp(parameter, "stopVideo")) {
|
||||
stopVideo();
|
||||
}
|
||||
} else if (!strcmp(command, "gps_command")) {
|
||||
if (!strcmp(parameter, "open")) {
|
||||
startLocation();
|
||||
} else if (!strcmp(parameter, "close")) {
|
||||
stopLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user