Expose common bitstream inspection and actual format checks to Android
This commit is contained in:
1 parent
68e5905d9e
commit
5e15fc0d3f
2 files changed
+29
-6
No files matched your search
@@ -2,6 +2,7 @@ package com.utun.chat.data
|
|||||||
|
|
||||||
/** Тот же C port, что у desktop: один TX mailbox, ограниченный RX, идентификатор звонка в каждой операции. */
|
/** Тот же C port, что у desktop: один TX mailbox, ограниченный RX, идентификатор звонка в каждой операции. */
|
||||||
internal object CallVideoNative {
|
internal object CallVideoNative {
|
||||||
|
init { System.loadLibrary("utun") }
|
||||||
external fun open(id: Long, caps: ByteArray): Boolean
|
external fun open(id: Long, caps: ByteArray): Boolean
|
||||||
external fun close(id: Long)
|
external fun close(id: Long)
|
||||||
external fun peer(id: Long): ByteArray?
|
external fun peer(id: Long): ByteArray?
|
||||||
@@ -13,12 +14,14 @@ internal object CallVideoNative {
|
|||||||
external fun pull(id: Long, meta: LongArray): ByteArray?
|
external fun pull(id: Long, meta: LongArray): ByteArray?
|
||||||
external fun requestKey(id: Long)
|
external fun requestKey(id: Long)
|
||||||
external fun range(id: Long, minimum: Int, maximum: Int): Boolean
|
external fun range(id: Long, minimum: Int, maximum: Int): Boolean
|
||||||
|
external fun inspect(codec: Int, bytes: ByteArray): LongArray?
|
||||||
|
external fun supported(local: ByteArray, peer: ByteArray, format: LongArray): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class CallVideoFormat(val generation: Long, val width: Int, val height: Int, val fps: Int = 30,
|
internal data class CallVideoFormat(val generation: Long, val width: Int, val height: Int, val fps: Int = 30,
|
||||||
val rotation: Int = 0, val codec: Int = 0, val level: Int = 0, val maximum: Int = 4_000_000, val vbv: Int = 1_000_000) {
|
val rotation: Int = 0, val codec: Int = 0, val level: Int = 0, val maximum: Int = 4_000_000, val profile: Int = 0) {
|
||||||
fun array() = longArrayOf(generation, width.toLong(), height.toLong(), fps.toLong(), rotation.toLong(), codec.toLong(),
|
fun array() = longArrayOf(generation, width.toLong(), height.toLong(), fps.toLong(), rotation.toLong(), codec.toLong(),
|
||||||
level.toLong(), maximum.toLong(), vbv.toLong())
|
level.toLong(), maximum.toLong(), profile.toLong())
|
||||||
companion object {
|
companion object {
|
||||||
fun from(a: LongArray) = CallVideoFormat(a[0], a[1].toInt(), a[2].toInt(), a[3].toInt(), a[4].toInt(),
|
fun from(a: LongArray) = CallVideoFormat(a[0], a[1].toInt(), a[2].toInt(), a[3].toInt(), a[4].toInt(),
|
||||||
a[5].toInt(), a[6].toInt(), a[7].toInt(), a[8].toInt())
|
a[5].toInt(), a[6].toInt(), a[7].toInt(), a[8].toInt())
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../../../src/call/call_video_port.h"
|
#include "../../../src/call/call_video_port.h"
|
||||||
|
#include "../../../src/call/call_video_bitstream.h"
|
||||||
#include "../../../lib/debug_config.h"
|
#include "../../../lib/debug_config.h"
|
||||||
#include "../../../lib/mem.h"
|
#include "../../../lib/mem.h"
|
||||||
|
|
||||||
/* LongArray format: generation,width,height,fps,rotation,codec,level,maximum_bps,vbv_bits.
|
/* LongArray format: generation,width,height,fps,rotation,codec,level,maximum_bps,profile.
|
||||||
* Frame metadata добавляет frame_id,pts_us,flags. JNI не хранит заимствованные массивы. */
|
* Frame metadata добавляет frame_id,pts_us,flags. JNI не хранит заимствованные массивы. */
|
||||||
static int read_format(JNIEnv *e, jlongArray array, struct call_video_format *f, jlong values[12], int frame) {
|
static int read_format(JNIEnv *e, jlongArray array, struct call_video_format *f, jlong values[12], int frame) {
|
||||||
if (!array || (*e)->GetArrayLength(e, array) != (frame ? 12 : 9)) goto invalid;
|
if (!array || (*e)->GetArrayLength(e, array) != (frame ? 12 : 9)) goto invalid;
|
||||||
@@ -14,7 +15,7 @@ static int read_format(JNIEnv *e, jlongArray array, struct call_video_format *f,
|
|||||||
if (values[0] <= 0 || values[1] < 16 || values[1] > 4096 || values[2] < 16 || values[2] > 4096
|
if (values[0] <= 0 || values[1] < 16 || values[1] > 4096 || values[2] < 16 || values[2] > 4096
|
||||||
|| values[3] < 1 || values[3] > 60 || values[4] < 0 || values[4] > 270 || values[4] % 90
|
|| values[3] < 1 || values[3] > 60 || values[4] < 0 || values[4] > 270 || values[4] % 90
|
||||||
|| values[5] < 0 || values[5] > 2 || values[6] < 0 || values[6] > 255
|
|| values[5] < 0 || values[5] > 2 || values[6] < 0 || values[6] > 255
|
||||||
|| values[7] < 300000 || values[7] > 4000000 || values[8] < 1 || values[8] > 16000000) goto invalid;
|
|| values[7] < 300000 || values[7] > 4000000 || values[8] < 0 || values[8] > 2) goto invalid;
|
||||||
*f = (struct call_video_format){values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8]};
|
*f = (struct call_video_format){values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8]};
|
||||||
return 0;
|
return 0;
|
||||||
invalid:
|
invalid:
|
||||||
@@ -53,7 +54,7 @@ JNIEXPORT jlongArray JNICALL Java_com_utun_chat_data_CallVideoNative_choose(
|
|||||||
(void)o; struct call_video_caps sender, receiver; struct call_video_format f; jlong values[12];
|
(void)o; struct call_video_caps sender, receiver; struct call_video_format f; jlong values[12];
|
||||||
if (read_caps(e, local, &sender) || read_caps(e, remote, &receiver) || read_format(e, desired, &f, values, 0)
|
if (read_caps(e, local, &sender) || read_caps(e, remote, &receiver) || read_format(e, desired, &f, values, 0)
|
||||||
|| call_video_choose(&sender, &receiver, &f) <= 0) return NULL;
|
|| call_video_choose(&sender, &receiver, &f) <= 0) return NULL;
|
||||||
values[5] = f.codec; values[6] = f.level;
|
values[5] = f.codec; values[6] = f.level; values[8] = f.profile;
|
||||||
jlongArray out = (*e)->NewLongArray(e, 9); if (out) (*e)->SetLongArrayRegion(e, out, 0, 9, values); return out;
|
jlongArray out = (*e)->NewLongArray(e, 9); if (out) (*e)->SetLongArrayRegion(e, out, 0, 9, values); return out;
|
||||||
}
|
}
|
||||||
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_CallVideoNative_format(
|
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_CallVideoNative_format(
|
||||||
@@ -84,7 +85,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_utun_chat_data_CallVideoNative_pull(JNIEnv
|
|||||||
struct call_video_frame f;
|
struct call_video_frame f;
|
||||||
if (call_video_port_pull(id, &f) != 1) return NULL;
|
if (call_video_port_pull(id, &f) != 1) return NULL;
|
||||||
jlong values[] = {f.format.generation, f.format.width, f.format.height, f.format.fps, f.format.rotation,
|
jlong values[] = {f.format.generation, f.format.width, f.format.height, f.format.fps, f.format.rotation,
|
||||||
f.format.codec, f.format.level, f.format.maximum_bps, f.format.vbv_bits, f.frame_id, f.pts_us, f.flags};
|
f.format.codec, f.format.level, f.format.maximum_bps, f.format.profile, f.frame_id, f.pts_us, f.flags};
|
||||||
jbyteArray out = (*e)->NewByteArray(e, f.size);
|
jbyteArray out = (*e)->NewByteArray(e, f.size);
|
||||||
if (out) { (*e)->SetByteArrayRegion(e, out, 0, f.size, (jbyte *)f.data); (*e)->SetLongArrayRegion(e, meta, 0, 12, values); }
|
if (out) { (*e)->SetByteArrayRegion(e, out, 0, f.size, (jbyte *)f.data); (*e)->SetLongArrayRegion(e, meta, 0, 12, values); }
|
||||||
else call_video_port_request_key(id);
|
else call_video_port_request_key(id);
|
||||||
@@ -96,4 +97,23 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_CallVideoNative_requestKey(JNIEnv
|
|||||||
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_CallVideoNative_range(JNIEnv *e, jobject o, jlong id, jint minimum, jint maximum) {
|
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_CallVideoNative_range(JNIEnv *e, jobject o, jlong id, jint minimum, jint maximum) {
|
||||||
(void)e; (void)o; return !call_video_port_range(id, minimum, maximum);
|
(void)e; (void)o; return !call_video_port_range(id, minimum, maximum);
|
||||||
}
|
}
|
||||||
|
JNIEXPORT jlongArray JNICALL Java_com_utun_chat_data_CallVideoNative_inspect(JNIEnv *e, jobject o, jint codec, jbyteArray bytes) {
|
||||||
|
(void)o;
|
||||||
|
if (!bytes) return NULL;
|
||||||
|
jsize size = (*e)->GetArrayLength(e, bytes);
|
||||||
|
if (size < 9 || size > CALL_VIDEO_MAX_FRAME) { DEBUG_WARN(DEBUG_CATEGORY_CALL, "video inspect JNI size=%d", size); return NULL; }
|
||||||
|
jbyte *data = (*e)->GetByteArrayElements(e, bytes, NULL); if (!data) return NULL;
|
||||||
|
struct call_video_bitstream s;
|
||||||
|
int result = call_video_inspect_key(codec, (uint8_t *)data, size, &s);
|
||||||
|
(*e)->ReleaseByteArrayElements(e, bytes, data, JNI_ABORT);
|
||||||
|
if (result) return NULL;
|
||||||
|
jlong values[] = {s.width, s.height, s.level, s.profile, s.dpb};
|
||||||
|
jlongArray out = (*e)->NewLongArray(e, 5); if (out) (*e)->SetLongArrayRegion(e, out, 0, 5, values); return out;
|
||||||
|
}
|
||||||
|
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_CallVideoNative_supported(
|
||||||
|
JNIEnv *e, jobject o, jbyteArray local, jbyteArray remote, jlongArray array) {
|
||||||
|
(void)o; struct call_video_caps sender, receiver; struct call_video_format f; jlong values[12];
|
||||||
|
return !read_caps(e, local, &sender) && !read_caps(e, remote, &receiver) && !read_format(e, array, &f, values, 0)
|
||||||
|
&& call_video_format_supported(&sender, &receiver, &f);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
Reference in new issue
Block a user