diff --git a/README.md b/README.md index f29cae3d3..5894a7bf5 100755 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ For previous versions, please read: ## V3 changes +* v3.0, 2019-12-29, For [#299][bug #299], increase dash segment size for avsync issue. 3.0.89 * v3.0, 2019-12-27, For [#299][bug #299], fix some bugs in dash, it works now. 3.0.88 * v3.0, 2019-12-27, For [#1544][bug #1544], fix memory leaking for complex error. 3.0.87 * v3.0, 2019-12-27, Add links for flv.js, hls.js and dash.js. diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index e706aed5c..1160877a4 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -965,14 +965,14 @@ vhost dash.srs.com { # Default: off enabled on; # The duration of segment in seconds. - # Default: 3 - dash_fragment 3; - # The period to update the MPD in seconds. # Default: 30 - dash_update_period 30; + dash_fragment 30; + # The period to update the MPD in seconds. + # Default: 150 + dash_update_period 150; # The depth of timeshift buffer in seconds. - # Default: 60 - dash_timeshift 60; + # Default: 300 + dash_timeshift 300; # The base/home dir/path for dash. # All init and segment files will write under this dir. dash_path ./objs/nginx/html; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 1a790627a..4a988dd2e 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -5810,7 +5810,7 @@ bool SrsConfig::get_dash_enabled(string vhost) srs_utime_t SrsConfig::get_dash_fragment(string vhost) { - static int DEFAULT = 3 * SRS_UTIME_SECONDS; + static int DEFAULT = 30 * SRS_UTIME_SECONDS; SrsConfDirective* conf = get_dash(vhost); if (!conf) { @@ -5827,7 +5827,7 @@ srs_utime_t SrsConfig::get_dash_fragment(string vhost) srs_utime_t SrsConfig::get_dash_update_period(string vhost) { - static srs_utime_t DEFAULT = 30 * SRS_UTIME_SECONDS; + static srs_utime_t DEFAULT = 150 * SRS_UTIME_SECONDS; SrsConfDirective* conf = get_dash(vhost); if (!conf) { @@ -5844,7 +5844,7 @@ srs_utime_t SrsConfig::get_dash_update_period(string vhost) srs_utime_t SrsConfig::get_dash_timeshift(string vhost) { - static srs_utime_t DEFAULT = 60 * SRS_UTIME_SECONDS; + static srs_utime_t DEFAULT = 300 * SRS_UTIME_SECONDS; SrsConfDirective* conf = get_dash(vhost); if (!conf) { diff --git a/trunk/src/app/srs_app_dash.cpp b/trunk/src/app/srs_app_dash.cpp index 08296a083..3288004f4 100644 --- a/trunk/src/app/srs_app_dash.cpp +++ b/trunk/src/app/srs_app_dash.cpp @@ -363,7 +363,18 @@ void SrsDashController::on_unpublish() { mpd->on_unpublish(); + srs_error_t err = srs_success; + + if ((err = vcurrent->reap(video_dts)) != srs_success) { + srs_warn("reap video err %s", srs_error_desc(err).c_str()); + srs_freep(err); + } srs_freep(vcurrent); + + if ((err = acurrent->reap(audio_dts)) != srs_success) { + srs_warn("reap audio err %s", srs_error_desc(err).c_str()); + srs_freep(err); + } srs_freep(acurrent); } diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 021b75c20..3b5a37f0f 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -27,7 +27,7 @@ // The version config. #define VERSION_MAJOR 3 #define VERSION_MINOR 0 -#define VERSION_REVISION 88 +#define VERSION_REVISION 89 // The macros generated by configure script. #include diff --git a/trunk/src/kernel/srs_kernel_mp4.cpp b/trunk/src/kernel/srs_kernel_mp4.cpp index fef9549ea..85459f0cc 100644 --- a/trunk/src/kernel/srs_kernel_mp4.cpp +++ b/trunk/src/kernel/srs_kernel_mp4.cpp @@ -41,6 +41,27 @@ using namespace std; #define SRS_MP4_BUF_SIZE 4096 +srs_error_t srs_mp4_write_box(ISrsWriter* writer, ISrsCodec* box) +{ + srs_error_t err = srs_success; + + int nb_data = box->nb_bytes(); + std::vector data(nb_data); + + SrsBuffer* buffer = new SrsBuffer(&data[0], nb_data); + SrsAutoFree(SrsBuffer, buffer); + + if ((err = box->encode(buffer)) != srs_success) { + return srs_error_wrap(err, "encode box"); + } + + if ((err = writer->write(&data[0], nb_data, NULL)) != srs_success) { + return srs_error_wrap(err, "write box"); + } + + return err; +} + stringstream& srs_padding(stringstream& ss, SrsMp4DumpContext dc, int tab = 4) { for (int i = 0; i < (int)dc.level; i++) { @@ -4587,7 +4608,7 @@ SrsMp4SegmentIndexBox::~SrsMp4SegmentIndexBox() int SrsMp4SegmentIndexBox::nb_header() { - return SrsMp4Box::nb_header() + 4+4+4 + (version? 4:8) + 4+4 + 12*entries.size(); + return SrsMp4Box::nb_header() + 4+4+4 + (!version? 8:16) + 4 + 12*entries.size(); } srs_error_t SrsMp4SegmentIndexBox::encode_header(SrsBuffer* buf) @@ -6041,18 +6062,24 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid) srs_error_t err = srs_success; // Write ftyp box. - SrsMp4FileTypeBox* ftyp = new SrsMp4FileTypeBox(); - SrsAutoFree(SrsMp4FileTypeBox, ftyp); if (true) { + SrsMp4FileTypeBox* ftyp = new SrsMp4FileTypeBox(); + SrsAutoFree(SrsMp4FileTypeBox, ftyp); + ftyp->major_brand = SrsMp4BoxBrandISO5; ftyp->minor_version = 512; ftyp->set_compatible_brands(SrsMp4BoxBrandISO6, SrsMp4BoxBrandMP41); + + if ((err = srs_mp4_write_box(writer, ftyp)) != srs_success) { + return srs_error_wrap(err, "write ftyp"); + } } // Write moov. - SrsMp4MovieBox* moov = new SrsMp4MovieBox(); - SrsAutoFree(SrsMp4MovieBox, moov); if (true) { + SrsMp4MovieBox* moov = new SrsMp4MovieBox(); + SrsAutoFree(SrsMp4MovieBox, moov); + SrsMp4MovieHeaderBox* mvhd = new SrsMp4MovieHeaderBox(); moov->set_mvhd(mvhd); @@ -6244,24 +6271,10 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid) trex->track_ID = tid; trex->default_sample_description_index = 1; } - } - - int nb_data = ftyp->nb_bytes() + moov->nb_bytes(); - uint8_t* data = new uint8_t[nb_data]; - SrsAutoFreeA(uint8_t, data); - - SrsBuffer* buffer = new SrsBuffer((char*)data, nb_data); - SrsAutoFree(SrsBuffer, buffer); - - if ((err = ftyp->encode(buffer)) != srs_success) { - return srs_error_wrap(err, "encode ftyp"); - } - if ((err = moov->encode(buffer)) != srs_success) { - return srs_error_wrap(err, "encode moov"); - } - - if ((err = writer->write(data, nb_data, NULL)) != srs_success) { - return srs_error_wrap(err, "write ftyp and moov"); + + if ((err = srs_mp4_write_box(writer, moov)) != srs_success) { + return srs_error_wrap(err, "write moov"); + } } return err; @@ -6275,6 +6288,7 @@ SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder() buffer = new SrsBuffer(); sequence_number = 0; decode_basetime = 0; + styp_bytes = 0; mdat_bytes = 0; } @@ -6301,19 +6315,11 @@ srs_error_t SrsMp4M2tsSegmentEncoder::initialize(ISrsWriter* w, uint32_t sequenc styp->major_brand = SrsMp4BoxBrandMSDH; styp->minor_version = 0; styp->set_compatible_brands(SrsMp4BoxBrandMSDH, SrsMp4BoxBrandMSIX); - - int nb_data = styp->nb_bytes(); - std::vector data(nb_data); - - SrsBuffer* buffer = new SrsBuffer(&data[0], nb_data); - SrsAutoFree(SrsBuffer, buffer); - - if ((err = styp->encode(buffer)) != srs_success) { - return srs_error_wrap(err, "encode styp"); - } - - // TODO: FIXME: Ensure write ok. - if ((err = writer->write(&data[0], nb_data, NULL)) != srs_success) { + + // Used for sidx to calcalute the referenced size. + styp_bytes = styp->nb_bytes(); + + if ((err = srs_mp4_write_box(writer, styp)) != srs_success) { return srs_error_wrap(err, "write styp"); } } @@ -6365,16 +6371,36 @@ srs_error_t SrsMp4M2tsSegmentEncoder::flush(uint64_t& dts) if (!nb_audios && !nb_videos) { return srs_error_new(ERROR_MP4_ILLEGAL_MOOF, "Missing audio and video track"); } - + + // Although the sidx is not required to start play DASH, but it's required for AV sync. + SrsMp4SegmentIndexBox* sidx = new SrsMp4SegmentIndexBox(); + SrsAutoFree(SrsMp4SegmentIndexBox, sidx); + if (true) { + sidx->version = 1; + sidx->reference_id = 1; + sidx->timescale = 1000; + sidx->earliest_presentation_time = uint64_t(decode_basetime / sidx->timescale); + + uint64_t duration = 0; + if (samples && !samples->samples.empty()) { + SrsMp4Sample* first = samples->samples[0]; + SrsMp4Sample* last = samples->samples[samples->samples.size() - 1]; + duration = srs_max(0, last->dts - first->dts); + } + + SrsMp4SegmentIndexEntry entry; + memset(&entry, 0, sizeof(entry)); + entry.subsegment_duration = duration; + entry.starts_with_SAP = 1; + sidx->entries.push_back(entry); + } + // Create a mdat box. // its payload will be writen by samples, // and we will update its header(size) when flush. SrsMp4MediaDataBox* mdat = new SrsMp4MediaDataBox(); SrsAutoFree(SrsMp4MediaDataBox, mdat); - // Although the sidx is not required to start play DASH, but it's required for AV sync. - // TODO: FIXME: Insert a sidx box. - // Write moof. if (true) { SrsMp4MovieFragmentBox* moof = new SrsMp4MovieFragmentBox(); @@ -6407,30 +6433,25 @@ srs_error_t SrsMp4M2tsSegmentEncoder::flush(uint64_t& dts) return srs_error_wrap(err, "write samples"); } - int nb_data = moof->nb_bytes(); // @remark Remember the data_offset of turn is size(moof)+header(mdat), not including styp or sidx. - trun->data_offset = (int32_t)(nb_data + mdat->sz_header()); - - uint8_t* data = new uint8_t[nb_data]; - SrsAutoFreeA(uint8_t, data); - - SrsBuffer* buffer = new SrsBuffer((char*)data, nb_data); - SrsAutoFree(SrsBuffer, buffer); - - if ((err = moof->encode(buffer)) != srs_success) { - return srs_error_wrap(err, "encode moof"); + int moof_bytes = moof->nb_bytes(); + trun->data_offset = (int32_t)(moof_bytes + mdat->sz_header()); + mdat->nb_data = (int)mdat_bytes; + + // Update the size of sidx. + SrsMp4SegmentIndexEntry* entry = &sidx->entries[0]; + entry->referenced_size = moof_bytes + mdat->nb_bytes(); + if ((err = srs_mp4_write_box(writer, sidx)) != srs_success) { + return srs_error_wrap(err, "write sidx"); } - - // TODO: FIXME: Ensure all bytes are writen. - if ((err = writer->write(data, nb_data, NULL)) != srs_success) { + + if ((err = srs_mp4_write_box(writer, moof)) != srs_success) { return srs_error_wrap(err, "write moof"); } } // Write mdat. if (true) { - mdat->nb_data = (int)mdat_bytes; - int nb_data = mdat->sz_header(); uint8_t* data = new uint8_t[nb_data]; SrsAutoFreeA(uint8_t, data); diff --git a/trunk/src/kernel/srs_kernel_mp4.hpp b/trunk/src/kernel/srs_kernel_mp4.hpp index c51e30ad0..0e52ff0cb 100644 --- a/trunk/src/kernel/srs_kernel_mp4.hpp +++ b/trunk/src/kernel/srs_kernel_mp4.hpp @@ -1835,7 +1835,7 @@ public: uint32_t reference_id; uint32_t timescale; uint64_t earliest_presentation_time; - uint32_t first_offset; + uint64_t first_offset; // TODO: FIXME: Should double check buffer. std::vector entries; public: @@ -2115,6 +2115,7 @@ private: private: uint32_t nb_audios; uint32_t nb_videos; + uint32_t styp_bytes; uint64_t mdat_bytes; SrsMp4SampleManager* samples; public: