From bd52982e0ef36a60b14df946e8464679c4328b63 Mon Sep 17 00:00:00 2001 From: Franken Zeng Date: Wed, 14 Jun 2017 21:47:27 +0800 Subject: [PATCH] The RTMP protocol extensions for H.265/HEVC --- libavformat/flv.h | 1 + libavformat/flvdec.c | 15 ++++++++++++--- libavformat/flvenc.c | 28 ++++++++++++++++++++-------- 3 files changed, 33 insertions(+), 11 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 36a179722f6c2..c4b06932a9707 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 @@ -231,6 +232,8 @@ static int flv_same_video_codec(AVCodecContext *vcodec, int flags) return vcodec->codec_id == AV_CODEC_ID_VP6A; case FLV_CODECID_H264: return vcodec->codec_id == AV_CODEC_ID_H264; + case FLV_CODECID_HEVC: + return vcodec->codec_id == AV_CODEC_ID_HEVC; default: return vcodec->codec_tag == flv_codecid; } @@ -275,6 +278,10 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, case FLV_CODECID_MPEG4: vcodec->codec_id = AV_CODEC_ID_MPEG4; return 3; + case FLV_CODECID_HEVC: + vcodec->codec_id = AV_CODEC_ID_HEVC; + vstream->need_parsing = AVSTREAM_PARSE_NONE; + return 3; // not 4, reading packet type will consume one byte default: avpriv_request_sample(s, "Video codec (%x)", flv_codecid); vcodec->codec_tag = flv_codecid; @@ -978,10 +985,12 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) if (st->codec->codec_id == AV_CODEC_ID_AAC || st->codec->codec_id == AV_CODEC_ID_H264 || - st->codec->codec_id == AV_CODEC_ID_MPEG4) { + st->codec->codec_id == AV_CODEC_ID_MPEG4 || + st->codec->codec_id == AV_CODEC_ID_HEVC) { int type = avio_r8(s->pb); size--; - if (st->codec->codec_id == AV_CODEC_ID_H264 || st->codec->codec_id == AV_CODEC_ID_MPEG4) { + if (st->codec->codec_id == AV_CODEC_ID_H264 || st->codec->codec_id == AV_CODEC_ID_MPEG4 + || st->codec->codec_id == AV_CODEC_ID_HEVC) { // sign extension int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000; pts = dts + cts; @@ -997,7 +1006,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) } } if (type == 0 && (!st->codec->extradata || st->codec->codec_id == AV_CODEC_ID_AAC || - st->codec->codec_id == AV_CODEC_ID_H264)) { + st->codec->codec_id == AV_CODEC_ID_H264 || st->codec->codec_id == AV_CODEC_ID_HEVC)) { AVDictionaryEntry *t; if (st->codec->extradata) { diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c index e217ba8a826cc..4187c827c87c0 100644 --- a/libavformat/flvenc.c +++ b/libavformat/flvenc.c @@ -28,6 +28,7 @@ #include "flv.h" #include "internal.h" #include "metadata.h" +#include "hevc.h" static const AVCodecTag flv_video_codec_ids[] = { @@ -40,6 +41,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 } }; @@ -440,7 +442,8 @@ static int flv_write_header(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; - if (enc->codec_id == AV_CODEC_ID_AAC || enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) { + if (enc->codec_id == AV_CODEC_ID_AAC || enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4 + || enc->codec_id == AV_CODEC_ID_HEVC) { int64_t pos; avio_w8(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); @@ -457,7 +460,11 @@ static int flv_write_header(AVFormatContext *s) avio_w8(pb, enc->codec_tag | FLV_FRAME_KEY); // flags avio_w8(pb, 0); // AVC sequence header avio_wb24(pb, 0); // composition time - ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size); + if (enc->codec_id == AV_CODEC_ID_HEVC) { + ff_isom_write_hvcc(pb, enc->extradata, enc->extradata_size, 0); + } else { + ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size); + } } data_size = avio_tell(pb) - pos; avio_seek(pb, -data_size - 10, SEEK_CUR); @@ -483,7 +490,7 @@ static int flv_write_trailer(AVFormatContext *s) AVCodecContext *enc = s->streams[i]->codec; FLVStreamContext *sc = s->streams[i]->priv_data; if (enc->codec_type == AVMEDIA_TYPE_VIDEO && - (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4)) + (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4 || enc->codec_id == AV_CODEC_ID_HEVC)) put_avc_eos_tag(pb, sc->last_ts); } @@ -515,12 +522,13 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) int flags = -1, flags_size, ret; if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A || - enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_AAC) + enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_AAC) { flags_size = 2; - else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) + } else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4 || enc->codec_id == AV_CODEC_ID_HEVC) { flags_size = 5; - else + } else { flags_size = 1; + } if (flv->delay == AV_NOPTS_VALUE) flv->delay = -pkt->dts; @@ -566,6 +574,10 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0) return ret; + } else if (enc->codec_id == AV_CODEC_ID_HEVC) { + if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) + if ((ret = ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, NULL)) < 0) + return ret; } else if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { if (!s->streams[pkt->stream_index]->nb_frames) { @@ -636,9 +648,9 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) else avio_w8(pb, ((FFALIGN(enc->width, 16) - enc->width) << 4) | (FFALIGN(enc->height, 16) - enc->height)); - } else if (enc->codec_id == AV_CODEC_ID_AAC) + } else if (enc->codec_id == AV_CODEC_ID_AAC) { avio_w8(pb, 1); // AAC raw - else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) { + } else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4 || enc->codec_id == AV_CODEC_ID_HEVC) { avio_w8(pb, 1); // AVC NALU avio_wb24(pb, pkt->pts - pkt->dts); }