视频流媒体中视频数据的传输占据了绝大部分的带宽,如何提升编码效率、减小带宽使用、提升画面质量,成为音视频开发者努力的重点。hevc编码格式的推出为此带来了突破点。对于直播而言,大部分推拉流协议是基于rtmp的,因此本文将主要介绍如何在rtmp协议中增加对hevc视频编码格式的支持。
本文来自金山云obg事业部投稿,是《ffmpeg从入门到出家》系列的第一篇下半部分,由livevideostack审校整理,希望能让大家对ffmpeg有更深入了解。阅读上半部分内容请点击【阅读原文】。
文 / 施雪梅
4. hevc在rtmp中的扩展
为推进hevc视频编码格式在直播方案中的落地,经过cdn联盟讨论,并和主流云服务厂商达成一致,规范了hevc在rtmp/flv中的扩展,具体修改内容见下。
4.1 flv规范扩展
hevc为视频编码格式,因此对flv规范的扩展,只集中在video tag,其它部分,无任何改动。
4.1.1 支持hevc的videotagheader
扩展后的videotagheader如下图所示(红色字体为新增内容):
图9. 支持hevc的flvtagheader
修改点如下:
1.codecid - 定义hevc格式的值为12;
2.hevcpackettype - 当codecid == 12时,avcpackettype为hevcpackettype:
如果hevcpackettype为0,表示hevcvideopacket中存放的是hevc sequence header;
如果hevcpackettype为1,表示hevcvideopacket中存放的是hevc nalu;
如果hevcpackettype为2,表示hevcvidepacket中存放的是hevc end of sequence,即hevcdecoderconfigurationrecord;
3.compositiontime - 当codecid == 12时,同样需要compositiontime。
4.1.2 支持hevc的videotagbody
当codecid为12时,videotagbody中存放的就是hevc视频帧内容。
扩展后的videotagbody如下图所示(红色字体为hevc新增内容):
图10. 支持hevc的videotagbody
4.2 ffmpeg中的修改
我们已在ffmpeg的各个版本上提供相关的完整修改,具体参见:https://github.com/ksvc/ffmpeg,完整patch获取及相关说明见:https://github.com/ksvc/ffmpeg/wiki。
由第二章节的阐述可知,flv的解复用和复用功能代码分别在libavformt/flvdec.c和libavformat/flvenc.c中,扩展后的修改也都集中在这两个文件。本节将在ffmpeg3.3的基础上,说明修改的关键点。
4.2.1 编码类型定义
libavformat/flv.h中按照videotagheader中的codecid定义了一组视频编码格式的枚举值,扩展后的枚举定义如下:
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,};
4.2.2 flv demux
在解复用过程中,flv_read_packet方法是整个过程的核心,它里面完成了对每个tag的读取和解析。
4.1.1中提到,如果hevcpackettype为0时,表示hevcvideopacket中存放的是hevc sequence header,也就是hevcdecoderconfigurationrecord,解码时需设置hevcdecoderconfigurationrecord方能正确解码。
hevc与avc视频帧在flv中的存放格式相同,所以只需在读取video tag的地方增加av_codec_id_hevc的判断条件即可,调整后的代码如下:
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--; 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 = dts + cts; if (ctswrong_dts) av_log(s, av_log_warning, negative cts, previous timestamps might be wrong.\n); flv->wrong_dts = 1; } else if (ffabs(dts - pts) > 1000*60*15) { av_log(s, av_log_warning, invalid timestamps %prid64 %prid64\n, dts, pts); dts = pts = av_nopts_value; } } if (type == 0 &&(!st->codecpar->extradata || st->codecpar->codec_id == av_codec_id_aac || st->codecpar->codec_id == av_codec_id_hevc || st->codecpar->codec_id == av_codec_id_h264)) { avdictionaryentry *t; if (st->codecpar->extradata) { if ((ret = flv_queue_extradata(flv, s->pb, stream_type, size)) < 0) return ret; ret = fferror_redo; goto leave; } if ((ret = flv_get_extradata(s, st, size)) avcodecparameter->extradata中。
4.2.3 flv mux
flv mux的修改相对较多、header、packet、trailer中均有涉及。
4.2.3.1 write header
flv_write_header中主要完成了以下工作:
写入flv header;
写入metadata;
如果音频编码格式为aac,则写入第一个audio tag,其audiotagbody中存放的是aac sequence header;
如果视频编码格式为avc,则写入第一个video tag,其中videotagbody中存放的是avc sequence header。
同样,当视频编码格式hevc时,也要写入第一个videotag,其中videotagbody中存放的是hevcdecoderconfigurationrecord,修改点如下:
avio_w8(pb, par->codec_tag | flv_frame_key); // flagsavio_w8(pb, 0); // avc sequence headeravio_wb24(pb, 0); // composition timeif (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);
ff_isom_write_hvcc的作用是将extradata转为hevcdecoderconfigurationrecord结构并写入。
4.2.3.2 write packet
flv_write_packet的作用是写入音视频帧,其中有关写入video数据的地方,都需要加上av_codec_id_hevc的判断条件,修改内容如下:
else if (par->codec_id == av_codec_id_hevc ){ if (par->extradata_size> 0 && *(uint8_t*)par->extradata != 1) if ((ret = ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, null)) codec_type == avmedia_type_video && (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);
5. 结束语
本文简单介绍了如何在ffmpeg中扩展rtmp协议对hevc编码格式的支持,而要将hevc应用于直播整体方案,除推流端和播放端要提供相应能力外,源站、cdn、转码服务同样都需要提供这种能力。金山云的所有视频服务中,已完全支持hevc视频编码格式,欢迎大家使用。
RFID怎样为农村的物流助力
全球十三家广电组织首次对话 倡议统一标准
基于物联网无线技术实现4S店VOC排放监测系统
大健康领域的融资金额及发展项目分析
华为荣耀9和荣耀v9哪个好?华为荣耀9和荣耀v9区别对比,华为荣耀9和v9买哪个?
如何在RTMP协议中增加对HEVC视频编码格式的支持
数字化技术热潮下,RFID迎来许多机遇
技术创新推动机器人传感器市场的发展
两种电路中电容容值计算的方法
首届数字化智造博览会回顾
薪火相传 绽放未来 ——【官宣】“广东希荻微”更名为“希荻微集团”
高通公布新型快速充电技术,15分钟内将4500mAh电池充满100%
英飞凌为工业4.0提供业界领先的半导体解决方案
交换机的基本工作原理?交换机的二、三、四层交换技术简析
调节DAC输出电压范围的几种方式
MCU巨头,奔向同一个目标
基于PLC切削液自动勾兑机的远程监控故障报警系统
Senorics已成功完成Pre-A轮融资,总金额超800万欧元
美允许五角大楼延后执行华为禁令_为什么允许延后执行华为禁令
固态硬盘接口有几种