ffmpeg 支持用h265编码的rtmp

修改ffmpeg5.0的代码,让ffmpeg的flv支持h265封装及解封装

中间目录:out
1、x264
   下载x264-stable.zip
   unzip x264-stable.zip
   cd x264-stable
   ./configure --enable-shared --enable-static
   make
   make DESTDIR=../out install
   
2、安装nv-codec-headers
  git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
  cd nv-codec-headers
  make
  sudo make isntall

3、x265
   下载x265_3.2.1.tar.gz
   tar -zxvf x265_3.2.1.tar.gz
   cd x265_3.2.1
   cd build/linux
   ./make-Makefiles.bash
   make
   make DESTDIR=../../../out install

4、mp3
   下载lame-3.100.tar.gz
   tar -zxvf lame-3.100.tar.gz
   cd lame-3.100
   ./configure 
   make
   make DESTDIR=../out install
  
5、ffmpeg
   下载 FFmpeg-release-5.0.zip
   unzip FFmpeg-release-5.0.zip
   修改 FFmpeg-release-5.0/libavformat 下flv相关代码,让ffmpeg的flv支持h265(hevc)


   5.1修改flv.h,扩展rtmp协议的支持 FLV_CODECID_HEVC    = 12,

didiff --git a/flv0.h b/flv.h
index 3571b90..91f0065 100644
--- a/flv0.h
+++ b/flv.h
@@ -110,6 +110,7 @@ enum {
     FLV_CODECID_H264    = 7,
     FLV_CODECID_REALH263= 8,
     FLV_CODECID_MPEG4   = 9,
+    FLV_CODECID_HEVC    = 12,
 };
 
 enum {

    5.2修改解码flvdec.c,参照h264,增加h265(hevc) 

diff --git a/flvdec0.c b/flvdec.c
index b9e36b3..8a9261b 100644
--- a/flvdec0.c
+++ b/flvdec.c
@@ -321,6 +321,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;
     }
@@ -367,6 +369,11 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
         vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
         ret = 3;     // not 4, reading packet type will consume one byte
         break;
+    case FLV_CODECID_HEVC:
+        par->codec_id = AV_CODEC_ID_HEVC;
+        vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
+        ret = 3;     // not 4, reading packet type will consume one byte
+        break;
     case FLV_CODECID_MPEG4:
         par->codec_id = AV_CODEC_ID_MPEG4;
         ret = 3;
@@ -1243,6 +1250,7 @@ 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_HEVC ||
         st->codecpar->codec_id == AV_CODEC_ID_MPEG4) {
         int type = avio_r8(s->pb);
         size--;
@@ -1252,7 +1260,7 @@ 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_HEVC ||st->codecpar->codec_id == AV_CODEC_ID_MPEG4) {
             // sign extension
             int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
             pts = av_sat_add64(dts, cts);
@@ -1268,7 +1276,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) {

 5.3修改编码flvenc.c,增加头文件hevc.h

    注意两个地方:

      1)ff_isom_write_hvcc(pb, par->extradata, par->extradata_size,0);

      2)if ((ret = ff_hevc_annexb2mp4_buf(pkt->data, &data, &size,0,NULL)) < 0)  

diff --git a/flvenc0.c b/flvenc.c
index 66c530a..2be4bec 100644
--- a/flvenc0.c
+++ b/flvenc.c
@@ -35,6 +35,7 @@
 #include "libavutil/opt.h"
 #include "libavcodec/put_bits.h"
 
+#include "hevc.h"
 
 static const AVCodecTag flv_video_codec_ids[] = {
     { AV_CODEC_ID_FLV1,     FLV_CODECID_H263 },
@@ -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 }
 };
 
@@ -490,7 +492,7 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
     AVIOContext *pb = s->pb;
     FLVContext *flv = s->priv_data;
 
-    if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+    if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_HEVC
             || par->codec_id == AV_CODEC_ID_MPEG4) {
         int64_t pos;
         avio_w8(pb,
@@ -537,7 +539,15 @@ 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);
+            //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);
@@ -797,7 +807,7 @@ 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_HEVC || par->codec_id == AV_CODEC_ID_MPEG4))
                 put_avc_eos_tag(pb, sc->last_ts);
         }
     }
@@ -848,12 +858,12 @@ 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_HEVC || par->codec_id == AV_CODEC_ID_MPEG4)
         flags_size = 5;
     else
         flags_size = 1;
 
-    if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+    if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_HEVC
             || par->codec_id == AV_CODEC_ID_MPEG4) {
         size_t side_size;
         uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
@@ -874,7 +884,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
                "Packets are not in the proper order with respect to DTS\n");
         return AVERROR(EINVAL);
     }
-    if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) {
+    if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_MPEG4) {
         if (pkt->pts == AV_NOPTS_VALUE) {
             av_log(s, AV_LOG_ERROR, "Packet is missing PTS\n");
             return AVERROR(EINVAL);
@@ -914,11 +924,20 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
         return AVERROR(EINVAL);
     }
 
-    if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) {
+    if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_MPEG4) {
         /* check if extradata looks like mp4 formatted */
         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;
+            if(par->codec_id == AV_CODEC_ID_HEVC)
+            {
+                if ((ret = ff_hevc_annexb2mp4_buf(pkt->data, &data, &size,0,NULL)) < 0)
+				    return ret;
+            }
+            else
+            {
+                if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 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) {
@@ -991,7 +1010,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_HEVC || par->codec_id == AV_CODEC_ID_MPEG4) {
             avio_w8(pb, 1); // AVC NALU
             avio_wb24(pb, pkt->pts - pkt->dts);
         }


6、编译ffmpeg
   cd FFmpeg-release-5.0/
   ./configure --enable-shared --enable-static --enable-debug --enable-libx264 --enable-libx265 --enable-libmp3lame --enable-gpl --disable-optimizations --disable-stripping --enable-libfreetype --enable-version3 --extra-cflags=-I../out/usr/local/include  --extra-ldflags=-L../out/usr/local/lib
   make -j8
   make DESTDIR=../out install

当执行./configure时遇到ERROR: x265 not found using pkg-config这个错误时,先执行下:
sudo apt install pkg-config

如已安装,还会提示,执行export 

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:`pwd`/../out/usr/local/lib/pkgconfig

`pwd`/../out/usr/local/lib/pkgconfig 不行,就用自己的绝对路径
   
7、验证
   cd out/usr/local
   export LD_LIBRARY_PATH='pwd'/lib:$LD_LIBRARY_PATH
   ./bin/ffmpeg  -i 1.mp4 -c:v libx265 -f flv 1.flv
   用./bin/ffprobe -i 1.flv 查看是否成功
   ./bin/ffmpeg  -i 1.flv -c:v libx264 2.mp4
   成功

8、测试rtmp推流

 下载安装支持h265的rtmp推流服务 pingos ,此平台个人觉得不好,有空可以试试修改srs

./bin/ffmpeg -re -stream_loop -1 -i 1.mp4 -c:v hevc_nvenc -f flv rtmp://192.168.0.15/live/t33
./bin/ffmpeg -c:v hevc_cuvid -i rtmp://192.168.0.15/live/t33 -c:v h264_nvenc -f flv rtmp://192.168.0.15/live/t35

这样就可以用vlc播放rtmp://192.168.0.15/live/t35。

感谢博主:染尘111

参考了他的博文:

ffmpeg编译支持h265的rtmp windown版本_染尘111的博客-CSDN博客_ffmpeg支持h265编解码版本

你可能感兴趣的:(ffmpeg,开发语言)