当前位置: 首页 > article >正文

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脚本参数。

更改如下:

./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转发出去了。


http://www.kler.cn/news/363956.html

相关文章:

  • 一文搞懂大模型量化和大模型微调
  • DNS安全概述
  • 小新学习K8s第一天之K8s基础概念
  • Jupyter Notebook汉化(中文版)
  • 【知识科普】websocket深入了解
  • RNN,LSTM,GRU的区别和联系? RNN的梯度消失问题?如何解决?
  • 【C++复习】经典笔试题
  • 【Linux系统内核探索】进程调度
  • 【设计模式】Liskov替换原则
  • 智谱清言AI
  • Java | Leetcode Java题解之第497题非重叠矩形中的随机点
  • Spring AOP的概念与使用
  • 构建后端为etcd的CoreDNS的容器集群(一)、生成自签名证书
  • java的maven打包插件来了,package一键打包exe、dmg、rpm等
  • 小程序开发语言Java跟php的区别
  • Element Plus的el-tree-v2 组件实现仅叶子节点显示勾选框,并且只能单选
  • MYSQL-SQL-04-DCL(Data Control Language,数据控制语言)
  • 若依框架vue3模板
  • 单例模式是一种常见的设计模式,确保一个类只有一个实例,并提供一个全局访问点。
  • Linux Redis查询key与移除日常操作
  • 尚硅谷redis 第97节 redisTmplate下答疑
  • 代码随想录算法训练营第二天| 209.长度最小的子数组 59.螺旋矩阵II 区间和 开发商购买土地
  • 身份证识别JAVA+OPENCV+OCR
  • ref属性的作用对象类型
  • 文件操作(1) —— 文件基础知识
  • 【C++】——list 容器的解析与极致实现