@Author:明明不说话
@Statement:博客内容纯属个人观点,欢迎转载,转载请注明,谢谢
RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议基于TCP,是一个协议族,包括RTMP基本协议及RTMPT/RTMPS/RTMPE等多种变种。RTMP是一种设计用来进行实时数据通信的网络协议,主要用来在Flash/AIR平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。支持该协议的软件包括Adobe Media Server/Ultrant Media Server/red5等。
Android上常用的RTMP工程可以用juv-rtmp-client,这是一款收费的软件,但是可以在网上找破解版作为学习了解使用,可以参考该示例。使用起来就是调用API,底层基本上都不要处理接触,比较方便。
同时还有一个开源工程rmtpdump,完全开源C语言代码,我们可以自己根据需要编译和定制,例如要修改rtmp协议时(rtmp内容修改添加部分字段),则rtmpdump则体现出它的优势了。
可以在RtmpDump网站上下载源码编译(编译方法可以网上搜索),或者使用官网已经编译好的rtmpdump-2.3-android.zip库
图1
按照Android jni代码方式实现添加,不清楚百度或者参考demo,可以看到代码结构里面包含了librtmp.a和librtmp.so两个文件,其实只是链接方式的不同而已,最后JNI结构如图1所示,Android.mk根据librtmp目标文件是否静态而选在PREBUILT_SHARED_LIBRARY还是PREBUILT_STATIC_LIBRARY
# Android.mk for rtmp
LOCAL_PATH := $(call my-dir)
# rtmp library
include $(CLEAR_VARS)
LOCAL_MODULE := rtmp
LOCAL_SRC_FILES := librtmp.so
include $(PREBUILT_SHARED_LIBRARY) #动态库
#include $(PREBUILT_STATIC_LIBRARY)
# Program
include $(CLEAR_VARS)
LOCAL_MODULE := nativeRtmp
LOCAL_SRC_FILES := nativeRtmp.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog -lz
LOCAL_SHARED_LIBRARIES := rtmp
include $(BUILD_SHARED_LIBRARY)
#APP_ABI := all
#APP_ABI := armeabi armeabi-v7a x86
APP_ABI :=armeabi
编写nativeRtmp.c,分别编写初始化,销毁和发送函数,来测试使用librtmp.so
void send_pkt(char* buf, int buflen, int type, unsigned int timestamp)
{
int ret;
RTMPPacket rtmp_pakt;
RTMPPacket_Reset(&rtmp_pakt);
RTMPPacket_Alloc(&rtmp_pakt, buflen);
rtmp_pakt.m_packetType = type;
rtmp_pakt.m_nBodySize = buflen;
rtmp_pakt.m_nTimeStamp = timestamp;
rtmp_pakt.m_nChannel = 4;
rtmp_pakt.m_headerType = RTMP_PACKET_SIZE_LARGE;
rtmp_pakt.m_nInfoField2 = pubRtmp->m_stream_id;
memcpy(rtmp_pakt.m_body, buf, buflen);
ret = RTMP_SendPacket(pubRtmp, &rtmp_pakt, 0);
RTMPPacket_Free(&rtmp_pakt);
}
void my_Native_rtmpInit(JNIEnv *env, jobject jobj,jstring jRtmpUrl){
const char* rtmpUrl = (*env)->GetStringUTFChars(env, jRtmpUrl, 0);
pubRtmpUrl = malloc(strlen(rtmpUrl) + 1);
memset(pubRtmpUrl, 0, strlen(rtmpUrl) + 1);
strcpy(pubRtmpUrl, rtmpUrl);
pubRtmp = RTMP_Alloc();
RTMP_Init(pubRtmp);
LOGI("RTMP_Init %s", pubRtmpUrl);
if (!RTMP_SetupURL(pubRtmp, pubRtmpUrl)) {
LOGE("RTMP_SetupURL error");
return;
}
if (!RTMP_Connect(pubRtmp, NULL) ) {
LOGE("RTMP_Connect error");
return;
}
/* if (!RTMP_ConnectStream(pubRtmp, 0)) {
LOGE("RTMP_ConnectStream error");
return;
}*/
LOGI("RTMP Connect ok");
send_pkt("aa", 20, RTMP_PACKET_TYPE_AUDIO, 20);
}
void my_Native_rtmpDeInit(JNIEnv *env, jobject jobj)
{
if (RTMP_IsConnected(pubRtmp)) {
RTMP_Close(pubRtmp);
}
RTMP_Free(pubRtmp);
free(pubRtmpUrl);
}
这里采用JNI_OnLoad函数来加载jni的方法,供给API调用
static JNINativeMethod METHODS[]={
{"rtmpInit","(Ljava/lang/String;)V",(void *)my_Native_rtmpInit},
{"rtmpDeInit","()V",(void *)my_Native_rtmpDeInit},
};
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
int retVal = -1;
JNIEnv *env;
if ( (*vm)->GetEnv(vm,(void **) &env, JNI_VERSION_1_4) == JNI_OK ) {
jclass clazz = (*env)->FindClass(env,ClassName);
if (clazz != NULL) {
if ((*env)->RegisterNatives(env,clazz, METHODS,sizeof(METHODS) / sizeof(METHODS[0])) >= 0) {
retVal = JNI_VERSION_1_4;
}else{
LOGI("RegisterNatives Subprocess.create method failed!");
}
(*env)->DeleteLocalRef(env,clazz);
}else{
LOGI("className not found!");
}
}
return retVal;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
{
}
ps:这里需要定义ClassName变量,例如demo中
static const char *ClassName = "org/src/rtmp_get/rtmpJNI";
就是说,是org.src.rtmp_get.rtmpJNI类调用了该jni的接口,根据实际调用类的位置和名字来修改该ClassName的名字
添加需要的libray以及申明Native本地方法,这里需要和JNINativeMethod 中定义的一致,否则会报找不到该接口。
public class rtmpJNI {
public native void rtmpDeInit();
public native void rtmpInit(String rtmpUrl);
static {
System.loadLibrary("rtmp");
System.loadLibrary("nativeRtmp");
}
}
public class MainActivity extends Activity {
private rtmpJNI mRtmpClient ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRtmpClient = new rtmpJNI(); //初始化打开链接rtmp流媒体服务器
mRtmpClient.rtmpInit("rtmp://live.hkstv.hk.lxdns.com/live/hks"); //亲测该rtmp地址可用,可以采用rtmp流播放器播放视频
}
@Override
protected void onDestroy() {
super.onDestroy();
mRtmpClient.rtmpDeInit();//销毁断开链接
}
}
ps一定要记得申明权限,否则会不能正常访问网络
android:name="android.permission.INTERNET"></uses-permission>
可以用简易RED5流媒体服务器测试参考Windows环境搭建Red5流媒体服务器指南,执行red5.bat,然后执行上述应用,看是否能够链接上服务器。
上面就是对rtmpDump的使用,可以参考如上操作,附上demo以及相关链接,Q&A。
Demo下载地址
red5流媒体服务器搭建下载地址