How to record the H264 stream using EuhatRtsp lib

euhatrtsp/livevideo/RtspOp.cpp

389
390
391
392
393
394
395
396
397
int EuhatRtspOp::decodingProc()
{//frame是原始H264数据,在这里录像最好,此库已经把ffmpeg库编译进去了,直接用ffmpeg库就可以完成录像功能。
//可以网上搜ffmpeg录像api怎么用。
//这就要求会写C++代码,还要加jni接口提供给java端打开或关闭录像功能。
decoder_->decode(frame + 4, *(int *)frame);}

android cmake命令行

ninja这个工具是google的cmake特有的一个工具,不能用CMake官网下载安装的cmake编译安卓程序。

1
2
3
4
5
6
7
8
9
10
set SDK_PATH=E:\euhat\android-sdk
set path=%SDK_PATH%\cmake\3.10.2.4988404\bin;%path%
 
cd app
mkdir manBuild
cd manBuild
 
cmake -DANDROID_ABI=armeabi-v7a -DANDROID_STL=c++_shared -DBUILD_SHARED_LIBS=ON -DCMAKE_C_FLAGS="-s" -DANDROID_PLATFORM=android-27 -DCMAKE_BUILD_TYPE=Debug -DANDROID_NDK=%SDK_PATH%\ndk-bundle -DCMAKE_TOOLCHAIN_FILE=%SDK_PATH%\ndk-bundle\build\cmake\android.toolchain.cmake -DCMAKE_GENERATOR=Ninja ..
 
ninja

refer to: https://bbs.csdn.net/topics/392257691?list=lz

Android Handler and Runnable

Runnable并不是一个线程,它是Thread运行过程中的一个片断。

以下例子是创建子线程获取图片后发送给UI线程显示,第一个Runnable运行在子线程中,第二个Runnable运行在UI线程中:

1
2
3
4
5
6
7
8
9
10
11
12
public void onClick(View v) {
    new Thread(new Runnable() { // 第一个Runnable
        public void run() {
            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
            mImageView.post(new Runnable() { // 第二个Runnable
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

而Handler与线程的绑定有两种方式。
第一种是与当前线程绑定:

1
public Handler handler = new Handler();

第二种是指定线程绑定:

1
handler = new Handler(thread.getLooper());

Android NDK动态获取系统版本

让电脑连上安卓手机上,执行

1
2
adb shell
cat /system/build.prop

可看到

1
2
3
4
5
...
ro.build.version.sdk=18
ro.build.version.codename=REL
ro.build.version.release=4.3
...

于是jni中可写如下代码获取系统版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <sys/system_properties.h>
 
static int test(){
    char *key = (char *)"ro.build.version.sdk";
    //char *key = (char *)"ro.build.version.release";
    char value[1024] = {0};
    int ret = __system_property_get(key, value);
    if (ret <= 0 ) {
        DBG(("get prop value failed.\n"));
        return 0;
    }
    DBG(("ro.build.id is [%s]\n", value));
 
    return 0;
}

Android jni基于NdkMediaCodec硬解码mjpeg

NdkMediaCodec需要安卓5.0以上系统才能运行,在Android.mk里加入

1
LOCAL_LDLIBS += -lmediandk

如果是在安卓5.0以下系统中跑,程序会直接崩掉,主函数都不会进,所以要在旧手机中运行,要根据系统版本来判断是不是5.0以上系统,如果是则动态加载libmediandk.so,而不要写死在编译脚本里。

还有,要看手机上有没有解mjpeg的硬解码器,通过以下java代码来查看

1
2
3
4
5
6
7
8
9
10
11
12
int n = MediaCodecList.getCodecCount();
for (int i = 0; i < n; ++i) {
	MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
	String[] supportedTypes = info.getSupportedTypes();
	boolean mime_support = false;
	if(info.isEncoder()){
		continue;
	}
	for (int j = 0; j < supportedTypes.length; ++j) {
		Log.v("euhat", "codec info:" + info.getName()+" supportedTypes:" + supportedTypes[j]);
	}
}

以下是jni硬解码代码,因为没找到支持mjpeg硬解的手机,所以还没实际跑起来过。
但实际测试过程中,新的手机上软解1920x1080的mjpeg输出yuv都很流畅了。

阅读更多Android jni基于NdkMediaCodec硬解码mjpeg