mirror of
				https://git.jami.net/savoirfairelinux/jami-client-android.git
				synced 2025-10-30 07:58:36 +08:00 
			
		
		
		
	video output rotation
* Change camera settings and reinvite on screen rotation. * Apply rotation in the JNI layer Change-Id: I48fe8f5eb47287f964012be416875a656993e912 Tuleap: #566
This commit is contained in:
		| @ -29,8 +29,13 @@ import android.content.Intent; | ||||
| import android.content.IntentFilter; | ||||
| import android.content.res.Configuration; | ||||
| import android.graphics.PixelFormat; | ||||
| import android.hardware.display.DisplayManager; | ||||
| import android.media.AudioManager; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.support.v4.app.NotificationManagerCompat; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.os.PowerManager; | ||||
| import android.os.PowerManager.WakeLock; | ||||
| @ -112,6 +117,8 @@ public class CallFragment extends Fragment implements CallInterface { | ||||
|     private ViewGroup rootView = null; | ||||
|     private boolean ongoingCall = false; | ||||
|  | ||||
|     private DisplayManager.DisplayListener displayListener; | ||||
|  | ||||
|     @Override | ||||
|     public void onAttach(Activity activity) { | ||||
|         Log.i(TAG, "onAttach"); | ||||
| @ -156,15 +163,37 @@ public class CallFragment extends Fragment implements CallInterface { | ||||
|  | ||||
|         setHasOptionsMenu(true); | ||||
|         PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); | ||||
|         mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, | ||||
|                 "cx.ring.onIncomingCall"); | ||||
|         mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "cx.ring.onIncomingCall"); | ||||
|         mScreenWakeLock.setReferenceCounted(false); | ||||
|  | ||||
|         Log.d(TAG, "Acquire wake up lock"); | ||||
|         if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) { | ||||
|             mScreenWakeLock.acquire(); | ||||
|         } | ||||
|  | ||||
|         if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { | ||||
|             displayListener = new DisplayManager.DisplayListener() { | ||||
|                 @Override | ||||
|                 public void onDisplayAdded(int displayId) {} | ||||
|  | ||||
|                 @Override | ||||
|                 public void onDisplayRemoved(int displayId) {} | ||||
|  | ||||
|                 @Override | ||||
|                 public void onDisplayChanged(int displayId) { | ||||
|                     getActivity().runOnUiThread(new Runnable() { | ||||
|                         @Override | ||||
|                         public void run() { | ||||
|                             try { | ||||
|                                 mCallbacks.getRemoteService().switchInput(getConference().getId(), lastVideoSource); | ||||
|                             } catch (RemoteException e) { | ||||
|                                 e.printStackTrace(); | ||||
|                             } | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         setRetainInstance(true); | ||||
|     } | ||||
|  | ||||
| @ -354,10 +383,16 @@ public class CallFragment extends Fragment implements CallInterface { | ||||
|  | ||||
|     @Override | ||||
|     public void onStop() { | ||||
|         super.onStop(); | ||||
|  | ||||
|         Conference c = getConference(); | ||||
|         Log.w(TAG, "onStop() haveVideo="+haveVideo); | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { | ||||
|             DisplayManager displayManager = (DisplayManager) getActivity().getSystemService(Context.DISPLAY_SERVICE); | ||||
|             displayManager.unregisterDisplayListener(displayListener); | ||||
|         } | ||||
|  | ||||
|         DRingService.videoSurfaces.remove(c.getId()); | ||||
|         DRingService.mCameraPreviewSurface.clear(); | ||||
|         try { | ||||
| @ -369,13 +404,17 @@ public class CallFragment extends Fragment implements CallInterface { | ||||
|         } catch (RemoteException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | ||||
|         super.onStop(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { | ||||
|             DisplayManager displayManager = (DisplayManager) getActivity().getSystemService(Context.DISPLAY_SERVICE); | ||||
|             displayManager.registerDisplayListener(displayListener, null); | ||||
|         } | ||||
|  | ||||
|         Conference c = getConference(); | ||||
|         if (c != null && video != null && c.resumeVideo) { | ||||
|             Log.w(TAG, "Resuming video"); | ||||
| @ -571,6 +610,7 @@ public class CallFragment extends Fragment implements CallInterface { | ||||
|     public void onConfigurationChanged(Configuration newConfig) { | ||||
|         if (videoPreview.getVisibility() == View.VISIBLE) { | ||||
|             try { | ||||
|                 mCallbacks.getRemoteService().setPreviewSettings(); | ||||
|                 mCallbacks.getRemoteService().videoPreviewSurfaceAdded(); | ||||
|             } catch (RemoteException e) { | ||||
|                 e.printStackTrace(); | ||||
|  | ||||
| @ -28,6 +28,7 @@ package cx.ring.service; | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.IntentFilter; | ||||
| import android.content.res.Configuration; | ||||
| import android.hardware.Camera; | ||||
| import android.media.AudioManager; | ||||
| import android.os.Handler; | ||||
| @ -230,41 +231,66 @@ public class DRingService extends Service { | ||||
|             this.height = height; | ||||
|             this.rate = rate; | ||||
|         } | ||||
|         public VideoParams(VideoParams p) { | ||||
|             this.id = p.id; | ||||
|             this.format = p.format; | ||||
|             this.width = p.width; | ||||
|             this.height = p.height; | ||||
|             this.rate = p.rate; | ||||
|         } | ||||
|  | ||||
|         public int id; | ||||
|         public int format; | ||||
|  | ||||
|         // size as captured by Android | ||||
|         public int width; | ||||
|         public int height; | ||||
|  | ||||
|         //size, rotated, as seen by the daemon | ||||
|         public int rot_width; | ||||
|         public int rot_height; | ||||
|  | ||||
|         public int rate; | ||||
|         public int rotation; | ||||
|     } | ||||
|  | ||||
|     public int setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) { | ||||
|         android.hardware.Camera.CameraInfo info = | ||||
|                 new android.hardware.Camera.CameraInfo(); | ||||
|         android.hardware.Camera.getCameraInfo(cameraId, info); | ||||
|         WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); | ||||
|         int rotation = windowManager.getDefaultDisplay().getRotation(); | ||||
|         int degrees = 0; | ||||
|         switch (rotation) { | ||||
|             case Surface.ROTATION_0: degrees = 0; break; | ||||
|             case Surface.ROTATION_90: degrees = 90; break; | ||||
|             case Surface.ROTATION_180: degrees = 180; break; | ||||
|             case Surface.ROTATION_270: degrees = 270; break; | ||||
|     static public int rotationToDegrees(int r) { | ||||
|         switch (r) { | ||||
|             case Surface.ROTATION_0: return 0; | ||||
|             case Surface.ROTATION_90: return 90; | ||||
|             case Surface.ROTATION_180: return 180; | ||||
|             case Surface.ROTATION_270: return 270; | ||||
|         } | ||||
|  | ||||
|         int result; | ||||
|         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { | ||||
|             result = (info.orientation + degrees) % 360; | ||||
|             result = (360 - result) % 360;  // compensate the mirror | ||||
|         } else {  // back-facing | ||||
|             result = (info.orientation - degrees + 360) % 360; | ||||
|         } | ||||
|         camera.setDisplayOrientation(result); | ||||
|         return result; | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     public void startCapture(VideoParams p) { | ||||
|     public void setVideoRotation(VideoParams p, Camera.CameraInfo info) { | ||||
|         WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); | ||||
|         int rotation = rotationToDegrees(windowManager.getDefaultDisplay().getRotation()); | ||||
|         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { | ||||
|             p.rotation =  (info.orientation + rotation + 360) % 360; | ||||
|         } else { | ||||
|             p.rotation =  (info.orientation - rotation + 360) % 360; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void setCameraDisplayOrientation(int cam_id, android.hardware.Camera camera) { | ||||
|         android.hardware.Camera.CameraInfo info = | ||||
|                 new android.hardware.Camera.CameraInfo(); | ||||
|         android.hardware.Camera.getCameraInfo(cam_id, info); | ||||
|         WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); | ||||
|         int rotation = rotationToDegrees(windowManager.getDefaultDisplay().getRotation()); | ||||
|         int result; | ||||
|         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { | ||||
|             result = (info.orientation + rotation) % 360; | ||||
|             result = (360 - result) % 360;  // compensate the mirror | ||||
|         } else {  // back-facing | ||||
|             result = (info.orientation - rotation + 360) % 360; | ||||
|         } | ||||
|         camera.setDisplayOrientation(result); | ||||
|     } | ||||
|  | ||||
|     public void startCapture(final VideoParams p) { | ||||
|         stopCapture(); | ||||
|  | ||||
|         SurfaceHolder surface = mCameraPreviewSurface.get(); | ||||
| @ -281,12 +307,12 @@ public class DRingService extends Service { | ||||
|             Log.w(TAG, "startCapture: no video parameters "); | ||||
|             return; | ||||
|         } | ||||
|         Log.w(TAG, "startCapture " + p.id); | ||||
|         Log.d(TAG, "startCapture " + p.id); | ||||
|  | ||||
|         final Camera preview; | ||||
|         try { | ||||
|             preview = Camera.open(p.id); | ||||
|             p.rotation = setCameraDisplayOrientation(p.id, preview); | ||||
|             setCameraDisplayOrientation(p.id, preview); | ||||
|         } catch (Exception e) { | ||||
|             Log.e(TAG, e.getMessage()); | ||||
|             return; | ||||
| @ -317,7 +343,15 @@ public class DRingService extends Service { | ||||
|             Log.e(TAG, e.getMessage()); | ||||
|         } | ||||
|  | ||||
|         preview.setPreviewCallback(videoManagerCallback); | ||||
|         preview.setPreviewCallback(new Camera.PreviewCallback() { | ||||
|             @Override | ||||
|             public void onPreviewFrame(byte[] data, Camera camera) { | ||||
|                 long ptr = RingserviceJNI.obtainFrame(data.length); | ||||
|                 if (ptr != 0) | ||||
|                     RingserviceJNI.setVideoFrame(data, data.length, ptr, p.width, p.height, p.rotation); | ||||
|                 RingserviceJNI.releaseFrame(ptr); | ||||
|             } | ||||
|         }); | ||||
|         preview.setErrorCallback(new Camera.ErrorCallback() { | ||||
|             @Override | ||||
|             public void onError(int error, Camera cam) { | ||||
| @ -334,19 +368,19 @@ public class DRingService extends Service { | ||||
|         Intent intent = new Intent(VIDEO_EVENT); | ||||
|         intent.putExtra("camera", p.id == 1); | ||||
|         intent.putExtra("started", true); | ||||
|         boolean invert = p.rotation == 90 || p.rotation == 270; | ||||
|         intent.putExtra("width", invert ? p.height : p.width); | ||||
|         intent.putExtra("height", invert ? p.width : p.height); | ||||
|         intent.putExtra("width", p.rot_width); | ||||
|         intent.putExtra("height", p.rot_height); | ||||
|         sendBroadcast(intent); | ||||
|     } | ||||
|  | ||||
|     public void stopCapture() { | ||||
|         Log.w(TAG, "stopCapture " + previewCamera); | ||||
|         Log.d(TAG, "stopCapture " + previewCamera); | ||||
|         if (previewCamera != null) { | ||||
|             final Camera preview = previewCamera; | ||||
|             final VideoParams p = previewParams; | ||||
|             previewCamera = null; | ||||
|             preview.setPreviewCallback(null); | ||||
|             preview.setErrorCallback(null); | ||||
|             preview.stopPreview(); | ||||
|             preview.release(); | ||||
|  | ||||
| @ -1390,7 +1424,7 @@ public class DRingService extends Service { | ||||
|  | ||||
|         public void videoSurfaceAdded(String id) | ||||
|         { | ||||
|             Log.i(TAG, "DRingService.videoSurfaceAdded() " + id); | ||||
|             Log.d(TAG, "DRingService.videoSurfaceAdded() " + id); | ||||
|             Shm shm = videoInputs.get(id); | ||||
|             SurfaceHolder holder = videoSurfaces.get(id).get(); | ||||
|             if (shm != null && holder != null && shm.window == 0) | ||||
| @ -1399,7 +1433,7 @@ public class DRingService extends Service { | ||||
|  | ||||
|         public void videoSurfaceRemoved(String id) | ||||
|         { | ||||
|             Log.i(TAG, "DRingService.videoSurfaceRemoved() " + id); | ||||
|             Log.d(TAG, "DRingService.videoSurfaceRemoved() " + id); | ||||
|             Shm shm = videoInputs.get(id); | ||||
|             if (shm != null) | ||||
|                 stopVideo(shm); | ||||
| @ -1419,13 +1453,26 @@ public class DRingService extends Service { | ||||
|             getExecutor().execute(new SipRunnable() { | ||||
|                 @Override | ||||
|                 protected void doRun() throws SameThreadException, RemoteException { | ||||
|                     String uri = "camera://" + (front ? videoManagerCallback.cameraFront : videoManagerCallback.cameraBack); | ||||
|                     int cam_id = (front ? videoManagerCallback.cameraFront : videoManagerCallback.cameraBack); | ||||
|                     String uri = "camera://" + cam_id; | ||||
|                     Log.i(TAG, "DRingService.switchInput() " + uri); | ||||
|                     Ringservice.applySettings(id, videoManagerCallback.getNativeParams(cam_id).toMap(getResources().getConfiguration().orientation)); | ||||
|                     Ringservice.switchInput(id, uri); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         public void setPreviewSettings() { | ||||
|             getExecutor().execute(new SipRunnable() { | ||||
|                 @Override | ||||
|                 protected void doRun() throws SameThreadException, RemoteException { | ||||
|                     for (int i=0, n=Camera.getNumberOfCameras(); i<n; i++) { | ||||
|                         Ringservice.applySettings(Integer.toString(i), videoManagerCallback.getNativeParams(i).toMap(getResources().getConfiguration().orientation)); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         public int exportAccounts(final List accountIDs, final String toDir, final String password) { | ||||
|             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Integer>() { | ||||
|                 @Override | ||||
|  | ||||
| @ -82,6 +82,7 @@ interface IDRingService { | ||||
|     void attendedTransfer(in String transferID, in String targetID); | ||||
|  | ||||
|     /* Video */ | ||||
|     void setPreviewSettings(); | ||||
|     void switchInput(in String call, in boolean front); | ||||
|     void videoSurfaceAdded(in String call); | ||||
|     void videoSurfaceRemoved(in String call); | ||||
|  | ||||
| @ -182,12 +182,12 @@ public class LocalService extends Service implements SharedPreferences.OnSharedP | ||||
|             contact = findContactByNumber(call.getNumberUri()); | ||||
|         Conversation conv = startConversation(contact); | ||||
|         try { | ||||
|             mService.setPreviewSettings(); | ||||
|             SipUri number = call.getNumberUri(); | ||||
|             if (number == null || number.isEmpty()) | ||||
|                 number = contact.getPhones().get(0).getNumber(); | ||||
|             String callId = mService.placeCall(call.getAccount(), number.getUriString()); | ||||
|             if (callId == null || callId.isEmpty()) { | ||||
|                 //CallActivity.this.terminateCall(); | ||||
|                 return null; | ||||
|             } | ||||
|             call.setCallID(callId); | ||||
| @ -1335,6 +1335,12 @@ public class LocalService extends Service implements SharedPreferences.OnSharedP | ||||
|                     toAdd.showCallNotification(LocalService.this); | ||||
|                     updateAudioState(); | ||||
|  | ||||
|                     try { | ||||
|                         mService.setPreviewSettings(); | ||||
|                     } catch (RemoteException e) { | ||||
|                         e.printStackTrace(); | ||||
|                     } | ||||
|  | ||||
|                     sendBroadcast(new Intent(ACTION_CONF_UPDATE)); | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
| @ -19,21 +19,37 @@ | ||||
|  */ | ||||
| package cx.ring.service; | ||||
|  | ||||
| import android.content.res.Configuration; | ||||
| import android.hardware.Camera; | ||||
| import android.util.Log; | ||||
| import android.view.SurfaceHolder; | ||||
| import android.util.LongSparseArray; | ||||
| import android.graphics.Point; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.HashMap; | ||||
|  | ||||
|  | ||||
| public class VideoManagerCallback extends VideoCallback implements Camera.PreviewCallback | ||||
| public class VideoManagerCallback extends VideoCallback | ||||
| { | ||||
|     private static final String TAG = VideoManagerCallback.class.getSimpleName(); | ||||
|  | ||||
|     private final DRingService mService; | ||||
|     private final LongSparseArray<DeviceParams> native_params = new LongSparseArray<>(); | ||||
|     private final HashMap<String, DRingService.VideoParams> params = new HashMap<>(); | ||||
|  | ||||
|     class DeviceParams { | ||||
|         Point size; | ||||
|         long rate; | ||||
|         Camera.CameraInfo infos; | ||||
|  | ||||
|         public StringMap toMap(int orientation) { | ||||
|             StringMap p = new StringMap(); | ||||
|             boolean rotated = (size.x >  size.y) == (orientation == Configuration.ORIENTATION_PORTRAIT); | ||||
|             p.set("size", Integer.toString(rotated ? size.y : size.x) + "x" + Integer.toString(rotated ? size.x : size.y)); | ||||
|             p.set("rate", Long.toString(rate)); | ||||
|             return p; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public int cameraFront = 0; | ||||
|     public int cameraBack = 0; | ||||
|  | ||||
| @ -56,6 +72,10 @@ public class VideoManagerCallback extends VideoCallback implements Camera.Previe | ||||
|         RingserviceJNI.setDefaultDevice(Integer.toString(cameraFront)); | ||||
|     } | ||||
|  | ||||
|     DeviceParams getNativeParams(int i) { | ||||
|         return native_params.get(i); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void decodingStarted(String id, String shm_path, int w, int h, boolean is_mixer) { | ||||
|         mService.decodingStarted(id, shm_path, w, h, is_mixer); | ||||
| @ -66,17 +86,14 @@ public class VideoManagerCallback extends VideoCallback implements Camera.Previe | ||||
|         mService.decodingStopped(id); | ||||
|     } | ||||
|  | ||||
|     public void onPreviewFrame(byte[] data, Camera camera) { | ||||
|         int ptr = RingserviceJNI.obtainFrame(data.length); | ||||
|         if (ptr != 0) | ||||
|             RingserviceJNI.setVideoFrame(data, data.length, ptr); | ||||
|         RingserviceJNI.releaseFrame(ptr); | ||||
|     } | ||||
|  | ||||
|     public void setParameters(String camid, int format, int width, int height, int rate) { | ||||
|         int id = Integer.valueOf(camid); | ||||
|         DRingService.VideoParams p = new DRingService.VideoParams(id, format, width, height, rate); | ||||
|         params.put(camid, p); | ||||
|         DeviceParams p = native_params.get(id); | ||||
|         DRingService.VideoParams new_params = new DRingService.VideoParams(id, format, p.size.x, p.size.y, rate); | ||||
|         new_params.rot_width = width; | ||||
|         new_params.rot_height = height; | ||||
|         mService.setVideoRotation(new_params, p.infos); | ||||
|         params.put(camid, new_params); | ||||
|     } | ||||
|  | ||||
|     public void startCapture(String camid) { | ||||
| @ -106,15 +123,25 @@ public class VideoManagerCallback extends VideoCallback implements Camera.Previe | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Camera.CameraInfo camInfo =     new Camera.CameraInfo(); | ||||
|         Camera.getCameraInfo(id, camInfo); | ||||
|  | ||||
|         Camera.Parameters param = cam.getParameters(); | ||||
|         cam.release(); | ||||
|  | ||||
|         getFormats(param, formats); | ||||
|         getSizes(param, sizes); | ||||
|  | ||||
|         DeviceParams p = new DeviceParams(); | ||||
|         p.size = getSizeToUse(param); | ||||
|         sizes.add(p.size.x); | ||||
|         sizes.add(p.size.y); | ||||
|         sizes.add(p.size.y); | ||||
|         sizes.add(p.size.x); | ||||
|  | ||||
|         getRates(param, rates); | ||||
|         p.rate = rates.get(0); | ||||
|  | ||||
|         p.infos = new Camera.CameraInfo(); | ||||
|         Camera.getCameraInfo(id, p.infos); | ||||
|  | ||||
|         native_params.put(id, p); | ||||
|     } | ||||
|  | ||||
|     private int getNumberOfCameras() { | ||||
| @ -127,7 +154,7 @@ public class VideoManagerCallback extends VideoCallback implements Camera.Previe | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void getSizes(Camera.Parameters param, UintVect sizes) { | ||||
|     private Point getSizeToUse(Camera.Parameters param) { | ||||
|         int sw = 1280, sh = 720; | ||||
|         for(Camera.Size s : param.getSupportedPreviewSizes()) { | ||||
|             if (s.width < sw) { | ||||
| @ -136,8 +163,7 @@ public class VideoManagerCallback extends VideoCallback implements Camera.Previe | ||||
|             } | ||||
|         } | ||||
|         Log.d(TAG, "Supported size: " + sw + " x " + sh); | ||||
|         sizes.add(sw); | ||||
|         sizes.add(sh); | ||||
|         return new Point(sw, sh); | ||||
|     } | ||||
|  | ||||
|     private void getRates(Camera.Parameters param, UintVect rates_) { | ||||
|  | ||||
| @ -50,9 +50,55 @@ public: | ||||
| std::map<ANativeWindow*, std::unique_ptr<DRing::FrameBuffer>> windows {}; | ||||
| std::mutex windows_mutex; | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_cx_ring_service_RingserviceJNI_setVideoFrame(JNIEnv *jenv, jclass jcls, void * jarg1, jint jarg2, jlong jarg3) | ||||
| std::vector<uint8_t> workspace; | ||||
|  | ||||
| void rotateNV21(std::vector<uint8_t>& input, unsigned width, unsigned height, int rotation, uint8_t* output) | ||||
| { | ||||
|     jenv->GetByteArrayRegion(jarg1, 0, jarg2, jarg3); | ||||
|     if (rotation == 0) { | ||||
|         std::copy_n(input.begin(), input.size(), output); | ||||
|         return; | ||||
|     } | ||||
|     if (rotation % 90 != 0 || rotation < 0 || rotation > 270) { | ||||
|         __android_log_print(ANDROID_LOG_ERROR, "videomanager.i", "%u %u %d", width, height, rotation); | ||||
|         return; | ||||
|     } | ||||
|     unsigned frameSize = width * height; | ||||
|     bool swap      = rotation % 180 != 0; | ||||
|     bool xflip     = rotation % 270 != 0; | ||||
|     bool yflip     = rotation >= 180; | ||||
|     unsigned wOut  = swap ? height : width; | ||||
|     unsigned hOut  = swap ? width  : height; | ||||
|  | ||||
|     for (unsigned j = 0; j < height; j++) { | ||||
|         for (unsigned i = 0; i < width; i++) { | ||||
|             unsigned yIn = j * width + i; | ||||
|             unsigned uIn = frameSize + (j >> 1) * width + (i & ~1); | ||||
|             unsigned vIn = uIn + 1; | ||||
|             unsigned iSwapped = swap ? j : i; | ||||
|             unsigned jSwapped = swap ? i : j; | ||||
|             unsigned iOut     = xflip ? wOut - iSwapped - 1 : iSwapped; | ||||
|             unsigned jOut     = yflip ? hOut - jSwapped - 1 : jSwapped; | ||||
|             unsigned yOut = jOut * wOut + iOut; | ||||
|             unsigned uOut = frameSize + (jOut >> 1) * wOut + (iOut & ~1); | ||||
|             unsigned vOut = uOut + 1; | ||||
|             output[yOut] = input[yIn]; | ||||
|             output[uOut] = input[uIn]; | ||||
|             output[vOut] = input[vIn]; | ||||
|         } | ||||
|     } | ||||
|     return output; | ||||
| } | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_cx_ring_service_RingserviceJNI_setVideoFrame(JNIEnv *jenv, jclass jcls, void* frame, int frame_size, jlong target, int w, int h, int rotation) | ||||
| { | ||||
|     uint8_t* f_target = (uint8_t*) ((intptr_t) target); | ||||
|     if (rotation == 0) | ||||
|          jenv->GetByteArrayRegion(frame, 0, frame_size, f_target); | ||||
|     else { | ||||
|         workspace.resize(frame_size); | ||||
|         jenv->GetByteArrayRegion(frame, 0, frame_size, workspace.data()); | ||||
|         rotateNV21(workspace, w, h, rotation, f_target); | ||||
|     } | ||||
| } | ||||
|  | ||||
| JNIEXPORT jlong JNICALL Java_cx_ring_service_RingserviceJNI_acquireNativeWindow(JNIEnv *jenv, jclass jcls, jobject javaSurface) | ||||
| @ -60,7 +106,7 @@ JNIEXPORT jlong JNICALL Java_cx_ring_service_RingserviceJNI_acquireNativeWindow( | ||||
|     return (jlong)(intptr_t)ANativeWindow_fromSurface(jenv, javaSurface); | ||||
| } | ||||
|  | ||||
| JNIEXPORT jlong JNICALL Java_cx_ring_service_RingserviceJNI_releaseNativeWindow(JNIEnv *jenv, jclass jcls, jlong window_) | ||||
| JNIEXPORT void JNICALL Java_cx_ring_service_RingserviceJNI_releaseNativeWindow(JNIEnv *jenv, jclass jcls, jlong window_) | ||||
| { | ||||
|     std::lock_guard<std::mutex> guard(windows_mutex); | ||||
|     ANativeWindow *window = (ANativeWindow*)((intptr_t) window_); | ||||
| @ -162,7 +208,7 @@ JNIEXPORT void JNICALL Java_cx_ring_service_RingserviceJNI_unregisterVideoCallba | ||||
| } | ||||
|  | ||||
| %} | ||||
| %native(setVideoFrame) void setVideoFrame(void *, int, long); | ||||
| %native(setVideoFrame) void setVideoFrame(void*, int, jlong, int, int, int); | ||||
| %native(acquireNativeWindow) jlong acquireNativeWindow(jobject); | ||||
| %native(releaseNativeWindow) void releaseNativeWindow(jlong); | ||||
| %native(setNativeWindowGeometry) void setNativeWindowGeometry(jlong, int, int); | ||||
| @ -180,11 +226,13 @@ void stopCamera(); | ||||
| bool hasCameraStarted(); | ||||
| bool switchInput(const std::string& resource); | ||||
| bool switchToCamera(); | ||||
| std::map<std::string, std::string> getSettings(const std::string& name); | ||||
| void applySettings(const std::string& name, const std::map<std::string, std::string>& settings); | ||||
|  | ||||
| void addVideoDevice(const std::string &node); | ||||
| void removeVideoDevice(const std::string &node); | ||||
| long obtainFrame(int length); | ||||
| void releaseFrame(long frame); | ||||
| uintptr_t obtainFrame(int length); | ||||
| void releaseFrame(uintptr_t frame); | ||||
| void registerSinkTarget(const std::string& sinkId, const DRing::SinkTarget& target); | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Adrien Béraud
					Adrien Béraud