mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 11:51:57 +00:00
* H265: Support HEVC over HLS.(#465) * HLS: Support HEVC over HLS. v6.0.11 (#465) Co-authored-by: winlin <winlin@vip.126.com>
This commit is contained in:
parent
4bfc4de710
commit
fff8d9863c
6 changed files with 58 additions and 29 deletions
|
@ -8,6 +8,7 @@ The changelog for SRS.
|
||||||
|
|
||||||
## SRS 6.0 Changelog
|
## SRS 6.0 Changelog
|
||||||
|
|
||||||
|
* v6.0, 2023-01-02, For [#465](https://github.com/ossrs/srs/issues/465): HLS: Support HEVC over HLS. v6.0.11
|
||||||
* v6.0, 2022-12-30, Support first SRS6 version. v6.0.10
|
* v6.0, 2022-12-30, Support first SRS6 version. v6.0.10
|
||||||
* v6.0, 2022-12-26, For [#465](https://github.com/ossrs/srs/issues/465): TS: Support disable audio or video to make mpegts.js happy. v6.0.9
|
* v6.0, 2022-12-26, For [#465](https://github.com/ossrs/srs/issues/465): TS: Support disable audio or video to make mpegts.js happy. v6.0.9
|
||||||
* v6.0, 2022-12-26, For [#465](https://github.com/ossrs/srs/issues/465): TS: Fix bug for codec detecting for HTTP-TS. v6.0.8
|
* v6.0, 2022-12-26, For [#465](https://github.com/ossrs/srs/issues/465): TS: Fix bug for codec detecting for HTTP-TS. v6.0.8
|
||||||
|
|
|
@ -203,6 +203,7 @@ SrsHlsMuxer::SrsHlsMuxer()
|
||||||
context = new SrsTsContext();
|
context = new SrsTsContext();
|
||||||
segments = new SrsFragmentWindow();
|
segments = new SrsFragmentWindow();
|
||||||
latest_acodec_ = SrsAudioCodecIdForbidden;
|
latest_acodec_ = SrsAudioCodecIdForbidden;
|
||||||
|
latest_vcodec_ = SrsVideoCodecIdForbidden;
|
||||||
|
|
||||||
memset(key, 0, 16);
|
memset(key, 0, 16);
|
||||||
memset(iv, 0, 16);
|
memset(iv, 0, 16);
|
||||||
|
@ -282,6 +283,24 @@ void SrsHlsMuxer::set_latest_acodec(SrsAudioCodecId v)
|
||||||
latest_acodec_ = v;
|
latest_acodec_ = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsVideoCodecId SrsHlsMuxer::latest_vcodec()
|
||||||
|
{
|
||||||
|
// If current context writer exists, we query from it.
|
||||||
|
if (current && current->tscw) return current->tscw->vcodec();
|
||||||
|
|
||||||
|
// Get the configured or updated config.
|
||||||
|
return latest_vcodec_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHlsMuxer::set_latest_vcodec(SrsVideoCodecId v)
|
||||||
|
{
|
||||||
|
// Refresh the codec in context writer for current segment.
|
||||||
|
if (current && current->tscw) current->tscw->set_vcodec(v);
|
||||||
|
|
||||||
|
// Refresh the codec for future segments.
|
||||||
|
latest_vcodec_ = v;
|
||||||
|
}
|
||||||
|
|
||||||
srs_error_t SrsHlsMuxer::initialize()
|
srs_error_t SrsHlsMuxer::initialize()
|
||||||
{
|
{
|
||||||
return srs_success;
|
return srs_success;
|
||||||
|
@ -399,13 +418,17 @@ srs_error_t SrsHlsMuxer::segment_open()
|
||||||
std::string default_vcodec_str = _srs_config->get_hls_vcodec(req->vhost);
|
std::string default_vcodec_str = _srs_config->get_hls_vcodec(req->vhost);
|
||||||
if (default_vcodec_str == "h264") {
|
if (default_vcodec_str == "h264") {
|
||||||
default_vcodec = SrsVideoCodecIdAVC;
|
default_vcodec = SrsVideoCodecIdAVC;
|
||||||
|
} else if (default_vcodec_str == "h265") {
|
||||||
|
default_vcodec = SrsVideoCodecIdHEVC;
|
||||||
} else if (default_vcodec_str == "vn") {
|
} else if (default_vcodec_str == "vn") {
|
||||||
default_vcodec = SrsVideoCodecIdDisabled;
|
default_vcodec = SrsVideoCodecIdDisabled;
|
||||||
} else {
|
} else {
|
||||||
srs_warn("hls: use h264 for other codec=%s", default_vcodec_str.c_str());
|
srs_warn("hls: use h264 for other codec=%s", default_vcodec_str.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Now that we know the latest video codec in stream, use it.
|
||||||
|
if (latest_vcodec_ != SrsVideoCodecIdForbidden) default_vcodec = latest_vcodec_;
|
||||||
|
|
||||||
// new segment.
|
// new segment.
|
||||||
current = new SrsHlsSegment(context, default_acodec, default_vcodec, writer);
|
current = new SrsHlsSegment(context, default_acodec, default_vcodec, writer);
|
||||||
current->sequence_no = _sequence_no++;
|
current->sequence_no = _sequence_no++;
|
||||||
|
@ -546,7 +569,7 @@ bool SrsHlsMuxer::is_segment_absolutely_overflow()
|
||||||
|
|
||||||
bool SrsHlsMuxer::pure_audio()
|
bool SrsHlsMuxer::pure_audio()
|
||||||
{
|
{
|
||||||
return current && current->tscw && current->tscw->video_codec() == SrsVideoCodecIdDisabled;
|
return current && current->tscw && current->tscw->vcodec() == SrsVideoCodecIdDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsHlsMuxer::flush_audio(SrsTsMessageCache* cache)
|
srs_error_t SrsHlsMuxer::flush_audio(SrsTsMessageCache* cache)
|
||||||
|
@ -576,7 +599,7 @@ srs_error_t SrsHlsMuxer::flush_audio(SrsTsMessageCache* cache)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsHlsMuxer::flush_video(SrsTsMessageCache* cache, SrsVideoFrame* frame)
|
srs_error_t SrsHlsMuxer::flush_video(SrsTsMessageCache* cache)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
@ -595,12 +618,6 @@ srs_error_t SrsHlsMuxer::flush_video(SrsTsMessageCache* cache, SrsVideoFrame* fr
|
||||||
// update the duration of segment.
|
// update the duration of segment.
|
||||||
current->append(cache->video->dts / 90);
|
current->append(cache->video->dts / 90);
|
||||||
|
|
||||||
// The video codec might change during streaming. Note that the frame might be NULL, when reap segment.
|
|
||||||
if (frame && frame->vcodec()) {
|
|
||||||
SrsTsContextWriter* tscw = current->tscw;
|
|
||||||
tscw->update_video_codec(frame->vcodec()->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = current->tscw->write_video(cache->video)) != srs_success) {
|
if ((err = current->tscw->write_video(cache->video)) != srs_success) {
|
||||||
return srs_error_wrap(err, "hls: write video");
|
return srs_error_wrap(err, "hls: write video");
|
||||||
}
|
}
|
||||||
|
@ -1039,7 +1056,14 @@ srs_error_t SrsHlsController::write_audio(SrsAudioFrame* frame, int64_t pts)
|
||||||
srs_error_t SrsHlsController::write_video(SrsVideoFrame* frame, int64_t dts)
|
srs_error_t SrsHlsController::write_video(SrsVideoFrame* frame, int64_t dts)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// Refresh the codec ASAP.
|
||||||
|
if (muxer->latest_vcodec() != frame->vcodec()->id) {
|
||||||
|
srs_trace("HLS: Switch video codec %d(%s) to %d(%s)", muxer->latest_acodec(), srs_video_codec_id2str(muxer->latest_vcodec()).c_str(),
|
||||||
|
frame->vcodec()->id, srs_video_codec_id2str(frame->vcodec()->id).c_str());
|
||||||
|
muxer->set_latest_vcodec(frame->vcodec()->id);
|
||||||
|
}
|
||||||
|
|
||||||
// write video to cache.
|
// write video to cache.
|
||||||
if ((err = tsmc->cache_video(frame, dts)) != srs_success) {
|
if ((err = tsmc->cache_video(frame, dts)) != srs_success) {
|
||||||
return srs_error_wrap(err, "hls: cache video");
|
return srs_error_wrap(err, "hls: cache video");
|
||||||
|
@ -1059,7 +1083,7 @@ srs_error_t SrsHlsController::write_video(SrsVideoFrame* frame, int64_t dts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush video when got one
|
// flush video when got one
|
||||||
if ((err = muxer->flush_video(tsmc, frame)) != srs_success) {
|
if ((err = muxer->flush_video(tsmc)) != srs_success) {
|
||||||
return srs_error_wrap(err, "hls: flush video");
|
return srs_error_wrap(err, "hls: flush video");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1091,7 +1115,7 @@ srs_error_t SrsHlsController::reap_segment()
|
||||||
}
|
}
|
||||||
|
|
||||||
// segment open, flush video first.
|
// segment open, flush video first.
|
||||||
if ((err = muxer->flush_video(tsmc, NULL)) != srs_success) {
|
if ((err = muxer->flush_video(tsmc)) != srs_success) {
|
||||||
return srs_error_wrap(err, "hls: flush video");
|
return srs_error_wrap(err, "hls: flush video");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1351,9 +1375,9 @@ srs_error_t SrsHls::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma
|
||||||
if (format->video->frame_type == SrsVideoAvcFrameTypeVideoInfoFrame) {
|
if (format->video->frame_type == SrsVideoAvcFrameTypeVideoInfoFrame) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_assert(format->vcodec);
|
srs_assert(format->vcodec);
|
||||||
if (format->vcodec->id != SrsVideoCodecIdAVC) {
|
if (format->vcodec->id != SrsVideoCodecIdAVC && format->vcodec->id != SrsVideoCodecIdHEVC) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,8 @@ private:
|
||||||
private:
|
private:
|
||||||
// Latest audio codec, parsed from stream.
|
// Latest audio codec, parsed from stream.
|
||||||
SrsAudioCodecId latest_acodec_;
|
SrsAudioCodecId latest_acodec_;
|
||||||
|
// Latest audio codec, parsed from stream.
|
||||||
|
SrsVideoCodecId latest_vcodec_;
|
||||||
public:
|
public:
|
||||||
SrsHlsMuxer();
|
SrsHlsMuxer();
|
||||||
virtual ~SrsHlsMuxer();
|
virtual ~SrsHlsMuxer();
|
||||||
|
@ -172,6 +174,8 @@ public:
|
||||||
public:
|
public:
|
||||||
SrsAudioCodecId latest_acodec();
|
SrsAudioCodecId latest_acodec();
|
||||||
void set_latest_acodec(SrsAudioCodecId v);
|
void set_latest_acodec(SrsAudioCodecId v);
|
||||||
|
SrsVideoCodecId latest_vcodec();
|
||||||
|
void set_latest_vcodec(SrsVideoCodecId v);
|
||||||
public:
|
public:
|
||||||
// Initialize the hls muxer.
|
// Initialize the hls muxer.
|
||||||
virtual srs_error_t initialize();
|
virtual srs_error_t initialize();
|
||||||
|
@ -199,7 +203,7 @@ public:
|
||||||
// Whether current hls muxer is pure audio mode.
|
// Whether current hls muxer is pure audio mode.
|
||||||
virtual bool pure_audio();
|
virtual bool pure_audio();
|
||||||
virtual srs_error_t flush_audio(SrsTsMessageCache* cache);
|
virtual srs_error_t flush_audio(SrsTsMessageCache* cache);
|
||||||
virtual srs_error_t flush_video(SrsTsMessageCache* cache, SrsVideoFrame* frame);
|
virtual srs_error_t flush_video(SrsTsMessageCache* cache);
|
||||||
// Close segment(ts).
|
// Close segment(ts).
|
||||||
virtual srs_error_t segment_close();
|
virtual srs_error_t segment_close();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
#define VERSION_MAJOR 6
|
#define VERSION_MAJOR 6
|
||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_REVISION 10
|
#define VERSION_REVISION 11
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2678,7 +2678,7 @@ SrsTsContextWriter::SrsTsContextWriter(ISrsStreamWriter* w, SrsTsContext* c, Srs
|
||||||
context = c;
|
context = c;
|
||||||
|
|
||||||
acodec_ = ac;
|
acodec_ = ac;
|
||||||
vcodec = vc;
|
vcodec_ = vc;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsContextWriter::~SrsTsContextWriter()
|
SrsTsContextWriter::~SrsTsContextWriter()
|
||||||
|
@ -2692,8 +2692,8 @@ srs_error_t SrsTsContextWriter::write_audio(SrsTsMessage* audio)
|
||||||
srs_info("hls: write audio codec=%d/%d, pts=%" PRId64 ", dts=%" PRId64 ", size=%d",
|
srs_info("hls: write audio codec=%d/%d, pts=%" PRId64 ", dts=%" PRId64 ", size=%d",
|
||||||
acodec_, vcodec_, audio->pts, audio->dts, audio->PES_packet_length);
|
acodec_, vcodec_, audio->pts, audio->dts, audio->PES_packet_length);
|
||||||
|
|
||||||
if ((err = context->encode(writer, audio, vcodec, acodec_)) != srs_success) {
|
if ((err = context->encode(writer, audio, vcodec_, acodec_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: write audio acodec=%d, vcodec=%d", acodec_, vcodec);
|
return srs_error_wrap(err, "ts: write audio");
|
||||||
}
|
}
|
||||||
srs_info("hls encode audio ok");
|
srs_info("hls encode audio ok");
|
||||||
|
|
||||||
|
@ -2707,22 +2707,22 @@ srs_error_t SrsTsContextWriter::write_video(SrsTsMessage* video)
|
||||||
srs_info("hls: write video codec=%d/%d, pts=%" PRId64 ", dts=%" PRId64 ", size=%d",
|
srs_info("hls: write video codec=%d/%d, pts=%" PRId64 ", dts=%" PRId64 ", size=%d",
|
||||||
acodec_, vcodec_, video->pts, video->dts, video->PES_packet_length);
|
acodec_, vcodec_, video->pts, video->dts, video->PES_packet_length);
|
||||||
|
|
||||||
if ((err = context->encode(writer, video, vcodec, acodec_)) != srs_success) {
|
if ((err = context->encode(writer, video, vcodec_, acodec_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: write video acodec=%d, vcodec=%d", acodec_, vcodec);
|
return srs_error_wrap(err, "ts: write video");
|
||||||
}
|
}
|
||||||
srs_info("hls encode video ok");
|
srs_info("hls encode video ok");
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsVideoCodecId SrsTsContextWriter::video_codec()
|
SrsVideoCodecId SrsTsContextWriter::vcodec()
|
||||||
{
|
{
|
||||||
return vcodec;
|
return vcodec_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsTsContextWriter::update_video_codec(SrsVideoCodecId v)
|
void SrsTsContextWriter::set_vcodec(SrsVideoCodecId v)
|
||||||
{
|
{
|
||||||
vcodec = v;
|
vcodec_ = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsAudioCodecId SrsTsContextWriter::acodec()
|
SrsAudioCodecId SrsTsContextWriter::acodec()
|
||||||
|
@ -3293,7 +3293,7 @@ srs_error_t SrsTsTransmuxer::write_video(int64_t timestamp, char* data, int size
|
||||||
}
|
}
|
||||||
|
|
||||||
// The video codec might change during streaming.
|
// The video codec might change during streaming.
|
||||||
tscw->update_video_codec(format->vcodec->id);
|
tscw->set_vcodec(format->vcodec->id);
|
||||||
|
|
||||||
// ignore sequence header
|
// ignore sequence header
|
||||||
if (format->video->frame_type == SrsVideoAvcFrameTypeKeyFrame && format->video->avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
|
if (format->video->frame_type == SrsVideoAvcFrameTypeKeyFrame && format->video->avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
|
||||||
|
|
|
@ -1259,7 +1259,7 @@ class SrsTsContextWriter
|
||||||
private:
|
private:
|
||||||
// User must config the codec in right way.
|
// User must config the codec in right way.
|
||||||
// @see https://github.com/ossrs/srs/issues/301
|
// @see https://github.com/ossrs/srs/issues/301
|
||||||
SrsVideoCodecId vcodec;
|
SrsVideoCodecId vcodec_;
|
||||||
SrsAudioCodecId acodec_;
|
SrsAudioCodecId acodec_;
|
||||||
private:
|
private:
|
||||||
SrsTsContext* context;
|
SrsTsContext* context;
|
||||||
|
@ -1275,8 +1275,8 @@ public:
|
||||||
virtual srs_error_t write_video(SrsTsMessage* video);
|
virtual srs_error_t write_video(SrsTsMessage* video);
|
||||||
public:
|
public:
|
||||||
// Get or update the video codec of ts muxer.
|
// Get or update the video codec of ts muxer.
|
||||||
virtual SrsVideoCodecId video_codec();
|
virtual SrsVideoCodecId vcodec();
|
||||||
virtual void update_video_codec(SrsVideoCodecId v);
|
virtual void set_vcodec(SrsVideoCodecId v);
|
||||||
public:
|
public:
|
||||||
// Get and set the audio codec.
|
// Get and set the audio codec.
|
||||||
SrsAudioCodecId acodec();
|
SrsAudioCodecId acodec();
|
||||||
|
|
Loading…
Reference in a new issue