For #299, increase dash segment size for avsync issue. 3.0.89

pull/1568/head
winlin 5 years ago
parent d11a7b2e00
commit 8a28a11648

@ -146,6 +146,7 @@ For previous versions, please read:
## V3 changes ## 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 [#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, 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. * v3.0, 2019-12-27, Add links for flv.js, hls.js and dash.js.

@ -965,14 +965,14 @@ vhost dash.srs.com {
# Default: off # Default: off
enabled on; enabled on;
# The duration of segment in seconds. # The duration of segment in seconds.
# Default: 3
dash_fragment 3;
# The period to update the MPD in seconds.
# Default: 30 # 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. # The depth of timeshift buffer in seconds.
# Default: 60 # Default: 300
dash_timeshift 60; dash_timeshift 300;
# The base/home dir/path for dash. # The base/home dir/path for dash.
# All init and segment files will write under this dir. # All init and segment files will write under this dir.
dash_path ./objs/nginx/html; dash_path ./objs/nginx/html;

@ -5810,7 +5810,7 @@ bool SrsConfig::get_dash_enabled(string vhost)
srs_utime_t SrsConfig::get_dash_fragment(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); SrsConfDirective* conf = get_dash(vhost);
if (!conf) { 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) 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); SrsConfDirective* conf = get_dash(vhost);
if (!conf) { 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) 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); SrsConfDirective* conf = get_dash(vhost);
if (!conf) { if (!conf) {

@ -363,7 +363,18 @@ void SrsDashController::on_unpublish()
{ {
mpd->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); 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); srs_freep(acurrent);
} }

@ -27,7 +27,7 @@
// The version config. // The version config.
#define VERSION_MAJOR 3 #define VERSION_MAJOR 3
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_REVISION 88 #define VERSION_REVISION 89
// The macros generated by configure script. // The macros generated by configure script.
#include <srs_auto_headers.hpp> #include <srs_auto_headers.hpp>

@ -41,6 +41,27 @@ using namespace std;
#define SRS_MP4_BUF_SIZE 4096 #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<char> 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) stringstream& srs_padding(stringstream& ss, SrsMp4DumpContext dc, int tab = 4)
{ {
for (int i = 0; i < (int)dc.level; i++) { for (int i = 0; i < (int)dc.level; i++) {
@ -4587,7 +4608,7 @@ SrsMp4SegmentIndexBox::~SrsMp4SegmentIndexBox()
int SrsMp4SegmentIndexBox::nb_header() 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) 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; srs_error_t err = srs_success;
// Write ftyp box. // Write ftyp box.
if (true) {
SrsMp4FileTypeBox* ftyp = new SrsMp4FileTypeBox(); SrsMp4FileTypeBox* ftyp = new SrsMp4FileTypeBox();
SrsAutoFree(SrsMp4FileTypeBox, ftyp); SrsAutoFree(SrsMp4FileTypeBox, ftyp);
if (true) {
ftyp->major_brand = SrsMp4BoxBrandISO5; ftyp->major_brand = SrsMp4BoxBrandISO5;
ftyp->minor_version = 512; ftyp->minor_version = 512;
ftyp->set_compatible_brands(SrsMp4BoxBrandISO6, SrsMp4BoxBrandMP41); 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. // Write moov.
if (true) {
SrsMp4MovieBox* moov = new SrsMp4MovieBox(); SrsMp4MovieBox* moov = new SrsMp4MovieBox();
SrsAutoFree(SrsMp4MovieBox, moov); SrsAutoFree(SrsMp4MovieBox, moov);
if (true) {
SrsMp4MovieHeaderBox* mvhd = new SrsMp4MovieHeaderBox(); SrsMp4MovieHeaderBox* mvhd = new SrsMp4MovieHeaderBox();
moov->set_mvhd(mvhd); moov->set_mvhd(mvhd);
@ -6244,24 +6271,10 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
trex->track_ID = tid; trex->track_ID = tid;
trex->default_sample_description_index = 1; trex->default_sample_description_index = 1;
} }
}
int nb_data = ftyp->nb_bytes() + moov->nb_bytes(); if ((err = srs_mp4_write_box(writer, moov)) != srs_success) {
uint8_t* data = new uint8_t[nb_data]; return srs_error_wrap(err, "write moov");
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");
} }
return err; return err;
@ -6275,6 +6288,7 @@ SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
buffer = new SrsBuffer(); buffer = new SrsBuffer();
sequence_number = 0; sequence_number = 0;
decode_basetime = 0; decode_basetime = 0;
styp_bytes = 0;
mdat_bytes = 0; mdat_bytes = 0;
} }
@ -6302,18 +6316,10 @@ srs_error_t SrsMp4M2tsSegmentEncoder::initialize(ISrsWriter* w, uint32_t sequenc
styp->minor_version = 0; styp->minor_version = 0;
styp->set_compatible_brands(SrsMp4BoxBrandMSDH, SrsMp4BoxBrandMSIX); styp->set_compatible_brands(SrsMp4BoxBrandMSDH, SrsMp4BoxBrandMSIX);
int nb_data = styp->nb_bytes(); // Used for sidx to calcalute the referenced size.
std::vector<char> data(nb_data); styp_bytes = styp->nb_bytes();
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 = srs_mp4_write_box(writer, styp)) != srs_success) {
if ((err = writer->write(&data[0], nb_data, NULL)) != srs_success) {
return srs_error_wrap(err, "write styp"); return srs_error_wrap(err, "write styp");
} }
} }
@ -6366,15 +6372,35 @@ srs_error_t SrsMp4M2tsSegmentEncoder::flush(uint64_t& dts)
return srs_error_new(ERROR_MP4_ILLEGAL_MOOF, "Missing audio and video track"); 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. // Create a mdat box.
// its payload will be writen by samples, // its payload will be writen by samples,
// and we will update its header(size) when flush. // and we will update its header(size) when flush.
SrsMp4MediaDataBox* mdat = new SrsMp4MediaDataBox(); SrsMp4MediaDataBox* mdat = new SrsMp4MediaDataBox();
SrsAutoFree(SrsMp4MediaDataBox, mdat); 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. // Write moof.
if (true) { if (true) {
SrsMp4MovieFragmentBox* moof = new SrsMp4MovieFragmentBox(); SrsMp4MovieFragmentBox* moof = new SrsMp4MovieFragmentBox();
@ -6407,30 +6433,25 @@ srs_error_t SrsMp4M2tsSegmentEncoder::flush(uint64_t& dts)
return srs_error_wrap(err, "write samples"); 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. // @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()); int moof_bytes = moof->nb_bytes();
trun->data_offset = (int32_t)(moof_bytes + mdat->sz_header());
uint8_t* data = new uint8_t[nb_data]; mdat->nb_data = (int)mdat_bytes;
SrsAutoFreeA(uint8_t, data);
SrsBuffer* buffer = new SrsBuffer((char*)data, nb_data);
SrsAutoFree(SrsBuffer, buffer);
if ((err = moof->encode(buffer)) != srs_success) { // Update the size of sidx.
return srs_error_wrap(err, "encode moof"); 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 = srs_mp4_write_box(writer, moof)) != srs_success) {
if ((err = writer->write(data, nb_data, NULL)) != srs_success) {
return srs_error_wrap(err, "write moof"); return srs_error_wrap(err, "write moof");
} }
} }
// Write mdat. // Write mdat.
if (true) { if (true) {
mdat->nb_data = (int)mdat_bytes;
int nb_data = mdat->sz_header(); int nb_data = mdat->sz_header();
uint8_t* data = new uint8_t[nb_data]; uint8_t* data = new uint8_t[nb_data];
SrsAutoFreeA(uint8_t, data); SrsAutoFreeA(uint8_t, data);

@ -1835,7 +1835,7 @@ public:
uint32_t reference_id; uint32_t reference_id;
uint32_t timescale; uint32_t timescale;
uint64_t earliest_presentation_time; uint64_t earliest_presentation_time;
uint32_t first_offset; uint64_t first_offset;
// TODO: FIXME: Should double check buffer. // TODO: FIXME: Should double check buffer.
std::vector<SrsMp4SegmentIndexEntry> entries; std::vector<SrsMp4SegmentIndexEntry> entries;
public: public:
@ -2115,6 +2115,7 @@ private:
private: private:
uint32_t nb_audios; uint32_t nb_audios;
uint32_t nb_videos; uint32_t nb_videos;
uint32_t styp_bytes;
uint64_t mdat_bytes; uint64_t mdat_bytes;
SrsMp4SampleManager* samples; SrsMp4SampleManager* samples;
public: public:

Loading…
Cancel
Save