librtmp开源库与android平台编译记录

一、编写目的

为了记录编译librtmp开源库过程遇到的问题,帮助后来人提供参考,希望本文能为大家提供参考。

二、简介(官方介绍)

The Real-Time Messaging Protocol (RTMP) is used for streaming multimedia content across a TCP/IP network. This API provides most client functions and a few server functions needed to support RTMP, RTMP tunneled in HTTP (RTMPT), encrypted RTMP (RTMPE), RTMP over SSL/TLS (RTMPS) and tunneled variants of these encrypted types (RTMPTE, RTMPTS). The basic RTMP specification has been published by Adobe but this API was reverse-engineered without use of the Adobe specification. As such, it may deviate from any published specifications but it usually duplicates the actual behavior of the original Adobe clients.

三、编译步骤

1、下载源码

可以从以下两个仓库下载源码,目前使用master主分支

git clone https://github.com/shishuo365/librtmp.git
git clone https://github.com/LinChengChun/librtmp.git

2、安装Android NDK

为了开发支持android平台的库,所以需要下载google官方的NDK

https://developer.android.google.cn/ndk/downloads/index.html

3、 使用android ndk 提供脚本,允许自己定制一套工具链

cd android-ndk-r13b/build/tools/
./make-standalone-toolchain.sh --platform=android-14 --install-dir=/home/cclin/android-toolchain --force
----------------------------------------------------------------------------------------------------------------------------------------
Valid options (defaults are in brackets):
  --help                  Print this help.
  --verbose                Enable verbose mode.
  --dryrun                Unsupported.
  --toolchain=      Specify toolchain name
  --use-llvm              No-op. Clang is always available.
  --stl=            Specify C++ STL [gnustl]
  --arch=            Specify target architecture    默认是 arm,可以指定其他指令架构
  --abis=            No-op. Derived from --arch or --toolchain.
  --ndk-dir=        Unsupported.
  --package-dir=    Place package file in  [/tmp/ndk-cclin]    如果不指定安装目录,默认生成一个压缩包,路径在/tmp/ndk-cclin
  --install-dir=    Don't create package, install files to  instead.    指定 工具链安装目录
  --dryrun                Unsupported.
  --platform=        Specify target Android platform/API level. [android-9]    指定哪个平台/API 版本
  --force                  Remove existing install directory.    强制覆盖上一次生成的文件

4、获得工具链后,就可以编译支持android平台的librtmp库了

  • 根据上一步生成的工具链,修改 librtmp 目录下的Makefile和tools/compile-librtmp-android.sh
diff --git a/Makefile b/Makefile
index 1597948..a761d8d 100644
--- a/Makefile
+++ b/Makefile
@@ -72,7 +72,7 @@ SOINST_yes=install_so
SO_DEF=$(SODEF_$(SHARED))
SO_LIB=$(SOLIB_$(SHARED))
SO_INST=$(SOINST_$(SHARED))
-
+XLDFLAGS=-llog
DEF=-DRTMPDUMP_VERSION=\"$(VERSION)\" $(CRYPTO_DEF) $(XDEF)
OPT=-O2
CFLAGS=-Wall $(ARCH_CFLAGS) $(XCFLAGS) $(INC) $(DEF) $(OPT) $(SO_DEF)
diff --git a/tools/compile-librtmp-android.sh b/tools/compile-librtmp-android.sh
old mode 100644
new mode 100755
index 032bfab..a56faa7
--- a/tools/compile-librtmp-android.sh
+++ b/tools/compile-librtmp-android.sh
@@ -8,17 +8,19 @@ if [ -z "$RTMP_ARCH" ]; then
fi

# replace this path to your android NDK standalone toolchain ptah.
-RTMP_TOOLCHAIN_PATH=/Users/shishuo/Documents/app/Android-NDK-Toolchain
+#RTMP_TOOLCHAIN_PATH=/Users/shishuo/Documents/app/Android-NDK-Toolchain
+RTMP_TOOLCHAIN_PATH=/home/cclin/android-toolchain/bin/
RTMP_BUILD_ROOT=`pwd`
RTMP_BIN_ROOT=$RTMP_BUILD_ROOT/bin
RTMP_ARCH_DIR=
cd ..

compile_armv7a() {
-      export CC=$RTMP_TOOLCHAIN_PATH/arm/bin/arm-linux-androideabi-gcc
-      export LD=$RTMP_TOOLCHAIN_PATH/arm/bin/arm-linux-androideabi-ld
-      export AR=$RTMP_TOOLCHAIN_PATH/arm/bin/arm-linux-androideabi-ar
-      export ARCH_CFLAGS=-march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb
+      export CC=$RTMP_TOOLCHAIN_PATH/arm-linux-androideabi-gcc
+      export LD=$RTMP_TOOLCHAIN_PATH/arm-linux-androideabi-ld
+      export AR=$RTMP_TOOLCHAIN_PATH/arm-linux-androideabi-ar
+      export ARCH_CFLAGS=-march=armv7-a
+    #-mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb
        make clean
        make all
}
@@ -94,6 +96,7 @@ release_librtmp() {
        cp -f http.h    $RTMP_BIN_ROOT/$RTMP_ARCH_DIR/include/librtmp
        cp -f log.h    $RTMP_BIN_ROOT/$RTMP_ARCH_DIR/include/librtmp
        cp -f rtmp.h    $RTMP_BIN_ROOT/$RTMP_ARCH_DIR/include/librtmp
+    #cp -f librtmp.so.1 $RTMP_BIN_ROOT/$RTMP_ARCH_DIR/librtmp.so
}

if [ "$RTMP_ARCH" = "armv7a" ]; then
@@ -137,4 +140,4 @@ elif [ "$RTMP_ARCH" = "all" ]; then
else
    echo "unknown architecture $RTMP_ARCH";
    exit 1
-fi
\ No newline at end of file
+fi
  • 跳转到 librtmp/tools 目录运行编译脚本,即可开始编译
./compile-librtmp-android.sh armv7a    // 由于只编译armv7a架构的,因此只修改了compile-librtmp-android.sh中对应的编译器有效路径,如果需要编译其他架构需要重新生成对应工具链,重新配置对应架构下面编译器的有效路径

5、生成的文件

librtmp/tools/bin/armeabi-v7a$cp ../../../librtmp.so.1 librtmp.so
librtmp/tools/bin/armeabi-v7a$ ls -R
.:
include  lib  librtmp.so

./include:
librtmp

./include/librtmp:
amf.h  http.h  log.h  rtmp.h

./lib:
librtmp.a

6、在AS新建一个工程用于使用librtmp库

  • 项目结构
    librtmp开源库与android平台编译记录_第1张图片
  • 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)
-----------------------------------------------------------------上面是引用librtmp.so动态库脚本,下面是引用librtmp.a静态库脚本------------
# 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)
LOCAL_SRC_FILES := librtmp.a
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_STATIC_LIBRARIES := rtmp
#LOCAL_SHARED_LIBRARIES := rtmp
include $(BUILD_SHARED_LIBRARY)
  • Application.mk
#APP_ABI := all
#APP_ABI := armeabi armeabi-v7a x86
APP_ABI :=armeabi-v7a
  • rtmpJNI.java
package org.src.rtmp_get;

/**
* Created by Administrator on 2015/12/4.
*/
public class rtmpJNI {
    public native void rtmpDeInit();

    public native void rtmpInit(String rtmpUrl);

    static {
        System.loadLibrary("rtmp"); // 如果编译脚本引用librtmp.so库,需要添加该句;如果引用librtmp.a,需要注释该句;引用动态库时,native调用RTMP_Close时会出现进程崩溃;引用静态库时,运行正常,所以建议引用静态库。
        System.loadLibrary("nativeRtmp");
    }

}
  • MainActivity.java
package org.src.rtmp_get;

import android.app.Activity;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

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();
        mRtmpClient.rtmpInit("rtmp://192.168.1.116");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mRtmpClient.rtmpDeInit();
    }
}
  • nativeRtmp.c
//
// Created by Administrator on 2015/12/4.
//
#include 
#include 
#include 
#include "include/librtmp/rtmp.h"
#include 
#include 


#define LOG_TAG "NativeRTMP"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
static const char *ClassName = "org/src/rtmp_get/rtmpJNI";


char* pubRtmpUrl;
RTMP *pubRtmp; //rtmp


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);
}

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)
{
}

四、总结

根据以上记录,librtmp库最好在linux平台编译(mingw编译不成功);编译成功后,新建一个工程测试一下librtmp库的功能,前提是具有RTMP服务器,便于通信。当然,也可以使用附件的工程来测试;本文主要是记录 librtmp编译以及在APP中的应用。后续再分析librtmp、rtmp协议相关知识点。^-^

附件rtmpDumpDemo
链接:https://pan.baidu.com/s/1nvl9inn 密码:plhb

你可能感兴趣的:(Android)