hi3536上ffmpeg带rtmp移植

1.下载ffmpeg-4.1.3版本源码包

用下面的脚本进行configure:

复制代码
./configure \
    --target-os=linux \
    --prefix=./libs/ \
    --enable-cross-compile \
    --arch=arm \
    --cc=arm-hisiv500-linux-gcc \
    --cross-prefix=arm-hisiv500-linux- \
    --nm=arm-hisiv500-linux-nm \
    --enable-shared \
    --disable-static \
    --enable-gpl \
    --enable-swscale \
    --enable-avfilter \
    --disable-devices \
    --disable-filters \
    --disable-decoders \
    --enable-decoder=h264 \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-doc \
    --disable-encoders \
    --enable-small \
    --enable-encoder=flv \
    --enable-encoder=mp4 \
    --disable-muxers \
    --enable-muxer=flv \
    --enable-muxer=rtsp \
    --enable-muxer=rtp \
    --disable-parsers \
    --enable-parser=flv \
    --enable-parser=h264 \
    --disable-demuxers \
    --enable-demuxer=flv \
    --enable-demuxer=h264 \
    --enable-ffmpeg 

然后make和make install,生成的可执行文件以及lib和include等将拷贝到prefix指定的目录下,然后将这个目录拷贝到nfs共享文件夹里面,到板子中,通过软连接的方式,将可执行文件和动态库链接到板子上,因为板子空间有限,所以不直接拷贝到板子上,拷贝之后,可以通过nginx代理,将本地flv文件通过rtmp推送出去,但是mp4文件推不出去,而且rtsp流也没法拉流,所以需要修改configure参数,

2.更换新的configure脚本参数。

更改如下:

c 复制代码
./configure \
        --prefix=./libs/ \
        --enable-filters   \
        --enable-asm \
        --enable-ffmpeg \
        --enable-ffplay \
        --enable-ffprobe \
        --enable-doc \
        --enable-cross-compile \
        --cross-prefix=arm-hisiv500-linux- \
        --arch=arm \
        --target-os=linux \
        --host-os=linux \
        --enable-gpl \
        --enable-version3 \
        --enable-small \
        --enable-shared \
        --enable-static \
        --enable-encoder=rawvideo \
        --enable-encoder=mpeg2video \
        --enable-encoder=mp2 \
        --enable-encoder=libx264 \
        --enable-libx264 \
        --enable-muxer=adts \
        --enable-muxer=mpegts \
        --enable-muxer=mpeg2video \
        --enable-muxer=rtsp \
        --enable-muxer=hls \
        --enable-muxer=h264 \
        --enable-muxer=rtp \
        --enable-muxer=avi \
        --enable-muxer=flv \
        --enable-muxer=mp4 \
        --enable-demuxer=mpegts \
        --enable-demuxer=rtsp \
        --enable-demuxer=hls \
        --enable-demuxer=h264 \
        --enable-demuxer=rtp \
        --enable-demuxer=flv \
        --enable-muxer=mp4 \
        --enable-demuxer=mpegts \
        --enable-demuxer=rtsp \
        --enable-demuxer=hls \
        --enable-demuxer=h264 \
        --enable-demuxer=rtp \
        --enable-demuxer=flv \
        --enable-demuxer=avi \
        --enable-demuxer=mpegps \
        --enable-demuxer=mpegtsraw \
        --enable-demuxer=mpegvideo \
        --enable-parser=aac \
        --enable-parser=h264 \
        --enable-parser=mpeg4video \
        --enable-parser=mpegvideo \
        --enable-parser=mpegaudio \
        --enable-bsf=h264_mp4toannexb \
        --enable-protocol=http \
        --enable-protocol=rtp \
        --enable-protocol=rtmpts \
        --enable-protocol=https \
        --enable-protocol=hls \
        --enable-protocol=file \
        --enable-protocol=data \
        --enable-gray  \
        --enable-safe-bitstream-reader \
        --extra-cflags=-I/home/zl/vstdio-workspace/hi3536-webapp/x264/x264_hisi/include \
        --extra-ldflags=-L/home/zl/vstdio-workspace/hi3536-webapp/x264/x264_hisi/lib

添加了一个x264的扩展包.

3.x264移植。

1.下载编译x264。

(1)下载链接如下:

复制代码
git clone https://github.com/mirror/x264

(2)configure脚本:

复制代码
CC=arm-hisiv500-linux-gcc  ./configure \
--host=arm-hisiv500-linux \
--prefix=./x264_hisi \
--cross-prefix=arm-hisiv500-linux- \
--enable-static \
--enable-shared \

成功之后执行:

复制代码
make
make install

然后回到ffmpeg的路径下,修改configure,将x264的库和头文件路径配置上,编译,提示下面的错误:

复制代码
libavfilter/libavfilter.so: undefined reference to `fminf'
libavfilter/libavfilter.so: undefined reference to `fmaxf'
collect2: error: ld returned 1 exit status
Makefile:108: recipe for target 'ffprobe_g' failed
make: *** [ffprobe_g] Error 1
make: *** Waiting for unfinished jobs....
libavfilter/libavfilter.so: undefined reference to `fminf'
libavfilter/libavfilter.so: undefined reference to `fmaxf'
collect2: error: ld returned 1 exit status
Makefile:108: recipe for target 'ffmpeg_g' failed
make: *** [ffmpeg_g] Error 1

网上查到的资料显示是,海思用的交叉编译链不支持浮点操作,然后也没找到修改方法,看到最多的是用ffmpeg早期版本,因为目前的版本是4.1.3。

4.重新拉取ffmpeg源码,更换版本。

从网上查到ffmpeg的开源链接如下:

复制代码
git clone https://git.ffmpeg.org/ffmpeg.git

下载之后,默认是最新的release版本,用下面的命令更换分支:

复制代码
git checkout -t remotes/origin/release/3.4

切换到3.4版本,然后将configure脚本拷过来,进行配置,配置完后,执行make和make install,然后将可执行文件和动态库拷贝到板子上,进行测试,通过测试,可以推mp4文件到rtmp,以及拉rtsp然后推rtmp出去。测试命令如下:

复制代码
ffmpeg -re -i test.mp4 -vcodec copy -codec copy -f flv rtmp://192.168.0.165:1935/live/mainstream

ffmpeg -i rtsp://admin:12345@192.168.0.200:554/Streaming/Channels/1 -vcodec copy -acodec copy -f flv rtmp://192.168.0.165:1935/live/mainstream

5.测试H265码流的支持,从H265 ipc上拉取H265的rtsp流,然后转rtmp流出去:

命令如下:

复制代码
ffmpeg -i rtsp://192.168.0.132:554/user=admin_password=tlJwpbo6_channel=1_stream=0.sdp?real_stream -vcodec copy -acodec copy -f flv rtmp://192.168.0.165:1935/live/thirdstream

报错:

复制代码
[rtsp @ 0x421f0] max delay reached. need to consume packet
[rtsp @ 0x421f0] RTP: missed 46 packets
Input #0, rtsp, from 'rtsp://192.168.0.132:554/user=admin_password=tlJwpbo6_channel=1_stream=0.sdp?real_stream':
  Metadata:
    title           : RTSP Session
  Duration: N/A, start: 0.040000, bitrate: N/A
    Stream #0:0: Video: hevc, yuvj420p(pc, bt709), 1920x1080, 25 fps, 25 tbr, 90k tbn, 90k tbc
[flv @ 0x98310] Video codec hevc not compatible with flv
Could not write header for output file #0 (incorrect codec parameters ?): Function not implemented
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
    Last message repeated 1 times

原因:

rtmp默认是flv封装的,而这个封装默认是不支持HEVC也就是H265的,所以需要打个patch:0020-ffmpeg-flv-support-hevc.patch

复制代码
diff --git a/libavformat/flv.h b/libavformat/flv.h
index 3571b90279..91f006520c 100644
--- a/libavformat/flv.h
+++ b/libavformat/flv.h
@@ -110,6 +110,7 @@ enum {
     FLV_CODECID_H264    = 7,
     FLV_CODECID_REALH263= 8,
     FLV_CODECID_MPEG4   = 9,
+    FLV_CODECID_HEVC    = 12,
 };
 
 enum {
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index b531a39adc..fc9be86509 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -37,6 +37,7 @@
 #include "internal.h"
 #include "avio_internal.h"
 #include "flv.h"
+#include "hevc.h"
 
 #define VALIDATE_INDEX_TS_THRESH 2500
 
@@ -319,6 +320,8 @@ static int flv_same_video_codec(AVCodecParameters *vpar, int flags)
         return vpar->codec_id == AV_CODEC_ID_VP6A;
     case FLV_CODECID_H264:
         return vpar->codec_id == AV_CODEC_ID_H264;
+    case FLV_CODECID_HEVC:
+        return vpar->codec_id == AV_CODEC_ID_HEVC;
     default:
         return vpar->codec_tag == flv_codecid;
     }
@@ -368,6 +371,11 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
         par->codec_id = AV_CODEC_ID_MPEG4;
         ret = 3;
         break;
+    case FLV_CODECID_HEVC:
+        par->codec_id = AV_CODEC_ID_HEVC;
+        vstream->need_parsing = AVSTREAM_PARSE_HEADERS;
+        ret = 3;
+        break;
     default:
         avpriv_request_sample(s, "Video codec (%x)", flv_codecid);
         par->codec_tag = flv_codecid;
@@ -1223,7 +1231,8 @@ retry_duration:
 
     if (st->codecpar->codec_id == AV_CODEC_ID_AAC ||
         st->codecpar->codec_id == AV_CODEC_ID_H264 ||
-        st->codecpar->codec_id == AV_CODEC_ID_MPEG4) {
+        st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
+        st->codecpar->codec_id == AV_CODEC_ID_HEVC) {
         int type = avio_r8(s->pb);
         size--;
 
@@ -1232,7 +1241,8 @@ retry_duration:
             goto leave;
         }
 
-        if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4) {
+        if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4
+                || st->codecpar->codec_id == AV_CODEC_ID_HEVC) {
             // sign extension
             int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
             pts = dts + cts;
@@ -1248,7 +1258,7 @@ retry_duration:
             }
         }
         if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
-            st->codecpar->codec_id == AV_CODEC_ID_H264)) {
+            st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC)) {
             AVDictionaryEntry *t;
 
             if (st->codecpar->extradata) {
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index fb1dede7ae..711b5dfb05 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -29,6 +29,7 @@
 #include "avc.h"
 #include "avformat.h"
 #include "flv.h"
+#include "hevc.h"
 #include "internal.h"
 #include "metadata.h"
 #include "libavutil/opt.h"
@@ -46,6 +47,7 @@ static const AVCodecTag flv_video_codec_ids[] = {
     { AV_CODEC_ID_VP6,      FLV_CODECID_VP6 },
     { AV_CODEC_ID_VP6A,     FLV_CODECID_VP6A },
     { AV_CODEC_ID_H264,     FLV_CODECID_H264 },
+    { AV_CODEC_ID_HEVC,     FLV_CODECID_HEVC },
     { AV_CODEC_ID_NONE,     0 }
 };
 
@@ -491,7 +493,7 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
     FLVContext *flv = s->priv_data;
 
     if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
-            || par->codec_id == AV_CODEC_ID_MPEG4) {
+            || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
         int64_t pos;
         avio_w8(pb,
                 par->codec_type == AVMEDIA_TYPE_VIDEO ?
@@ -537,7 +539,11 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
             avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags
             avio_w8(pb, 0); // AVC sequence header
             avio_wb24(pb, 0); // composition time
-            ff_isom_write_avcc(pb, par->extradata, par->extradata_size);
+            if (par->codec_id == AV_CODEC_ID_HEVC) {
+                ff_isom_write_hvcc(pb, par->extradata, par->extradata_size, 0);
+            } else {
+                ff_isom_write_avcc(pb, par->extradata, par->extradata_size);
+            }
         }
         data_size = avio_tell(pb) - pos;
         avio_seek(pb, -data_size - 10, SEEK_CUR);
@@ -847,7 +853,8 @@ end:
             AVCodecParameters *par = s->streams[i]->codecpar;
             FLVStreamContext *sc = s->streams[i]->priv_data;
             if (par->codec_type == AVMEDIA_TYPE_VIDEO &&
-                    (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4))
+                    (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4
+                     || par->codec_id == AV_CODEC_ID_HEVC))
                 put_avc_eos_tag(pb, sc->last_ts);
         }
     }
@@ -898,13 +905,13 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
     if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A ||
         par->codec_id == AV_CODEC_ID_VP6  || par->codec_id == AV_CODEC_ID_AAC)
         flags_size = 2;
-    else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4)
+    else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC)
         flags_size = 5;
     else
         flags_size = 1;
 
     if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
-            || par->codec_id == AV_CODEC_ID_MPEG4) {
+            || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
         int side_size = 0;
         uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
         if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
@@ -967,6 +974,11 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
         if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1)
             if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0)
                 return ret;
+    } else if (par->codec_id == AV_CODEC_ID_HEVC) {
+        /* check if extradata looks like mp4 formatted */
+        if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1)
+            if ((ret = ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, NULL)) < 0)
+                return ret;
     } else if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
                (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
         if (!s->streams[pkt->stream_index]->nb_frames) {
@@ -1038,7 +1050,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
                              (FFALIGN(par->height, 16) - par->height));
         } else if (par->codec_id == AV_CODEC_ID_AAC)
             avio_w8(pb, 1); // AAC raw
-        else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) {
+        else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
             avio_w8(pb, 1); // AVC NALU
             avio_wb24(pb, pkt->pts - pkt->dts);
         }

打完patch之后,重新编译,运行测试命令,就可以拉取H265的rtsp流并成功rtmp转发出去了。

相关推荐
学传打活1 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng1689 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心11 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552717 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552717 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝19 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552719 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552720 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552722 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552722 天前
Java I/O核心操作实战
人工智能·1024程序员节