RtmpPublisher.java----->RtmpUitls.java—>publish_jni.cpp----->Ramp.cpp
public class RtmpPublisher {
private long cPtr;
private long timeOffset;
public static RtmpPublisher newInstance() {
return new RtmpPublisher();
}
private RtmpPublisher(){}
public int init(String url, int w, int h, int timeOut) {
cPtr = RtmpUitls.init(url, w, h, timeOut);
if (cPtr != 0) {
return 0;
}
return -1;
}
public int sendSpsAndPps(byte[] sps, int spsLen, byte[] pps, int ppsLen, long timeOffset) {
this.timeOffset = timeOffset;
return RtmpUitls.sendSpsAndPps(cPtr, sps, spsLen, pps, ppsLen, 0);
}
public int sendVideoData(byte[] data, int len, long timestamp) {
if(timestamp-timeOffset<=0){return -1;}
return RtmpUitls.sendVideoData(cPtr, data, len, timestamp - timeOffset);
}
public int sendAacSpec(byte[] data, int len) {
return RtmpUitls.sendAacSpec(cPtr, data, len);
}
public int sendAacData(byte[] data, int len, long timestamp) {
if(timestamp-timestamp<0){return -1;}
return RtmpUitls.sendAacData(cPtr, data, len, timestamp - timeOffset);
}
public int stop() {
try {
return RtmpUitls.stop(cPtr);
}finally {
cPtr=0;
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if(cPtr!=0){
stop();
}
}
}
public final class RtmpUitls {
static {
System.loadLibrary("avcore");
}
static native long init(String url, int w, int h, int timeOut);
static native int sendSpsAndPps(long cptr, byte[] sps, int spsLen, byte[] pps,
int ppsLen, long timestamp);
static native int sendVideoData(long cptr, byte[] data, int len, long timestamp);
static native int sendAacSpec(long cptr, byte[] data, int len);
static native int sendAacData(long cptr, byte[] data, int len, long timestamp);
static native int stop(long cptr);
}
#include <jni.h>
#include <string>
#include "Rtmp.h"
#ifdef __cplusplus
extern "C" {
#endif
extern "C"
JNIEXPORT jlong JNICALL
Java_com_ivideo_avcore_rtmplive_RtmpUitls_init(JNIEnv *env, jclass type, jstring url_, jint w,
jint h,
jint timeOut) {
const char *url = env->GetStringUTFChars(url_, 0);
Rtmp *rtmp = new Rtmp();
rtmp->init(url, w, h, timeOut);
env->ReleaseStringUTFChars(url_, url);
return reinterpret_cast<long> (rtmp);
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ivideo_avcore_rtmplive_RtmpUitls_sendSpsAndPps(JNIEnv *env, jclass type, jlong cptr,
jbyteArray sps_, jint spsLen,
jbyteArray pps_,
jint ppsLen, jlong timestamp) {
jbyte *sps = env->GetByteArrayElements(sps_, NULL);
jbyte *pps = env->GetByteArrayElements(pps_, NULL);
Rtmp *rtmp = reinterpret_cast<Rtmp *>(cptr);
int ret = rtmp->sendSpsAndPps((BYTE *) sps, spsLen, (BYTE *) pps, ppsLen, timestamp);
env->ReleaseByteArrayElements(sps_, sps, 0);
env->ReleaseByteArrayElements(pps_, pps, 0);
return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ivideo_avcore_rtmplive_RtmpUitls_sendVideoData(JNIEnv *env, jclass type, jlong cptr,
jbyteArray data_, jint len,
jlong timestamp) {
jbyte *data = env->GetByteArrayElements(data_, NULL);
Rtmp *rtmp = reinterpret_cast<Rtmp *> (cptr);
int ret = rtmp->sendVideoData((BYTE *) data, len, timestamp);
env->ReleaseByteArrayElements(data_, data, 0);
return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ivideo_avcore_rtmplive_RtmpUitls_sendAacSpec(JNIEnv *env, jclass type, jlong cptr,
jbyteArray data_, jint len) {
jbyte *data = env->GetByteArrayElements(data_, NULL);
Rtmp *rtmp = reinterpret_cast<Rtmp *> (cptr);
int ret = rtmp->sendAacSpec((BYTE *) data, len);
env->ReleaseByteArrayElements(data_, data, 0);
return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ivideo_avcore_rtmplive_RtmpUitls_sendAacData(JNIEnv *env, jclass type, jlong cptr,
jbyteArray data_, jint len,
jlong timestamp) {
jbyte *data = env->GetByteArrayElements(data_, NULL);
Rtmp *rtmp = reinterpret_cast<Rtmp *> (cptr);
int ret = rtmp->sendAacData((BYTE *) data, len, timestamp);
env->ReleaseByteArrayElements(data_, data, 0);
return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ivideo_avcore_rtmplive_RtmpUitls_stop(JNIEnv *env, jclass type, jlong cptr) {
Rtmp *rtmp = reinterpret_cast<Rtmp *> (cptr);
delete rtmp;
return 0;
}
#ifdef __cplusplus
}
#endif
#include "Rtmp.h"
#include "librtmp/rtmp.h"
#include "librtmp/log.h"
/**
* 初始化
* @param url
* @param w
* @param h
* @param timeOut
* @return
*/
int Rtmp::init(std::string url, int w, int h, int timeOut) {
RTMP_LogSetLevel(RTMP_LOGDEBUG);
rtmp = RTMP_Alloc();
RTMP_Init(rtmp);
//设置rtmp的链接超时
LOGI("time out = %d",timeOut);
rtmp->Link.timeout = timeOut;
//设置rtmp的推流网址
RTMP_SetupURL(rtmp, (char *) url.c_str());
//设置可写
RTMP_EnableWrite(rtmp);
//链接rtmp服务器
if (!RTMP_Connect(rtmp, NULL) ) {
LOGI("RTMP_Connect error"); //链接失败
return -1;
}
LOGI("RTMP_Connect success.");//链接成功
if (!RTMP_ConnectStream(rtmp, 0)) {//打开流
LOGI("RTMP_ConnectStream error");
return -1;
}
LOGI("RTMP_ConnectStream success.");//打开流成功
return 0;
}
//发送视频:sps和pps
int Rtmp::sendSpsAndPps(BYTE *sps, int spsLen, BYTE *pps, int ppsLen, long timestamp) {
int i;
//封装RTMPPacket
RTMPPacket *packet = (RTMPPacket *) malloc(RTMP_HEAD_SIZE + 1024);
memset(packet, 0, RTMP_HEAD_SIZE);
packet->m_body = (char *) packet + RTMP_HEAD_SIZE;
BYTE *body = (BYTE *) packet->m_body;
i = 0;
body[i++] = 0x17; //1:keyframe 7:AVC
body[i++] = 0x00; // AVC sequence header
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00; //fill in 0
/*AVCDecoderConfigurationRecord*/
body[i++] = 0x01;
body[i++] = sps[1]; //AVCProfileIndecation
body[i++] = sps[2]; //profile_compatibilty
body[i++] = sps[3]; //AVCLevelIndication
body[i++] = 0xff;//lengthSizeMinusOne
/*SPS*/
body[i++] = 0xe1;
body[i++] = (spsLen >> 8) & 0xff;
body[i++] = spsLen & 0xff;
/*sps data*/
memcpy(&body[i], sps, spsLen);
i += spsLen;
/*PPS*/
body[i++] = 0x01;
/*sps data length*/
body[i++] = (ppsLen >> 8) & 0xff;
body[i++] = ppsLen & 0xff;
memcpy(&body[i], pps, ppsLen);
i += ppsLen;
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
packet->m_nBodySize = i;
packet->m_nChannel = 0x04;
packet->m_nTimeStamp = 0;
packet->m_hasAbsTimestamp = 0;
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
packet->m_nInfoField2 = rtmp->m_stream_id;
/*发送*/
if (RTMP_IsConnected(rtmp)) {//判断是否链接着
RTMP_SendPacket(rtmp, packet, TRUE);//发送RTMPPacket
}
free(packet);
return 0;
}
//发送视频:
int Rtmp::sendVideoData(BYTE *buf, int len, long timestamp) {
int type;
/*去掉帧界定符*/
if (buf[2] == 0x00) {/*00 00 00 01*/
buf += 4;
len -= 4;
} else if (buf[2] == 0x01) {
buf += 3;
len - 3;
}
type = buf[0] & 0x1f;
//封装RTMPPacket
RTMPPacket *packet = (RTMPPacket *) malloc(RTMP_HEAD_SIZE + len + 9);
memset(packet, 0, RTMP_HEAD_SIZE);
packet->m_body = (char *) packet + RTMP_HEAD_SIZE;
packet->m_nBodySize = len + 9;
/* send video packet*/
BYTE *body = (BYTE *) packet->m_body;
memset(body, 0, len + 9);
/*key frame*/
body[0] = 0x27;
if (type == NAL_SLICE_IDR) {
body[0] = 0x17; //关键帧
}
body[1] = 0x01;/*nal unit*/
body[2] = 0x00;
body[3] = 0x00;
body[4] = 0x00;
body[5] = (len >> 24) & 0xff;
body[6] = (len >> 16) & 0xff;
body[7] = (len >> 8) & 0xff;
body[8] = (len) & 0xff;
/*copy data*/
memcpy(&body[9], buf, len);
packet->m_hasAbsTimestamp = 0;
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
packet->m_nInfoField2 = rtmp->m_stream_id;
packet->m_nChannel = 0x04;
packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
packet->m_nTimeStamp = timestamp;
if (RTMP_IsConnected(rtmp)) {
RTMP_SendPacket(rtmp, packet, TRUE);
}
free(packet);
return 0;
}
//发送音频
int Rtmp::sendAacSpec(BYTE *data, int spec_len) {
RTMPPacket *packet;
BYTE *body;
int len = spec_len;//spec len 是2
packet = (RTMPPacket *) malloc(RTMP_HEAD_SIZE + len + 2);
memset(packet, 0, RTMP_HEAD_SIZE);
packet->m_body = (char *) packet + RTMP_HEAD_SIZE;
body = (BYTE *) packet->m_body;
/*AF 00 +AAC RAW data*/
body[0] = 0xAF;
body[1] = 0x00;
memcpy(&body[2], data, len);/*data 是AAC sequeuece header数据*/
packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;//音频
packet->m_nBodySize = len + 2;
packet->m_nChannel = STREAM_CHANNEL_AUDIO;
packet->m_nTimeStamp = 0;
packet->m_hasAbsTimestamp = 0;
packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
packet->m_nInfoField2 = rtmp->m_stream_id;
if (RTMP_IsConnected(rtmp)) {
RTMP_SendPacket(rtmp, packet, TRUE);
}
free(packet);
return 0;
}
//发送音频数据
int Rtmp::sendAacData(BYTE *data, int len, long timeOffset) {
// data += 5;
// len += 5;
if (len > 0) {
RTMPPacket *packet;
BYTE *body;
packet = (RTMPPacket *) malloc(RTMP_HEAD_SIZE + len + 2);
memset(packet, 0, RTMP_HEAD_SIZE);
packet->m_body = (char *) packet + RTMP_HEAD_SIZE;
body = (BYTE *) packet->m_body;
/*AF 00 +AAC Raw data*/
body[0] = 0xAF;
body[1] = 0x01;
memcpy(&body[2], data, len);
packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
packet->m_nBodySize = len + 2;
packet->m_nChannel = STREAM_CHANNEL_AUDIO;
packet->m_nTimeStamp = timeOffset;
packet->m_hasAbsTimestamp = 0;
packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
packet->m_nInfoField2 = rtmp->m_stream_id;
if (RTMP_IsConnected(rtmp)) {
RTMP_SendPacket(rtmp, packet, TRUE);
}
LOGD("send packet body[0]=%x,body[1]=%x", body[0], body[1]);
free(packet);
}
return 0;
}
//释放资源
int Rtmp::stop() const {
RTMP_Close(rtmp);
RTMP_Free(rtmp);
return 0;
}
Rtmp::~Rtmp() { stop(); }