From 88287f270df660645b3f6c813ab3fd7ad522e64c Mon Sep 17 00:00:00 2001 From: Franken Zeng Date: Wed, 14 Jun 2017 21:33:54 +0800 Subject: [PATCH] The RTMP protocol extensions for H.265/HEVC --- libavformat/flv.h | 1 + libavformat/flvdec.c | 16 +++++++++++++--- libavformat/flvenc.c | 29 ++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/libavformat/flv.h b/libavformat/flv.h index df5ce3d17f8c7..089bc76972d48 100644 --- a/libavformat/flv.h +++ b/libavformat/flv.h @@ -109,6 +109,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 94c9e28334382..8adae2f2f1299 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -36,6 +36,7 @@ #include "internal.h" #include "avio_internal.h" #include "flv.h" +#include "hevc.h" #define VALIDATE_INDEX_TS_THRESH 2500 @@ -291,6 +292,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; } @@ -340,6 +343,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_NONE; + ret = 3; // not 4, reading packet type will consume one byte + break; default: avpriv_request_sample(s, "Video codec (%x)", flv_codecid); par->codec_tag = flv_codecid; @@ -1142,10 +1150,12 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) 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--; - 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; @@ -1161,7 +1171,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) } } 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 899b07ea7bef8..eb955e5b45154 100644 --- a/libavformat/flvenc.c +++ b/libavformat/flvenc.c @@ -34,6 +34,7 @@ #include "libavutil/opt.h" #include "libavcodec/put_bits.h" #include "libavcodec/aacenctab.h" +#include "hevc.h" static const AVCodecTag flv_video_codec_ids[] = { @@ -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 } }; @@ -486,7 +488,7 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par) { 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 ? @@ -533,7 +535,11 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par) { 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); @@ -836,7 +842,7 @@ static int flv_write_trailer(AVFormatContext *s) 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); } } @@ -880,15 +886,16 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) int64_t cur_offset = avio_tell(pb); 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_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 + } 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))) { @@ -951,6 +958,10 @@ 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) { + 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) { @@ -1021,9 +1032,9 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) else avio_w8(pb, ((FFALIGN(par->width, 16) - par->width) << 4) | (FFALIGN(par->height, 16) - par->height)); - } else if (par->codec_id == AV_CODEC_ID_AAC) + } 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); }