Giter Club home page Giter Club logo

ffmpeg_rtmp_h265's Introduction

在ffmpeg中支持hevc/vp8/vp9/opus的flv格式

项目背景

  1. 当前阿里云,金山云等众多cdn,已经支持hevc in rtmp/flv(采用增加codecid=12的方式)
  2. 国外大厂和国外cdn支持hevc in rtmp/flv方式:enhanced-rtmp

基于兼容上面两种hevc in rtmp/flv的方式,本库均支持。

本库支持的版本(见对应的branch分支):

  • 4.1
  • 4.3
  • 5.0
  • 5.1
  • 6.0(支持enhanced-rtmp)

国内cdn方式: 新增codecid

hevc/vp8/vp9/opus在rtmp中的codecid没有官方协议定义,由国内众多知名cdn共同制定。


FLV_CODECID_OPUS = 9 << FLV_AUDIO_CODECID_OFFSET

enum {
    FLV_CODECID_H263    = 2,
    FLV_CODECID_SCREEN  = 3,
    FLV_CODECID_VP6     = 4,
    FLV_CODECID_VP6A    = 5,
    FLV_CODECID_SCREEN2 = 6,
    FLV_CODECID_H264    = 7,
    FLV_CODECID_REALH263= 8,
    FLV_CODECID_MPEG4   = 9,
    FLV_CODECID_HEVC    = 12,
    FLV_CODECID_AV1     = 13,
    FLV_CODECID_VP8     = 14,
    FLV_CODECID_VP9     = 15,
};

国外大厂和cdn方式:enhanced-rtmp

  • mux/推流:需要设置: -f flv -flvflags ext_header
ffmpeg -re -i source.flv -c:v libx265 -c:a copy -f flv -flvflags ext_header rtmp://192.168.0.1/live/1000
  • demux/拉流: 不需要格外操作,自动识别

编译

只需要把flv.h/flvdec.c/flvenc.c拷贝入libavformat文件夹中,后面ffmpeg正常编译即可。

ffmpeg_rtmp_h265's People

Contributors

runner365 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ffmpeg_rtmp_h265's Issues

ffmpeg 6.0 無法拉 OBS 的 RTMP 流

OBS 推送 HEVC 至 ossrs/srs:6,再用 ffmpeg 拉流,卻沒有 video track

編譯方式遵照官方說明:https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu

root@ffmpeg-6d5847bbf-x4nfj:/app# ./ffmpeg -i rtmp://srs-edge:19350/live/test -acodec copy -vcodec libx264 -b:v 250k -filter:v scale=w=640:h=360 -preset veryfast -tune zerolatency -profile:v baseline -pix_fmt yuv420p -f flv rtmp://srs-edge:19350/alt/live-test-video_250k2
ffmpeg version n6.0 Copyright (c) 2000-2023 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
  configuration: --prefix=/app/ffmpeg/build --pkg-config-flags=--static --extra-libs='-lpthread -lm' --extra-libs=-lpthread --disable-asm --disable-x86asm --disable-inline-asm --enable-gpl --enable-pthreads --enable-libaom --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-nonfree
  libavutil      58.  2.100 / 58.  2.100
  libavcodec     60.  3.100 / 60.  3.100
  libavformat    60.  3.100 / 60.  3.100
  libavdevice    60.  1.100 / 60.  1.100
  libavfilter     9.  3.100 /  9.  3.100
  libswscale      7.  1.100 /  7.  1.100
  libswresample   4. 10.100 /  4. 10.100
  libpostproc    57.  1.100 / 57.  1.100
Input #0, flv, from 'rtmp://srs-edge:19350/live/test':
  Metadata:
    |RtmpSampleAccess: true
    fileSize        : 0
    audiochannels   : 2
    2.1             : false
    3.1             : false
    4.0             : false
    4.1             : false
    5.1             : false
    7.1             : false
    encoder         : obs-output module (libobs version 29.1.0-beta4)
    server          : SRS/6.0.36(Bee)
    server_version  : 6.0.36
  Duration: N/A, start: 0.000000, bitrate: 163 kb/s
  Stream #0:0: Data: none
  Stream #0:1: Audio: aac (LC), 48000 Hz, stereo, fltp, 163 kb/s
[out#0/flv @ 0x559bca2ee4e0] Codec AVOption profile () has not been used for any stream. The most likely reason is either wrong type (e.g. a video option with no video streams) or that it is a private option of some encoder which was not actually used for any stream.
[out#0/flv @ 0x559bca2ee4e0] Codec AVOption b (set bitrate (in bits/s)) has not been used for any stream. The most likely reason is either wrong type (e.g. a video option with no video streams) or that it is a private option of some encoder which was not actually used for any stream.
Output #0, flv, to 'rtmp://srs-edge:19350/alt/live-test-video_250k2':
  Metadata:
    |RtmpSampleAccess: true
    fileSize        : 0
    audiochannels   : 2
    2.1             : false
    3.1             : false
    4.0             : false
    4.1             : false
    5.1             : false
    7.1             : false
    server_version  : 6.0.36
    server          : SRS/6.0.36(Bee)
    encoder         : Lavf60.3.100
  Stream #0:0: Audio: aac (LC) ([10][0][0][0] / 0x000A), 48000 Hz, stereo, fltp, 163 kb/s
Stream mapping:
  Stream #0:1 -> #0:0 (copy)
Press [q] to stop, [?] for help
size=      11kB time=00:00:09.99 bitrate=   9.0kbits/s speed=2.13x   

Unable to compile

Hello, when I use them in FFMpeg version 4.4.4 and 5.1.2, I can never compile. I use MSYS2 compiled by msys2 in Windows.No, I think it's my problem?Will get the following errors:

libavformat/flvdec.c:31:10: fatal error: libavutil/dict_internal.h: No such file or directory 31 | #include "libavutil/dict_internal.h" | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ compilation terminated. CC libavformat/format.o make: *** [ffbuild/common.mak:81: libavformat/flvdec.o] Error 1 make: *** Waiting for unfinished jobs.... libavformat/flvenc.c: In function 'write_metadata': libavformat/flvenc.c:375:19: error: implicit declaration of function 'av_dict_iterate'; did you mean 'av_codec_iterate'? [-Werror=implicit-function-declaration] 375 | while ((tag = av_dict_iterate(s->metadata, tag))) { | ^~~~~~~~~~~~~~~ | av_codec_iterate libavformat/flvenc.c:375:17: warning: assignment to 'const AVDictionaryEntry *' from 'int' makes pointer from integer without a cast [-Wint-conversion] 375 | while ((tag = av_dict_iterate(s->metadata, tag))) { | ^ libavformat/flvenc.c: At top level: libavformat/flvenc.c:1184:7: error: unknown type name 'FFOutputFormat' 1184 | const FFOutputFormat ff_flv_muxer = { | ^~~~~~~~~~~~~~ libavformat/flvenc.c:1185:5: error: field name not in record or union initializer 1185 | .p.name = "flv", | ^ libavformat/flvenc.c:1185:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1185:23: warning: initialization of 'int' from 'const char *' makes integer from pointer without a cast [-Wint-conversion] 1185 | .p.name = "flv", | ^~~~~ libavformat/flvenc.c:1185:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1185:23: error: initializer element is not computable at load time libavformat/flvenc.c:1185:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1186:5: error: field name not in record or union initializer 1186 | .p.long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"), | ^ libavformat/flvenc.c:1186:5: note: (near initialization for 'ff_flv_muxer') In file included from ./libavutil/common.h:575, from ./libavutil/avutil.h:296, from ./libavcodec/codec_desc.h:24, from libavformat/flvenc.c:27: libavformat/flvenc.c:1186:44: warning: excess elements in scalar initializer 1186 | .p.long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"), | ^~~~~~~~~~~~~~~~~~~ ./libavutil/internal.h:117:36: note: in definition of macro 'NULL_IF_CONFIG_SMALL' 117 | # define NULL_IF_CONFIG_SMALL(x) x | ^ libavformat/flvenc.c:1186:44: note: (near initialization for 'ff_flv_muxer') 1186 | .p.long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"), | ^~~~~~~~~~~~~~~~~~~ ./libavutil/internal.h:117:36: note: in definition of macro 'NULL_IF_CONFIG_SMALL' 117 | # define NULL_IF_CONFIG_SMALL(x) x | ^ libavformat/flvenc.c:1187:5: error: field name not in record or union initializer 1187 | .p.mime_type = "video/x-flv", | ^ libavformat/flvenc.c:1187:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1187:23: warning: excess elements in scalar initializer 1187 | .p.mime_type = "video/x-flv", | ^~~~~~~~~~~~~ libavformat/flvenc.c:1187:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1188:5: error: field name not in record or union initializer 1188 | .p.extensions = "flv", | ^ libavformat/flvenc.c:1188:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1188:23: warning: excess elements in scalar initializer 1188 | .p.extensions = "flv", | ^~~~~ libavformat/flvenc.c:1188:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1189:5: error: field name not in record or union initializer 1189 | .priv_data_size = sizeof(FLVContext), | ^ libavformat/flvenc.c:1189:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1189:23: warning: excess elements in scalar initializer 1189 | .priv_data_size = sizeof(FLVContext), | ^~~~~~ libavformat/flvenc.c:1189:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1190:5: error: field name not in record or union initializer 1190 | .p.audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF, | ^ libavformat/flvenc.c:1190:5: note: (near initialization for 'ff_flv_muxer') In file included from ./libavutil/bswap.h:35, from ./libavutil/intreadwrite.h:25, from libavformat/flvenc.c:22: ./config.h:498:27: warning: excess elements in scalar initializer 498 | #define CONFIG_LIBMP3LAME 0 | ^ libavformat/flvenc.c:1190:23: note: in expansion of macro 'CONFIG_LIBMP3LAME' 1190 | .p.audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF, | ^~~~~~~~~~~~~~~~~ ./config.h:498:27: note: (near initialization for 'ff_flv_muxer') 498 | #define CONFIG_LIBMP3LAME 0 | ^ libavformat/flvenc.c:1190:23: note: in expansion of macro 'CONFIG_LIBMP3LAME' 1190 | .p.audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF, | ^~~~~~~~~~~~~~~~~ libavformat/flvenc.c:1191:5: error: field name not in record or union initializer 1191 | .p.video_codec = AV_CODEC_ID_FLV1, | ^ libavformat/flvenc.c:1191:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1191:23: warning: excess elements in scalar initializer 1191 | .p.video_codec = AV_CODEC_ID_FLV1, | ^~~~~~~~~~~~~~~~ libavformat/flvenc.c:1191:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1192:5: error: field name not in record or union initializer 1192 | .init = flv_init, | ^ libavformat/flvenc.c:1192:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1192:23: warning: excess elements in scalar initializer 1192 | .init = flv_init, | ^~~~~~~~ libavformat/flvenc.c:1192:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1193:5: error: field name not in record or union initializer 1193 | .write_header = flv_write_header, | ^ libavformat/flvenc.c:1193:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1193:23: warning: excess elements in scalar initializer 1193 | .write_header = flv_write_header, | ^~~~~~~~~~~~~~~~ libavformat/flvenc.c:1193:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1194:5: error: field name not in record or union initializer 1194 | .write_packet = flv_write_packet, | ^ libavformat/flvenc.c:1194:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1194:23: warning: excess elements in scalar initializer 1194 | .write_packet = flv_write_packet, | ^~~~~~~~~~~~~~~~ libavformat/flvenc.c:1194:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1195:5: error: field name not in record or union initializer 1195 | .write_trailer = flv_write_trailer, | ^ libavformat/flvenc.c:1195:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1195:23: warning: excess elements in scalar initializer 1195 | .write_trailer = flv_write_trailer, | ^~~~~~~~~~~~~~~~~ libavformat/flvenc.c:1195:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1196:5: error: field name not in record or union initializer 1196 | .deinit = flv_deinit, | ^ libavformat/flvenc.c:1196:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1196:23: warning: excess elements in scalar initializer 1196 | .deinit = flv_deinit, | ^~~~~~~~~~ libavformat/flvenc.c:1196:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1197:5: error: field name not in record or union initializer 1197 | .check_bitstream= flv_check_bitstream, | ^ libavformat/flvenc.c:1197:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1197:23: warning: excess elements in scalar initializer 1197 | .check_bitstream= flv_check_bitstream, | ^~~~~~~~~~~~~~~~~~~ libavformat/flvenc.c:1197:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1198:5: error: field name not in record or union initializer 1198 | .p.codec_tag = (const AVCodecTag* const []) { | ^ libavformat/flvenc.c:1198:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1198:23: warning: excess elements in scalar initializer 1198 | .p.codec_tag = (const AVCodecTag* const []) { | ^ libavformat/flvenc.c:1198:23: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1201:5: error: field name not in record or union initializer 1201 | .p.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | | ^ libavformat/flvenc.c:1201:5: note: (near initialization for 'ff_flv_muxer') In file included from libavformat/flvenc.c:31: libavformat/avformat.h:480:29: warning: excess elements in scalar initializer 480 | #define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ | ^~~~~~ libavformat/flvenc.c:1201:23: note: in expansion of macro 'AVFMT_GLOBALHEADER' 1201 | .p.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | | ^~~~~~~~~~~~~~~~~~ libavformat/avformat.h:480:29: note: (near initialization for 'ff_flv_muxer') 480 | #define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ | ^~~~~~ libavformat/flvenc.c:1201:23: note: in expansion of macro 'AVFMT_GLOBALHEADER' 1201 | .p.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | | ^~~~~~~~~~~~~~~~~~ libavformat/flvenc.c:1203:5: error: field name not in record or union initializer 1203 | .p.priv_class = &flv_muxer_class, | ^ libavformat/flvenc.c:1203:5: note: (near initialization for 'ff_flv_muxer') libavformat/flvenc.c:1203:23: warning: excess elements in scalar initializer 1203 | .p.priv_class = &flv_muxer_class, | ^ libavformat/flvenc.c:1203:23: note: (near initialization for 'ff_flv_muxer') cc1.exe: some warnings being treated as errors make: *** [ffbuild/common.mak:81: libavformat/flvenc.o] Error 1

Excuse me, thank you

问题反馈

有两处地方可能有问题,辛苦确认指正:
1)flv.h文件中,以下两个宏的定义:
#define EXT_HEADER_IS_KEYFRAME(x) (((x) & FLV_VIDEO_FRAMETYPE_MASK) == FT_KEY)
#define EXT_HEADER_IS_INTERFRAME(x) (((x) & FLV_VIDEO_FRAMETYPE_MASK) == FT_INTER)
应该是:
#define FLV_VIDEO_EXT_FRAMETYPE_MASK 0x70
#define EXT_HEADER_IS_KEYFRAME(x) (((x) & FLV_VIDEO_EXT_FRAMETYPE_MASK) == FT_KEY)
#define EXT_HEADER_IS_INTERFRAME(x) (((x) & FLV_VIDEO_EXT_FRAMETYPE_MASK) == FT_INTER)
2)flvenc.c文件中,flv_write_packet方法的1085行:
unsigned char is_key = (pkt->flags & AV_PKT_FLAG_KEY) ? FT_KEY : 0;
应该是:
unsigned char is_key = (pkt->flags & AV_PKT_FLAG_KEY) ? FT_KEY : FT_INTER;

didn't support the tee muxer?

-f tee -map 0:v -map 0:a '[f=flv:flvflags=ext_header:onfail=ignore]rtmp://a.rtmp.youtube.com/live2/key1|[f=flv:flvflags=ext_header:onfail=ignore]rtmp://a.rtmp.youtube.com/live2/key2'

seems dint work

enhanced_rtmp 规范的 HEVC over FLV 视频无法 seek

6.0 打入 patch 后,相同音视频编码内容的文件,使用 ffplay 播放,

codecid=12 规范的 FLV 文件可以正常拖动进度,
enhanced_rtmp 规范的 FLV (HEVC) 文件无法拖动进度,拖动时报错。

FFmpeg/tree/master 播放 enhanced_rtmp 规范的 FLV (HEVC) 文件 可以拖动。

Video codec hevc not compatible with flv!

I compiled ffmpeg with libx265 based on your instruction, but when I tried to push hevc stream through rtmp, I faced with this error;

[flv @ 0x563fe9051c80] Video codec hevc not compatible with flv
Could not write header for output file #0 (incorrect codec parameters ?): Function not implemented
Error initializing output stream 0:0 -- 

How can I send hevc stream by rtmp and flv?
thanks.

flv_write_packet实现

flv_write_packet里
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 ||
par->codec_id == AV_CODEC_ID_OPUS)
flags_size = 2;
else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 ||
par->codec_id == AV_CODEC_ID_H265 || par->codec_id == AV_CODEC_ID_VP8 ||
par->codec_id == AV_CODEC_ID_VP9) {
if (is_flv_extern_header_enable(flv, par->codec_id) && (pkt->dts != pkt->pts)) {
flags_size = 8;
} else {
flags_size = 5;
}
}
else
flags_size = 1;

如果是扩展rtmp头,flags_size是8为什么不是5

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.