Android Rtmp客户端搭建

@Author:明明不说话
@Statement:博客内容纯属个人观点,欢迎转载,转载请注明,谢谢

RTMP介绍

RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议基于TCP,是一个协议族,包括RTMP基本协议及RTMPT/RTMPS/RTMPE等多种变种。RTMP是一种设计用来进行实时数据通信的网络协议,主要用来在Flash/AIR平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。支持该协议的软件包括Adobe Media Server/Ultrant Media Server/red5等。

Android的RTMP方案

Android上常用的RTMP工程可以用juv-rtmp-client,这是一款收费的软件,但是可以在网上找破解版作为学习了解使用,可以参考该示例。使用起来就是调用API,底层基本上都不要处理接触,比较方便。
同时还有一个开源工程rmtpdump,完全开源C语言代码,我们可以自己根据需要编译和定制,例如要修改rtmp协议时(rtmp内容修改添加部分字段),则rtmpdump则体现出它的优势了。

RtmpDump使用

下载RtmpDump

可以在RtmpDump网站上下载源码编译(编译方法可以网上搜索),或者使用官网已经编译好的rtmpdump-2.3-android.zip库

rtmp native实现

native代码添加

Android Rtmp客户端搭建_第1张图片图1
按照Android jni代码方式实现添加,不清楚百度或者参考demo,可以看到代码结构里面包含了librtmp.a和librtmp.so两个文件,其实只是链接方式的不同而已,最后JNI结构如图1所示,Android.mk根据librtmp目标文件是否静态而选在PREBUILT_SHARED_LIBRARY还是PREBUILT_STATIC_LIBRARY

Android.mk按如下编写

# 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)

Application.mk编写

#APP_ABI := all
#APP_ABI := armeabi armeabi-v7a x86
APP_ABI :=armeabi

rtmpdump jni使用

编写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动态加载

这里采用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的名字

rtmp 应用调用

java 类实现

添加需要的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流媒体服务器搭建下载地址

你可能感兴趣的:(android,网络协议,通信,re5流媒体服务器,librtmp,Android,应用)