private ThreadLocal<byte[]> rtpBuffer = new ThreadLocal<>();
public Object GetByteArray(int type,int len)
{
byte[] bytes = rtpBuffer.get();
if(bytes == null || (len+30) >bytes.length)
{
bytes = new byte[ Math.max(2000,len+30)];
rtpBuffer.set(bytes);
}
return bytes;
}
#include <jni.h>
#include <android/log.h>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <semaphore.h>
#include <arpa/inet.h>
#include <chrono>
#include "./../include/VideoNetOptimization.h"
#include "./../include/VideoNetOptimizationReceiver.h"
#include "./../include/VideoNetOptimizationSender.h"
#define LOG_SENDER 0
#define LOG_RECEIVER 0
#define SENDER_CALLBACK_DISABLE 0
#define RECEIVER_CALLBACK_DISABLE 0
#define INTERFACE_SENDER_DISABLE 0
#define INTERFACE_RECEIVER_DISABLE 0
#define LOG_TAG "Video_NetEq"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define MAX_RTP_PAYLOAD_LEN 30000
#define MAX_H264_LEN 1920*1080*2
#define VIDEO_NAL_NUM_MAX 1200
JavaVM* g_vm = NULL;
jobject g_sender = NULL;
#if 0
class CGlobalInit
{
public:
CGlobalInit();
};
CGlobalInit::CGlobalInit()
{
VNOInitParam param;
param.ulRcvrWorkThreadNum = 2;
(void)iVNO_Init(¶m);
}
static CGlobalInit gInitVno;
#endif
#define QUOTE(x) #x
#define STR(x) QUOTE(x)
#define GetVersion Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_GetVersion_0_0_0_71_20231110
const char* str_version = STR(GetVersion);
extern "C" JNIEXPORT void GetVersion()
{
}
static long long getCurrentMs()
{
auto time_now = std::chrono::system_clock::now();
auto duration_in_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_now.time_since_epoch());
return duration_in_ms.count();
}
bool FindTag(char* pBuf, int nBufLen, char*& pFind) {
unsigned char tag[] = { 0x00, 0x00, 0x01 };
if (pBuf == NULL || nBufLen < 0)
return false;
pFind = std::search(pBuf, pBuf + nBufLen, tag, tag + 3);
if (pFind == (pBuf + nBufLen))
return false;
return true;
}
struct FragmentationInfo {
unsigned long uOffset;
unsigned long uLen;
};
#define MAX_PAYLOAD_LEN 1500
class VideoNeteqSender;
class SenderCallback: public VideoNetOptimizationSenderCallback {
public:
SenderCallback(JNIEnv * env, jclass object, jobject javaSenderCallback, VideoNeteqSender* pSender, int resolutionNum);
~SenderCallback();
void OnRTPToSend(unsigned char* pPacket, int iPacketLen);
void OnRTCPToSend(unsigned char* pPacket, int iPacketLen);
void OnBitrateChanged(uint32_t uNewBitrate, uint32_t uRefFrameRate, uint32_t uResolutionIdx, uint8_t uFrLost);
void OnRequestKeyFrame();
int Init();
private:
uint32_t CalResolutionIdx(uint32_t uNewBitrate);
JNIEnv* m_pJavaEnv;
jclass m_pObject;
jobject m_javaSenderCallback;
bool m_bIsCallInit;
bool m_bInit;
jclass m_class;
jmethodID m_methodOnRtpToSend;
jmethodID m_methodOnRtcpToSend;
jmethodID m_methodOnBitrateChanged;
jmethodID m_methodOnRequestKeyFrame;
jmethodID m_methodInit;
jmethodID m_methodGetByteArray;
jbyteArray m_sender_pRtcpBuf;
jbyteArray m_sender_pRtpBuf;
sem_t m_sem_t;
uint32_t m_uNewBitrate;
uint32_t m_uRefFrameRate;
uint32_t m_uResolutionIdx;
VideoNeteqSender *m_pSender;
uint32_t m_uResolutionNum;
uint32_t m_uPreBitrate;
uint64_t m_uPreTimeMs;
};
SenderCallback::SenderCallback(JNIEnv * env, jclass object,
jobject javaSenderCallback, VideoNeteqSender* pSender, int resolutionNum) {
m_pJavaEnv = env;
m_pObject = object;
m_javaSenderCallback = m_pJavaEnv->NewGlobalRef(javaSenderCallback);
m_bIsCallInit = false;
m_bInit = false;
m_methodOnRtpToSend = 0;
m_methodOnRtcpToSend = 0;
m_methodOnBitrateChanged = 0;
m_methodOnRequestKeyFrame = 0;
m_methodInit = 0;
m_methodGetByteArray = 0;
m_sender_pRtpBuf = NULL;
m_sender_pRtcpBuf = NULL;
m_pSender = pSender;
m_uResolutionNum = resolutionNum;
m_uPreBitrate = 2048;
m_uPreTimeMs = 0;
Init();
}
uint32_t SenderCallback::CalResolutionIdx(uint32_t uNewBitrate)
{
uint32_t ret = m_uResolutionIdx;
if (2 == m_uResolutionNum)
{
if (uNewBitrate > 650)
{
ret = 0;
}
else if (uNewBitrate < 400)
{
ret = 1;
}
}
else
{
ret = 0;
}
return ret;
}
SenderCallback::~SenderCallback() {
if (g_vm) {
bool isAttached = false;
JNIEnv* env = NULL;
if (g_vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
jint res = g_vm->AttachCurrentThread(&env, NULL);
if ((res < 0) || !env) {
env = NULL;
} else {
isAttached = true;
}
}
if (m_javaSenderCallback) {
env->DeleteGlobalRef(m_javaSenderCallback);
}
if (isAttached) {
if (g_vm->DetachCurrentThread() < 0) {
}
}
}
sem_destroy(&m_sem_t);
#if LOG_SENDER
LOGI("native : SenderCallback::~SenderCallback()");
#endif
}
int SenderCallback::Init() {
#if SENDER_CALLBACK_DISABLE
return 0;
#endif
#if LOG_SENDER
LOGI("native : SenderCallback::Init is called");
#endif
m_uNewBitrate = 0;
m_uRefFrameRate = 0;
m_uResolutionIdx = 0;
if (m_bInit)
return 0;
m_class =
m_pJavaEnv->FindClass(
"com/jiaxun/sdk/scl/media/video/VideoNetOptimizationSenderCallback");
if (m_class == NULL) {
LOGI("native : SenderCallback::Init find class failed");
m_bInit = false;
return -1;
}
m_methodOnRtpToSend = m_pJavaEnv->GetMethodID(m_class, "OnRTPToSend",
"([BI)V");
if (m_methodOnRtpToSend == NULL) {
LOGI("native : SenderCallback::Init get method OnRTPToSend failed");
return -1;
}
m_methodOnRtcpToSend = m_pJavaEnv->GetMethodID(m_class, "OnRTCPToSend",
"([BI)V");
if (m_methodOnRtcpToSend == NULL) {
LOGI("native : SenderCallback::Init get method OnRTCPToSend failed");
return -1;
}
m_methodOnBitrateChanged = m_pJavaEnv->GetMethodID(m_class,
"OnBitrateChanged", "(IIIIJ)V");
if (m_methodOnBitrateChanged == NULL) {
LOGI(
"native : SenderCallback::Init get method OnBitrateChanged failed");
return -1;
}
m_methodOnRequestKeyFrame = m_pJavaEnv->GetMethodID(m_class,
"OnRequestKeyFrame", "(J)V");
if (m_methodOnRequestKeyFrame == NULL) {
LOGI(
"native : SenderCallback::Init get method OnRequestKeyFrame failed");
return -1;
}
m_methodGetByteArray = m_pJavaEnv->GetMethodID(m_class, "GetByteArray",
"(II)Ljava/lang/Object;");
if (m_methodGetByteArray == NULL)
{
LOGI("native : SenderCallback::Init find method GetByteArray failed");
return -1;
}
sem_init (&m_sem_t, 0, 1);
m_bInit = true;
#if LOG_SENDER
LOGI("native : SenderCallback::Init success");
#endif
return 0;
}
void SenderCallback::OnRTPToSend(unsigned char* pPacket, int iPacketLen) {
sem_wait(&m_sem_t);
#if SENDER_CALLBACK_DISABLE
return ;
#endif
#if LOG_SENDER
LOGI("native : SenderCallback::OnRTPToSend is called");
#endif
if (!m_bInit) {
if (Init() < 0)
{
sem_post(&m_sem_t);
return;
}
}
JNIEnv* env = NULL;
bool bIsAttached = false;
int ret = 0;
ret = g_vm->GetEnv((void**) &env, JNI_VERSION_1_4);
if (ret != JNI_OK) {
ret = g_vm->AttachCurrentThread(&env, NULL);
if (ret < 0 || !env) {
LOGI(
"native : SenderCallback::OnRTPToSend AttachCurrentThread failed");
sem_post(&m_sem_t);
return;
} else {
bIsAttached = true;
}
}
jobject jObj = env->CallObjectMethod(m_javaSenderCallback, m_methodGetByteArray, (jint)0, (jint)iPacketLen);
jbyteArray rtpArray = (jbyteArray)jObj;
#if 1
env->SetByteArrayRegion(rtpArray, 0, iPacketLen, (jbyte*) pPacket);
env->CallVoidMethod(m_javaSenderCallback, m_methodOnRtpToSend,
rtpArray, iPacketLen);
#else
m_sender_pRtpBuf = env->NewByteArray(iPacketLen);
env->SetByteArrayRegion(m_sender_pRtpBuf, 0, iPacketLen, (jbyte*) pPacket);
env->CallVoidMethod(m_javaSenderCallback, m_methodOnRtpToSend,
m_sender_pRtpBuf, iPacketLen);
#endif
if (bIsAttached)
g_vm->DetachCurrentThread();
#if LOG_SENDER
LOGI("native : SenderCallback::OnRTPToSend success");
#endif
sem_post(&m_sem_t);
}
void SenderCallback::OnRTCPToSend(unsigned char* pPacket, int iPacketLen) {
sem_wait(&m_sem_t);
#if SENDER_CALLBACK_DISABLE
return ;
#endif
#if LOG_SENDER
LOGI("native : SenderCallback::OnRTCPToSend is called");
#endif
if (!m_bInit) {
if (Init() < 0)
{
sem_post(&m_sem_t);
return;
}
}
JNIEnv* env = NULL;
bool bIsAttached = false;
int ret = 0;
ret = g_vm->GetEnv((void**) &env, JNI_VERSION_1_4);
if (ret != JNI_OK) {
ret = g_vm->AttachCurrentThread(&env, NULL);
if (ret < 0 || !env) {
LOGI(
"native : SenderCallback::OnRTCPToSend AttachCurrentThread failed");
sem_post(&m_sem_t);
return;
} else {
bIsAttached = true;
}
}
m_sender_pRtcpBuf = env->NewByteArray(iPacketLen + 30);
env->SetByteArrayRegion(m_sender_pRtcpBuf, 0, iPacketLen, (jbyte*) pPacket);
env->CallVoidMethod(m_javaSenderCallback, m_methodOnRtcpToSend,
m_sender_pRtcpBuf, iPacketLen);
if (bIsAttached)
g_vm->DetachCurrentThread();
#if LOG_SENDER
LOGI("native : SenderCallback::OnRTCPToSend is success");
#endif
sem_post(&m_sem_t);
}
void SenderCallback::OnBitrateChanged(uint32_t uNewBitrate, uint32_t uRefFrameRate, uint32_t uResolutionIdx, uint8_t uFrLost) {
#if SENDER_CALLBACK_DISABLE
return ;
#endif
bool bSkip = false;
if (uNewBitrate == m_uNewBitrate
&& uRefFrameRate == m_uRefFrameRate
&& uResolutionIdx == m_uResolutionIdx)
{
bSkip = true;
}
#if LOG_SENDER
LOGI("native : SenderCallback::OnBitrateChanged is called uNewBitrate(kbps)=%d uRefFrameRate=%d,uResloution:%d,uLost(255):%d,skip:%d.",uNewBitrate,uRefFrameRate,uResolutionIdx,uFrLost,bSkip);
#endif
if (bSkip)
{
return;
}
if (!m_bInit) {
if (Init() < 0)
return;
}
JNIEnv* env = NULL;
bool bIsAttached = false;
int ret = 0;
ret = g_vm->GetEnv((void**) &env, JNI_VERSION_1_4);
if (ret != JNI_OK) {
ret = g_vm->AttachCurrentThread(&env, NULL);
if (ret < 0 || !env) {
LOGI(
"native : SenderCallback::OnBitrateChanged AttachCurrentThread failed");
return;
} else {
bIsAttached = true;
}
}
int uLost = uFrLost * 100 / 255;
int32_t diff = (int32_t)std::abs((long)(uNewBitrate - m_uPreBitrate));
float t_scale = diff * 1.0f / m_uPreBitrate;
bool t_isUpdate = false;
uint64_t t_curTime = getCurrentMs();
#if 0
if (t_scale > 0.2f)
{
t_isUpdate = true;
}
else if (t_scale >= 0.05f && t_scale <= 0.2f)
{
if (t_curTime - m_uPreTimeMs > 2000)
{
t_isUpdate = true;
}
}
#else
t_isUpdate = true;
#endif
LOGI("native : SenderCallback::OnBitrateChanged uNewBitrate:%d m_uPreBitrate:%d t_scale:%f difTime:%lld t_isUpdate:%d .", uNewBitrate, m_uPreBitrate, t_scale,t_curTime-m_uPreTimeMs, t_isUpdate);
if (t_isUpdate)
{
m_uResolutionIdx = CalResolutionIdx(uNewBitrate);
int t_uNewBitrate = (int)uNewBitrate * 1000;
LOGI("native : SenderCallback::OnBitrateChanged is called uNewBitrate(kbps)=%d t_uNewBitrate:%d uRefFrameRate=%d,m_uResolutionIdx:%d,uLost(255):%d,skip:%d.", uNewBitrate, t_uNewBitrate, uRefFrameRate, m_uResolutionIdx, uFrLost, bSkip);
env->CallVoidMethod(m_javaSenderCallback, m_methodOnBitrateChanged,
t_uNewBitrate, (int)uRefFrameRate, m_uResolutionIdx, uLost, (jlong)m_pSender);
m_uNewBitrate = uNewBitrate;
m_uRefFrameRate = uRefFrameRate;
m_uPreTimeMs = t_curTime;
m_uPreBitrate = uNewBitrate;
}
if (bIsAttached)
g_vm->DetachCurrentThread();
#if LOG_SENDER
LOGI("native : SenderCallback::OnBitrateChanged success");
#endif
}
void SenderCallback::OnRequestKeyFrame() {
#if SENDER_CALLBACK_DISABLE
return ;
#endif
#if LOG_SENDER
LOGI("native : SenderCallback::OnRequestKeyFrame is called");
#endif
if (!m_bInit) {
if (Init() < 0)
return;
}
JNIEnv* env = NULL;
bool bIsAttached = false;
int ret = 0;
ret = g_vm->GetEnv((void**) &env, JNI_VERSION_1_4);
if (ret != JNI_OK) {
ret = g_vm->AttachCurrentThread(&env, NULL);
if (ret < 0 || !env) {
LOGI(
"native : SenderCallback::OnBitrateChanged AttachCurrentThread failed");
return;
} else {
bIsAttached = true;
}
}
env->CallVoidMethod(m_javaSenderCallback, m_methodOnRequestKeyFrame, (jlong)this);
if (bIsAttached)
g_vm->DetachCurrentThread();
#if LOG_SENDER
LOGI("native : SenderCallback::OnRequestKeyFrame success");
#endif
}
class ReceiverCallback: public VideoNetOptimizationReceiverCallback {
public:
ReceiverCallback(JNIEnv * env, jclass object, jobject javaReceiverCallback,
jint width, jint height);
~ReceiverCallback();
void OnVideoFrame(void* uUserData, const unsigned char* pFrame,
uint32_t uFrameLen, const VideoFrameInfo* pFrameInfo,
const VNO_RTPFragmentationHeader* pFragmentation);
void OnRTCPToSend(void* uUserData, const unsigned char* pPacket,
int iPacketLen);
int Init();
private:
JNIEnv* m_pJavaEnv;
jclass m_pObject;
jobject m_javaReceiverCallback;
bool m_bIsCallInit;
bool m_bInit;
jclass m_class;
jmethodID m_methodOnVideoFrame;
jmethodID m_methodOnRTCPToSend;
jmethodID m_methodGetByteArray;
jbyteArray m_receiver_pRtcpBuf;
jbyteArray m_nal_pBuf;
jint bufferSize;
};
ReceiverCallback::ReceiverCallback(JNIEnv * env, jclass object,
jobject javaReceiverCallback, jint width, jint height) {
m_pJavaEnv = env;
m_pObject = object;
m_javaReceiverCallback = m_pJavaEnv->NewGlobalRef(javaReceiverCallback);
m_bIsCallInit = false;
m_bInit = false;
m_class = 0;
m_methodOnVideoFrame = 0;
m_methodOnRTCPToSend = 0;
m_methodGetByteArray = 0;
m_receiver_pRtcpBuf = NULL;
m_nal_pBuf = NULL;
bufferSize = width * height * 3 / 2;
Init();
}
ReceiverCallback::~ReceiverCallback() {
if (g_vm) {
bool isAttached = false;
JNIEnv* env = NULL;
if (g_vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
jint res = g_vm->AttachCurrentThread(&env, NULL);
if ((res < 0) || !env) {
env = NULL;
} else {
isAttached = true;
}
}
if (m_javaReceiverCallback) {
env->DeleteGlobalRef(m_javaReceiverCallback);
}
if (isAttached) {
if (g_vm->DetachCurrentThread() < 0) {
}
}
}
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::~ReceiverCallback() success");
#endif
}
int ReceiverCallback::Init() {
#if RECEIVER_CALLBACK_DISABLE
return 0;
#endif
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::Init is called");
#endif
if (m_bInit)
return 0;
m_class =
m_pJavaEnv->FindClass(
"com/jiaxun/sdk/scl/media/video/VideoNetOptimizationReceiverCallback");
if (m_class == NULL) {
LOGI("native : ReceiverCallback::Init FindClass failed");
return -1;
}
m_methodOnVideoFrame = m_pJavaEnv->GetMethodID(m_class, "OnVideoFrame",
"(J[BJI)V");
if (m_methodOnVideoFrame == NULL) {
LOGI(
"native : ReceiverCallback::Init find method m_methodOnVideoFrame failed");
return -1;
}
m_methodOnRTCPToSend = m_pJavaEnv->GetMethodID(m_class, "OnRTCPToSend",
"([BI)V");
if (m_methodOnRTCPToSend == NULL) {
LOGI("native : ReceiverCallback::Init find method OnRTCPToSend failed");
return -1;
}
m_methodGetByteArray = m_pJavaEnv->GetMethodID(m_class, "GetByteArray",
"(II)Ljava/lang/Object;");
if (m_methodGetByteArray == NULL)
{
LOGI("native : ReceiverCallback::Init find method GetByteArray failed");
return -1;
}
m_bInit = true;
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::Init is success");
#endif
return 0;
}
void ReceiverCallback::OnVideoFrame(void* uUserData, const unsigned char* pFrame,
uint32_t uFrameLen, const VideoFrameInfo* pFrameInfo,
const VNO_RTPFragmentationHeader* pFragmentation) {
#if RECEIVER_CALLBACK_DISABLE
return ;
#endif
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::OnVideoFrame is called");
#endif
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::OnVideoFrame type:%d, bComplete:%d, bContinue:%d, len:%d.",
pFrameInfo->eFrameType, pFrameInfo->bComplete, pFrameInfo->bContinue, uFrameLen);
#endif
if (!m_bInit) {
if (Init() < 0)
return;
}
if (pFrameInfo->eFrameType == VNO_FRAMETYPE_SEI)
{
return;
}
uUserData = (void *)pFrameInfo->eFrameType;
JNIEnv* env = NULL;
bool bIsAttached = false;
int ret = 0;
ret = g_vm->GetEnv((void**) &env, JNI_VERSION_1_4);
if (ret != JNI_OK) {
ret = g_vm->AttachCurrentThread(&env, NULL);
if (ret < 0 || !env) {
LOGI(
"native : ReceiverCallback::OnVideoFrame AttachCurrentThread failed");
return;
} else {
bIsAttached = true;
}
}
for(int k = 0; k < pFragmentation->fragmentationVectorSize; k ++)
{
jobject jObj = env->CallObjectMethod(m_javaReceiverCallback, m_methodGetByteArray, (jint)0, (jint)pFragmentation->fragmentationLength[k]);
jbyteArray rtpArray = (jbyteArray)jObj;
#if 1
env->SetByteArrayRegion(rtpArray, 0, pFragmentation->fragmentationLength[k], (jbyte*) pFrame + pFragmentation->fragmentationOffset[k]);
env->CallVoidMethod(m_javaReceiverCallback, m_methodOnVideoFrame,
(jlong) uUserData, rtpArray, (jlong) pFragmentation->fragmentationLength[k], (jint)pFrameInfo->eFrameType);
#else
m_nal_pBuf = env->NewByteArray(uFrameLen + 1);
env->SetByteArrayRegion(m_nal_pBuf, 0, uFrameLen, (jbyte*) pFrame);
env->CallVoidMethod(m_javaReceiverCallback, m_methodOnVideoFrame,
(jlong) uUserData, m_nal_pBuf, (jlong) uFrameLen, (jint)pFrameInfo->eFrameType);
#endif
}
if (bIsAttached)
g_vm->DetachCurrentThread();
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::OnVideoFrame success");
#endif
}
void ReceiverCallback::OnRTCPToSend(void* uUserData,
const unsigned char* pPacket, int iPacketLen) {
#if RECEIVER_CALLBACK_DISABLE
return ;
#endif
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::OnRTCPToSend is called");
#endif
if (!m_bInit) {
if (Init() < 0)
return;
}
JNIEnv* env = NULL;
bool bIsAttached = false;
int ret = 0;
ret = g_vm->GetEnv((void**) &env, JNI_VERSION_1_4);
if (ret != JNI_OK) {
ret = g_vm->AttachCurrentThread(&env, NULL);
if (ret < 0 || !env) {
LOGI(
"native : ReceiverCallback::OnRTCPToSend AttachCurrentThread failed");
return;
} else {
bIsAttached = true;
}
}
#if LOG_RECEIVER
LOGI("ReceiverCallback::OnRTCPToSend iPacketLen : %d", iPacketLen);
#endif
m_receiver_pRtcpBuf = env->NewByteArray(iPacketLen + 30);
env->SetByteArrayRegion(m_receiver_pRtcpBuf, 0, iPacketLen,
(jbyte*) pPacket);
env->CallVoidMethod(m_javaReceiverCallback, m_methodOnRTCPToSend,
m_receiver_pRtcpBuf, iPacketLen);
if (bIsAttached)
g_vm->DetachCurrentThread();
#if LOG_RECEIVER
LOGI("native : ReceiverCallback::OnRTCPToSend success");
#endif
}
typedef struct VideoNeteqSender {
VideoNetOptimizationSender* m_pSender;
SenderCallback* m_pSenderCallback;
FragmentationInfo* m_pFragmentationInfos;
char* m_pH264Buf;
char* m_pRtcpBuf;
VideoNeteqSender();
~VideoNeteqSender();
} VideoNeteqSender;
VideoNeteqSender::VideoNeteqSender() {
m_pSender = NULL;
m_pSenderCallback = NULL;
m_pH264Buf = new char[MAX_H264_LEN];
m_pRtcpBuf = new char[MAX_RTP_PAYLOAD_LEN];
m_pFragmentationInfos = (FragmentationInfo*) malloc(
VIDEO_NAL_NUM_MAX * sizeof(FragmentationInfo));
}
VideoNeteqSender::~VideoNeteqSender() {
LOGI("VideoNeteqSender : 1");
if (m_pSender) {
delete m_pSender;
m_pSender = NULL;
}
LOGI("VideoNeteqSender : 2");
if (m_pRtcpBuf) {
delete[] m_pRtcpBuf;
m_pRtcpBuf = NULL;
}
LOGI("VideoNeteqSender : 3 ");
if (m_pH264Buf) {
delete[] m_pH264Buf;
m_pH264Buf = NULL;
}
LOGI("VideoNeteqSender : 4 m_pSenderCallback=%p", m_pSenderCallback);
if (m_pSenderCallback) {
delete m_pSenderCallback;
m_pSenderCallback = NULL;
}
LOGI("VideoNeteqSender : 5");
if (m_pFragmentationInfos) {
free(m_pFragmentationInfos);
m_pFragmentationInfos = NULL;
}
LOGI("VideoNeteqSender : 6");
}
typedef struct VideoNeteqReceiver {
VideoNetOptimizationReceiver* m_pReceiver;
ReceiverCallback* m_pReceiverCallback;
char* m_pRtpBuf;
char* m_pRtcpBuf;
bool m_bRecvedFrame;
VideoNeteqReceiver();
~VideoNeteqReceiver();
} VideoNeteqReceiver;
VideoNeteqReceiver::VideoNeteqReceiver() {
m_pReceiver = NULL;
m_pReceiverCallback = NULL;
m_pRtpBuf = new char[MAX_RTP_PAYLOAD_LEN];
m_pRtcpBuf = new char[MAX_RTP_PAYLOAD_LEN];
m_bRecvedFrame = false;
}
VideoNeteqReceiver::~VideoNeteqReceiver() {
LOGI("VideoNeteqReceiver 1");
if (m_pReceiver) {
delete m_pReceiver;
m_pReceiver = NULL;
}
LOGI("VideoNeteqReceiver 2");
if (m_pReceiverCallback) {
delete m_pReceiverCallback;
m_pReceiverCallback = NULL;
}
LOGI("VideoNeteqReceiver 3");
if (m_pRtpBuf) {
delete m_pRtpBuf;
m_pRtpBuf = NULL;
}
LOGI("VideoNeteqReceiver 4");
}
#ifndef _Included_com_jiaxun_sdk_scl_media_video_LibVideoNeteq
#define _Included_com_jiaxun_sdk_scl_media_video_LibVideoNeteq
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void *reserved) {
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
return -1;
g_vm = vm;
LOGI("native : JNI_OnLoad VNO2 version:%s \n", str_version);
return JNI_VERSION_1_4;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_iVNO_1Init(
JNIEnv * env, jclass object, jint nNum) {
int threadNum = nNum;
LOGI("native : iVNO_1Init is called i=%d do nothing and return ", threadNum);
return 0;
VNOInitParam param;
param.ulRcvrWorkThreadNum = threadNum;
(void)iVNO_Init(¶m);
return threadNum;
}
JNIEXPORT void JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_vVNO_1Unint(
JNIEnv * env, jclass object) {
LOGI("native : vVNO_1Unint is called");
return;
}
JNIEXPORT jlong JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_CreateVideoNetOptimizationReceiver(
JNIEnv * env, jclass object, jint nEncType, jint nPayloadType,
jint nVideoProtectType, jboolean bUseRcvThread,
jboolean bUseDecodeThread, jint eFrameCbMode, jobject objCallback,
jint width, jint height, jint nJxredPayloadType,
jint eEstimateMethod, jint iTransportSequenceNumberID, jint iDuration) {
#if LOG_RECEIVER
LOGI("native : CreateVideoNetOptimizationReceiver receiver is called\n");
#endif
VideoNeteqReceiver* pReceiver = new VideoNeteqReceiver();
if (pReceiver == NULL) {
LOGI("native : new VideoNeteqReceiver failed\n");
return 0;
}
pReceiver->m_pReceiverCallback = new ReceiverCallback(env, object,
objCallback, width, height);
if (pReceiver->m_pReceiverCallback == NULL) {
LOGI("native : new receiver callback failed\n");
delete pReceiver;
pReceiver = NULL;
return 0;
}
VideoNetOptimizationReceiverParameter oParameter;
oParameter.eCodecType = (VideoNetOptimizationCodecType) nEncType;
oParameter.m_PayloadType = (unsigned char) nPayloadType;
oParameter.m_eProtectionMethod =
(VideoNetOptimizationProtectionMethod) nVideoProtectType;
oParameter.pCallback = pReceiver->m_pReceiverCallback;
if (oParameter.m_eProtectionMethod == VNO_ProtectionMethodJxredOnly
|| oParameter.m_eProtectionMethod == VNO_ProtectionMethodHybridNackAndJxred)
{
oParameter.m_uJxredType = nJxredPayloadType;
}
oParameter.m_eRemoteBitrateEstimateMethod = (VnoRemoteBitrateEstimateMethod)eEstimateMethod;
oParameter.m_TransportSequenceNumberID = iTransportSequenceNumberID;
oParameter.m_bEnableFrameBuffer= true;
oParameter.m_iDuration = iDuration;
#if LOG_RECEIVER
LOGI("native : CreateVideoNetOptimizationReceiver para, method:%d, thread:%d, decode:%d, mode:%d, jxred:%d", oParameter.eProtectionMethod,
oParameter.bUseRcvThread, oParameter.bUseDecodeThread, oParameter.eFrameCbMode, nJxredPayloadType);
#endif
pReceiver->m_pReceiver =
VideoNetOptimizationReceiver::pCreateVideoNetOptimizationReceiver(
oParameter);
if (pReceiver->m_pReceiver == NULL) {
LOGI("native : CreateVideoNetOptimizationReceiver failed\n");
delete pReceiver;
pReceiver = NULL;
return 0;
}
#if LOG_RECEIVER
LOGI("native : CreateVideoNetOptimizationReceiver receiver is success\n");
#endif
LOGI("native : JNI_OnLoad VNO2 version:%s \n", str_version);
return (jlong) pReceiver;
}
JNIEXPORT void JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_DestroyVideoNetOptimizationReceiver(
JNIEnv * env, jclass object, jlong handle) {
#if LOG_RECEIVER
LOGI("native : DestroyVideoNetOptimizationReceiver receiver is called");
#endif
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) handle;
if (pReceiver) {
delete pReceiver;
pReceiver = NULL;
}
#if LOG_RECEIVER
LOGI("native : DestroyVideoNetOptimizationReceiver receiver is success");
#endif
return;
}
typedef struct RTP_FIXED_HEADER{
unsigned char csrc_len : 4;
unsigned char extension : 1;
unsigned char padding : 1;
unsigned char version : 2;
unsigned char payload : 7;
unsigned char marker : 1;
unsigned short seq_no;
unsigned long timestamp;
unsigned long ssrc;
} RTP_FIXED_HEADER;
typedef struct RTP_EXTENSION
{
unsigned short byProfile;
unsigned short len;
}RTP_EXTENSION;
#define DEBUG_INCOMING
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_IncomingRtpPacket(
JNIEnv * env, jclass object, jlong handle, jbyteArray rtpStream,
jint len, jint offset) {
#if INTERFACE_RECEIVER_DISABLE
return 0;
#endif
#if LOG_RECEIVER
LOGI("native : IncomingRtpPacket is called");
if(len > 1500)
{
LOGI("native : IncomingRtpPacket len=%d",len);
}
#endif
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) handle;
int ret = 0;
if (pReceiver == NULL) {
LOGI("native : IncomingRtpPacket pReceiver == NULL return");
return -1;
}
if(len > MAX_RTP_PAYLOAD_LEN)
{
LOGI("##########################################################native : IncomingRtpPacket len =%d",len);
return -1;
}
if (pReceiver->m_pRtpBuf) {
env->GetByteArrayRegion(rtpStream, 0, len, (jbyte*) pReceiver->m_pRtpBuf);
RTP_FIXED_HEADER *pRtpHeader = (RTP_FIXED_HEADER *)pReceiver->m_pRtpBuf;
#if LOG_RECEIVER
LOGI("native : IncomingRtpPacket GetByteArrayRegion OK, this:%p, ext:%d, len:%d", pReceiver, pRtpHeader->extension, len);
#endif
#if 0
if (pRtpHeader->extension)
{
uint32_t extLen;
RTP_EXTENSION *pExtHeader;
uint32_t headLen = sizeof(*pRtpHeader) + pRtpHeader->csrc_len * sizeof(uint32_t);
pExtHeader = (RTP_EXTENSION *)((char *)pRtpHeader + headLen);
extLen = sizeof(*pExtHeader) + ((pExtHeader->len >> 8) | ((pExtHeader->len & 0xff) << 8)) * 4;
#if LOG_RECEIVER
LOGI("native : IncomingRtpPacket GetByteArrayRegion OK, headLen:%d, extLen:%d", headLen, extLen);
#endif
memmove(pExtHeader, (char *)pExtHeader + extLen, len - headLen - extLen);
len -= extLen;
pRtpHeader->extension = 0;
}
#endif
#if LOG_RECEIVER
LOGI("native : IncomingRtpPacket clear rtp ext OK, payload:%d, len:%d, ssrc:0x%08x, seq:%d.", pRtpHeader->payload, len, ntohl(pRtpHeader->ssrc), ntohs(pRtpHeader->seq_no));
#endif
bool bRetransmit = false;
ret = pReceiver->m_pReceiver->IncomingRtpPacket(
(unsigned char*) pReceiver->m_pRtpBuf, len, bRetransmit);
#if LOG_RECEIVER
LOGI("native : IncomingRtpPacket call c++ interface OK, bRetransmit:%d", bRetransmit);
#endif
if (!pReceiver->m_bRecvedFrame)
{
pReceiver->m_pReceiver->RequestKeyFrame();
pReceiver->m_bRecvedFrame = true;
}
#if LOG_RECEIVER
LOGI("native : IncomingRtpPacket return");
#endif
return ret;
}
LOGI("native : IncomingRtpPacket is failed return -1");
return -1;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_ReceiverIncomingRtcpPacket(
JNIEnv * env, jclass object, jlong handle, jbyteArray rtcpStream,
jint len) {
#if INTERFACE_RECEIVER_DISABLE
return 0;
#endif
#if LOG_RECEIVER
LOGI("native : ReceiverIncomingRtcpPacket is called");
#endif
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) handle;
if (pReceiver == NULL) {
LOGI("native : IncomingRtpPacket pReceiver == NULL return");
return -1;
}
if (pReceiver->m_pRtcpBuf) {
env->GetByteArrayRegion(rtcpStream, 0, len,
(jbyte*) pReceiver->m_pRtcpBuf);
#if LOG_RECEIVER
LOGI("native : ReceiverIncomingRtcpPacket is success");
#endif
return pReceiver->m_pReceiver->IncomingRtcpPacket(
(unsigned char*) pReceiver->m_pRtcpBuf, len);
}
#if LOG_RECEIVER
LOGI("native : ReceiverIncomingRtcpPacket is failed return -1");
#endif
return 0;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_GetReceiverStatistics(
JNIEnv * env, jclass object, jlong handle, jobject infoObject) {
#if INTERFACE_RECEIVER_DISABLE
return 0;
#endif
#if LOG_RECEIVER
LOGI("native : GetReceiverStatistics is called");
#endif
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) handle;
if (pReceiver == NULL) {
LOGI("native : IncomingRtpPacket pReceiver == NULL return");
return -1;
}
jclass recInfo = env->FindClass(
"com/jiaxun/sdk/scl/media/video/VideoReceiverStatistics");
if (recInfo == 0) {
LOGI("native : find class VideoReceiverStatistics failed return ");
return -1;
}
jfieldID uPeerSsrcID = env->GetFieldID(recInfo, "uPeerSsrc", "J");
jfieldID uFractionLostID = env->GetFieldID(recInfo, "uFractionLost", "J");
jfieldID uCumulativeLostID = env->GetFieldID(recInfo, "uCumulativeLost",
"J");
jfieldID uJitterID = env->GetFieldID(recInfo, "uJitter", "J");
jfieldID uBpsID = env->GetFieldID(recInfo, "uBps", "J");
jfieldID uFractionOutOfOrderID = env->GetFieldID(recInfo,
"uFractionOutOfOrder", "J");
jfieldID uOutOfOrderDiffMaxID = env->GetFieldID(recInfo,
"uOutOfOrderDiffMax", "J");
jfieldID uRBEUpdateEstimateID = env->GetFieldID(recInfo,
"uRBEUpdateEstimate", "J");
jfieldID uKeyFrameRequestCtrID = env->GetFieldID(recInfo,
"uKeyFrameRequestCtr", "J");
VideoReceiverStatistics* pStatistics =
pReceiver->m_pReceiver->GetStatistics();
env->SetLongField(infoObject, uPeerSsrcID, pStatistics->uPeerSsrc);
env->SetLongField(infoObject, uFractionLostID, pStatistics->uFractionLost);
env->SetLongField(infoObject, uCumulativeLostID,
pStatistics->uCumulativeLost);
env->SetLongField(infoObject, uJitterID, pStatistics->uJitter);
env->SetLongField(infoObject, uBpsID, pStatistics->uBps);
env->SetLongField(infoObject, uFractionOutOfOrderID,
pStatistics->uFractionOutOfOrder);
env->SetLongField(infoObject, uOutOfOrderDiffMaxID,
pStatistics->uOutOfOrderDiffMax);
env->SetLongField(infoObject, uRBEUpdateEstimateID,
pStatistics->uRBEUpdateEstimate);
env->SetLongField(infoObject, uKeyFrameRequestCtrID,
pStatistics->uKeyFrameRequestCtr);
jfieldID uFrameRateID = env->GetFieldID(recInfo,
"uFrameRate", "J");
jfieldID uRttID = env->GetFieldID(recInfo,
"uRtt", "J");
env->SetLongField(infoObject, uFrameRateID,
pStatistics->uFrameRate);
env->SetLongField(infoObject, uRttID,
pStatistics->uRtt);
#if LOG_RECEIVER
LOGI("native : GetReceiverStatistics is success");
#endif
return 0;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_GetReceiverNetworkStatus(
JNIEnv * env, jclass object, jlong handle, jbyteArray passRateArray, jintArray oInfoArray) {
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) handle;
if (pReceiver == NULL) {
LOGI("native : GetReceiverNetworkStatus pReceiver == NULL return");
return -1;
}
jint length = env->GetArrayLength(passRateArray);
if(length < 2)
{
return -2;
}
int32_t iPassRateRemote = 0;
int32_t iPassRateLocal = 0;
int32_t iDownstreamBandWidth = 0;
pReceiver->m_pReceiver->GetNetworkStatus(iPassRateRemote, iPassRateLocal, iDownstreamBandWidth);
jbyte c_array[2];
jint c_array_size=2;
c_array[0] = iPassRateRemote;
c_array[1] = iPassRateLocal;
env->SetByteArrayRegion(passRateArray,0,c_array_size,c_array);
env->SetIntArrayRegion(oInfoArray,0,1, &iDownstreamBandWidth);
return 0;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_GetExtraDelay(
JNIEnv * env, jclass object, jlong handle) {
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) handle;
if (pReceiver == NULL) {
LOGI("native : GetExtraDelay pReceiver == NULL return");
return -1;
}
VideoReceiverStatistics* pStatistics =
pReceiver->m_pReceiver->GetStatistics();
int32_t tuFractionLost = pStatistics->uFractionLost;
int32_t tuRtt = pStatistics->uRtt;
tuRtt = tuRtt < 30 ? 30 : tuRtt;
int32_t tDelay = 0.133f * tuFractionLost * tuRtt;
return tDelay;
}
JNIEXPORT jlong JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_CreateVideoNetOptimizationSender(
JNIEnv * env, jclass object, jint nType, jbyte uPaylaodType,
jlong uStartBitrate, jint uLowestPercentage, jint uResolutionNum, jobject senderCallback, jbyte uJxredPayloadType,
jint eEstimateMethod, jint iTransportSequenceNumberID,jint iStreamType, jint nEncType, jint iDuration) {
#if LOG_SENDER
LOGI("native : CreateVideoNetOptimizationSender is called");
#endif
VideoNeteqSender* pSender = new VideoNeteqSender();
pSender->m_pSenderCallback = new SenderCallback(env, object,
senderCallback, pSender, uResolutionNum);
if (pSender->m_pSenderCallback == NULL) {
LOGI("native : Create Sender:: new SenderCallback failed");
delete pSender;
return 0;
}
LOGI("CreateVideoNetOptimizationSender callback: %p, bitrate:%lld, per:%d, resolution:%d iStreamType: %d",
pSender->m_pSenderCallback, uStartBitrate, uLowestPercentage, uResolutionNum, iStreamType);
VideoNetOptimizationCodecType peCodecType[1];
uint8_t puPaylaodType[1];
peCodecType[0] = (VideoNetOptimizationCodecType)nEncType;
puPaylaodType[0] = uPaylaodType;
VideoNetOptimizationSenderParameter oParameter;
oParameter.m_eProtectionMethod = (VideoNetOptimizationProtectionMethod) nType;
oParameter.peCodecType[0] = peCodecType[0];
oParameter.m_uLowestBitratePercentage = uLowestPercentage;
oParameter.m_uResolutionNum = uResolutionNum;
oParameter.m_uStartBitrate = uStartBitrate/1000;
oParameter.pCallback = pSender->m_pSenderCallback;
oParameter.m_PaylaodType[0] = puPaylaodType[0];
oParameter.m_uPayloadNum = 1;
oParameter.m_eRemoteBitrateEstimateMethod = (VnoRemoteBitrateEstimateMethod)eEstimateMethod;
oParameter.m_TransportSequenceNumberID = iTransportSequenceNumberID;
oParameter.m_iUpdateOnBitRateType = 2;
oParameter.m_iDuration = iDuration;
if (1 == iStreamType)
{
oParameter.m_uRscodeM[RsMLowLost] = 12;
oParameter.m_uRscodeM[RsMMidLost] = 12;
oParameter.m_uRscodeM[RsMHighLost] = 12;
}
if (oParameter.m_eProtectionMethod == VNO_ProtectionMethodJxredOnly
|| oParameter.m_eProtectionMethod == VNO_ProtectionMethodHybridNackAndJxred)
{
oParameter.m_uJxredType = uJxredPayloadType;
}
pSender->m_pSender =
VideoNetOptimizationSender::pCreateVideoNetOptimizationSender(
oParameter);
LOGI("CreateVideoNetOptimizationSender : %p", pSender->m_pSender);
if (pSender->m_pSender == NULL) {
LOGI("native : Create Sender:: new m_pSender failed");
delete pSender;
pSender = NULL;
return 0;
}
#if LOG_SENDER
LOGI("native : create sender success");
#endif
LOGI("native : JNI_OnLoad VNO2 version:%s \n", str_version);
return (jlong) pSender;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_GetSenderNetworkStatus(
JNIEnv * env, jclass object, jlong handle,jintArray oInfoArray)
{
VideoNeteqSender* pSender = (VideoNeteqSender*) handle;
if (!(pSender && pSender->m_pSender))
{
LOGI("native : LibVideoNeteq_GetSenderNetworkStatus failed.");
return -1;
}
int32_t iUpstreamBandwidth = 0;
pSender->m_pSender->GetNetworkStatus(iUpstreamBandwidth);
env->SetIntArrayRegion(oInfoArray,0,1, &iUpstreamBandwidth);
return 0;
}
JNIEXPORT jlong JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_SetMtu(JNIEnv * env, jclass object, jlong handle, jlong uMtu)
{
#if LOG_SENDER
LOGI("native : LibVideoNeteq_SetMtu is called");
#endif
VideoNeteqSender* pSender = (VideoNeteqSender*) handle;
LOGI("DestroyVideoNetOptimizationSender : %p", pSender->m_pSender);
if (!(pSender && pSender->m_pSender))
{
#if LOG_SENDER
LOGI("native : LibVideoNeteq_SetMtu failed.");
#endif
return -1;
}
pSender->m_pSender->SetMtu(uMtu);
#if LOG_SENDER
LOGI("native : LibVideoNeteq_SetMtu success");
#endif
}
JNIEXPORT void JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_DestroyVideoNetOptimizationSender(
JNIEnv * env, jclass object, jlong handle) {
#if LOG_SENDER
LOGI("native : DestroyVideoNetOptimizationSender is called");
#endif
VideoNeteqSender* pSender = (VideoNeteqSender*) handle;
LOGI("DestroyVideoNetOptimizationSender : %p", pSender->m_pSender);
if (pSender) {
delete pSender;
pSender = NULL;
}
#if LOG_SENDER
LOGI("native : delete sender success");
#endif
}
JNIEXPORT void JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_AddVideoReceiver(
JNIEnv * env, jclass object, jlong sender, jlong receiver) {
#if INTERFACE_SENDER_DISABLE
return ;
#endif
#if LOG_SENDER
LOGI("native : AddVideoReceiver is called");
#endif
if (sender != 0 && receiver != 0) {
VideoNeteqSender* pSender = (VideoNeteqSender*) sender;
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) receiver;
LOGI("native : AddVideoReceiver is success");
return;
}
if (sender == 0) {
LOGI("native : AddVideoReceiver : sender is 0 failed");
}
if (receiver == 0) {
LOGI("native : AddVideoReceiver : receiver is 0 failed");
}
return;
}
JNIEXPORT void JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_RemoveVideoReceiver(
JNIEnv * env, jclass object, jlong sender, jlong receiver) {
#if INTERFACE_SENDER_DISABLE
return ;
#endif
#if LOG_SENDER
LOGI("native : RemoveVideoReceiver is called");
#endif
if (sender != 0 && receiver != 0) {
VideoNeteqSender* pSender = (VideoNeteqSender*) sender;
VideoNeteqReceiver* pReceiver = (VideoNeteqReceiver*) receiver;
LOGI("native : RemoveVideoReceiver is success");
return;
}
if (sender == 0) {
LOGI("native : RemoveVideoReceiver : sender is 0");
}
if (receiver == 0) {
LOGI("native : RemoveVideoReceiver : receiver is 0");
}
return;
}
JNIEXPORT void JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_ClearVideoReceivers(
JNIEnv * env, jclass object, jlong handle) {
#if INTERFACE_SENDER_DISABLE
return ;
#endif
#if LOG_SENDER
LOGI("native : ClearVideoReceivers is called");
#endif
VideoNeteqSender* pSender = (VideoNeteqSender*) handle;
if (pSender) {
}
LOGI(" ClearVideoReceivers is success");
return;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_IncomingVideoFrame(
JNIEnv * env, jclass object, jlong handle, jint nFrameType,
jlong uTimeStamp, jbyteArray h264Stream, jint len,
jobject pFragmentation, jboolean bRtp) {
#if INTERFACE_SENDER_DISABLE
return 0;
#endif
#if LOG_SENDER
LOGI("native : IncomingVideoFrame is called");
#endif
VideoNeteqSender* pSender = (VideoNeteqSender*) handle;
char* pFind = NULL;
char* pBegin = NULL;
char* pSecond = NULL;
char* pBuf = NULL;
int nLen = 0;
int uNalNum = 0;
int nBufSize = 0;
int nOffSet = 3;
if (pSender->m_pH264Buf == NULL)
return -1;
env->GetByteArrayRegion(h264Stream, 0, len, (jbyte*) pSender->m_pH264Buf);
pBuf = pSender->m_pH264Buf;
pBegin = pSender->m_pH264Buf;
nLen = len;
nBufSize = len;
while (true) {
if (!FindTag(pBegin, nLen, pFind))
break;
if (FindTag(pBegin + nOffSet, nLen - nOffSet, pSecond)) {
pSender->m_pFragmentationInfos[uNalNum].uOffset = (pFind - pBuf)
+ nOffSet;
pSender->m_pFragmentationInfos[uNalNum].uLen = (pSecond - pFind)
- nOffSet;
if ((pSecond - pBuf > 1) && (pSecond[-1] == 0)) {
pSender->m_pFragmentationInfos[uNalNum].uLen -= 1;
}
nLen = nLen - (pSecond - pBuf);
pBegin = pSecond;
uNalNum++;
} else {
pSender->m_pFragmentationInfos[uNalNum].uOffset = (pFind - pBuf)
+ nOffSet;
pSender->m_pFragmentationInfos[uNalNum].uLen = nBufSize
- (pFind - pBuf) - nOffSet;
uNalNum++;
break;
}
}
VNO_RTPFragmentationHeader oFragmentations;
VideoNetOptimizationFrameType eFrameType;
oFragmentations.VerifyAndAllocateFragmentationHeader(uNalNum);
for (unsigned long i = 0; i < uNalNum; i++) {
oFragmentations.fragmentationOffset[i] =
pSender->m_pFragmentationInfos[i].uOffset;
oFragmentations.fragmentationLength[i] =
pSender->m_pFragmentationInfos[i].uLen;
oFragmentations.fragmentationPlType[i] = 0;
oFragmentations.fragmentationTimeDiff[i] = 0;
}
pSender->m_pSender->IncomingVideoFrame(
(VideoNetOptimizationFrameType) nFrameType,
(unsigned long) uTimeStamp, (unsigned char*) pSender->m_pH264Buf,
len, &oFragmentations, bRtp);
#if LOG_SENDER
LOGI(" IncomingVideoFrame is success");
#endif
return 0;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_SenderIncomingRTCPPacket(
JNIEnv * env, jclass object, jlong handle, jbyteArray rtcpStream,
jint len) {
#if INTERFACE_SENDER_DISABLE
return 0;
#endif
#if LOG_SENDER
LOGI("native : SenderIncomingRTCPPacket is called");
#endif
VideoNeteqSender* pSender = (VideoNeteqSender*) handle;
if (pSender == NULL)
return -1;
if (pSender->m_pRtcpBuf) {
env->GetByteArrayRegion(rtcpStream, 0, len,
(jbyte*) pSender->m_pRtcpBuf);
return pSender->m_pSender->IncomingRTCPPacket(
(unsigned char*) pSender->m_pRtcpBuf, len);
}
#if LOG_SENDER
LOGI("native : SenderIncomingRTCPPacket is failed");
#endif
return -1;
}
JNIEXPORT jint JNICALL Java_com_jiaxun_sdk_scl_media_video_LibVideoNeteq_GetSendertStatistics(
JNIEnv * env, jclass object, jlong handle, jobject pObject) {
#if INTERFACE_SENDER_DISABLE
return 0;
#endif
#if LOG_SENDER
LOGI("native : GetSendertStatistics is called");
#endif
VideoNeteqSender* pSender = (VideoNeteqSender*) handle;
if (pSender == NULL) {
LOGI("sender is NULL return ");
return -1;
}
jclass recInfo = env->FindClass(
"com/jiaxun/sdk/scl/media/video/VideoSenderStatistics");
if (recInfo == NULL) {
LOGI("get sendinfo find class failed");
return -1;
}
jfieldID uSSRCID = env->GetFieldID(recInfo, "uSSRC", "J");
jfieldID uSelectedPeerSSRCId = env->GetFieldID(recInfo, "uSelectedPeerSSRC",
"J");
jfieldID uFrameRateID = env->GetFieldID(recInfo, "uFrameRate", "J");
jfieldID uSentVideoRateBpsID = env->GetFieldID(recInfo, "uSentVideoRateBps",
"J");
jfieldID uSentNackRateBpsID = env->GetFieldID(recInfo, "uSentNackRateBps",
"J");
jfieldID uSentFecRateBpsID = env->GetFieldID(recInfo, "uSentFecRateBps",
"J");
jfieldID uForceKeyFrameCtrID = env->GetFieldID(recInfo, "uForceKeyFrameCtr",
"J");
jfieldID nActualCountID = env->GetFieldID(recInfo, "nActualCount", "I");
jmethodID getPeerID = env->GetMethodID(recInfo, "getPeerReceiverFeedback",
"(I)Lcom/jiaxun/sdk/scl/media/video/PeerReceiverFeedback;");
jmethodID setPeerID = env->GetMethodID(recInfo, "setPeerReceiverFeedback",
"(IBSJJJ)V");
jmethodID getPeerSizeID = env->GetMethodID(recInfo,
"getPeerReceiverFeedbackSize", "()I");
VideoSenderStatistics* pStatistics = pSender->m_pSender->GetStatistics();
env->SetLongField(pObject, uSSRCID, (jlong) pStatistics->uSSRC);
env->SetLongField(pObject, uSelectedPeerSSRCId,
(jlong) pStatistics->uSelectedPeerSSRC);
env->SetLongField(pObject, uFrameRateID, (jlong) pStatistics->uFrameRate);
env->SetLongField(pObject, uSentVideoRateBpsID,
(jlong) pStatistics->uSentVideoRateBps);
env->SetLongField(pObject, uSentNackRateBpsID,
(jlong) pStatistics->uSentNackRateBps);
env->SetLongField(pObject, uSentFecRateBpsID,
(jlong) pStatistics->uSentFecRateBps);
env->SetLongField(pObject, uForceKeyFrameCtrID,
(jlong) pStatistics->uForceKeyFrameCtr);
env->SetIntField(pObject, nActualCountID,
(jlong) pStatistics->mapReceiversInfo.size());
jclass jobjClass = env->FindClass(
"com/jiaxun/sdk/scl/media/video/PeerReceiverFeedback");
if (jobjClass == 0) {
LOGI(" failed to get PeerReceiverFeedback class ");
return -1;
}
jfieldID uFractionLostID = env->GetFieldID(jobjClass, "uFractionLost", "B");
jfieldID uRTTID = env->GetFieldID(jobjClass, "uRTT", "S");
jfieldID uCumulativeLostID = env->GetFieldID(jobjClass, "uCumulativeLost",
"J");
jfieldID ullRcvTimeID = env->GetFieldID(jobjClass, "ullRcvTime", "J");
jfieldID uRBEID = env->GetFieldID(jobjClass, "uRBE", "J");
LOGI("size=%d", pStatistics->mapReceiversInfo.size());
PeerReceiverFeedback peer;
peer.uCumulativeLost = 1;
peer.uFractionLost = 1;
peer.uRBE = 1;
peer.uRTT = 1;
peer.ullRcvTime = 1;
PeerReceiverFeedbackMap::iterator it;
for (it = pStatistics->mapReceiversInfo.begin();
it != pStatistics->mapReceiversInfo.end(); ++it) {
env->CallVoidMethod(pObject, setPeerID,
(jbyte) it->second.uFractionLost, (jshort) it->second.uRTT,
(jlong) it->second.uCumulativeLost,
(jlong) it->second.ullRcvTime, (jlong) it->second.uRBE);
LOGI("21");
}
LOGI(" GetSendertStatistics is success");
return 0;
}
#ifdef __cplusplus
}
#endif
#endif