video output rotation
* Change camera settings and reinvite on screen rotation.
* Apply rotation in the JNI layer
Change-Id: I48fe8f5eb47287f964012be416875a656993e912
Tuleap: #566
diff --git a/ring-android/app/src/main/jni/videomanager.i b/ring-android/app/src/main/jni/videomanager.i
index a40d527..4fc50d3 100644
--- a/ring-android/app/src/main/jni/videomanager.i
+++ b/ring-android/app/src/main/jni/videomanager.i
@@ -50,9 +50,55 @@
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 @@
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 @@
}
%}
-%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 @@
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);
}