mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
HLS: parse exist m3u8 when stream publish.
This commit is contained in:
parent
d6cbd277cc
commit
91b9228569
1 changed files with 135 additions and 1 deletions
|
@ -392,7 +392,8 @@ srs_error_t SrsHlsMuxer::restore_stream()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_trace("hls: restore stream m3u8=%s, m3u8_url=%s", m3u8.c_str(), m3u8_url.c_str());
|
srs_trace("hls: restore stream m3u8=%s, m3u8_url=%s, hls_path=%s",
|
||||||
|
m3u8.c_str(), m3u8_url.c_str(), hls_path.c_str());
|
||||||
|
|
||||||
// read m3u8
|
// read m3u8
|
||||||
SrsFileReader fr;
|
SrsFileReader fr;
|
||||||
|
@ -408,7 +409,140 @@ srs_error_t SrsHlsMuxer::restore_stream()
|
||||||
}
|
}
|
||||||
fr.close();
|
fr.close();
|
||||||
|
|
||||||
|
std::string body = fbuf;
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
|
if (body.empty()) {
|
||||||
|
return srs_error_wrap(err, "read empty m3u8");
|
||||||
|
}
|
||||||
|
|
||||||
|
int sequence_num = 0;
|
||||||
|
srs_utime_t max_target_duration = 0;
|
||||||
|
bool discon = false;
|
||||||
|
|
||||||
|
std::string ptl;
|
||||||
|
while (!body.empty()) {
|
||||||
|
size_t pos = string::npos;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
if ((pos = body.find("\n")) != string::npos) {
|
||||||
|
line = body.substr(0, pos);
|
||||||
|
body = body.substr(pos + 1);
|
||||||
|
} else {
|
||||||
|
line = body;
|
||||||
|
body = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
line = srs_string_replace(line, "\r", "");
|
||||||
|
line = srs_string_replace(line, " ", "");
|
||||||
|
|
||||||
|
// #EXT-X-VERSION:3
|
||||||
|
// the version must be 3.0
|
||||||
|
if (srs_string_starts_with(line, "#EXT-X-VERSION:")) {
|
||||||
|
if (!srs_string_ends_with(line, ":3")) {
|
||||||
|
srs_warn("m3u8 3.0 required, actual is %s", line.c_str());
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
// the playlist type, vod or nothing.
|
||||||
|
if (srs_string_starts_with(line, "#EXT-X-PLAYLIST-TYPE:")) {
|
||||||
|
ptl = line;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #EXT-X-MEDIA-SEQUENCE:4294967295
|
||||||
|
// the media sequence no.
|
||||||
|
if (srs_string_starts_with(line, "#EXT-X-MEDIA-SEQUENCE:")) {
|
||||||
|
sequence_num = ::atof(line.substr(string("#EXT-X-MEDIA-SEQUENCE:").length()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// #EXT-X-TARGETDURATION:12
|
||||||
|
// the target duration is required.
|
||||||
|
if (srs_string_starts_with(line, "#EXT-X-TARGETDURATION:")) {
|
||||||
|
max_target_duration = ::atof(line.substr(string("#EXT-X-TARGETDURATION:").length()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// #EXT-X-DISCONTINUITY
|
||||||
|
// the discontinuity tag.
|
||||||
|
if (srs_string_starts_with(line, "#EXT-X-DISCONTINUITY")) {
|
||||||
|
discon = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #EXT-X-ENDLIST
|
||||||
|
// parse completed.
|
||||||
|
if (line == "#EXT-X-ENDLIST") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #EXTINF:11.401,
|
||||||
|
// livestream-5.ts
|
||||||
|
// parse each ts entry, expect current line is inf.
|
||||||
|
if (!srs_string_starts_with(line, "#EXTINF:")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect next line is url.
|
||||||
|
std::string ts_url;
|
||||||
|
if ((pos = body.find("\n")) != string::npos) {
|
||||||
|
ts_url = body.substr(0, pos);
|
||||||
|
body = body.substr(pos + 1);
|
||||||
|
} else {
|
||||||
|
srs_warn("ts entry unexpected eof, inf=%s", line.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the ts duration.
|
||||||
|
line = line.substr(string("#EXTINF:").length());
|
||||||
|
if ((pos = line.find(",")) != string::npos) {
|
||||||
|
line = line.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
double ts_duration = ::atof(line.c_str());
|
||||||
|
|
||||||
|
// load the default acodec from config.
|
||||||
|
SrsAudioCodecId default_acodec = SrsAudioCodecIdAAC;
|
||||||
|
if (true) {
|
||||||
|
std::string default_acodec_str = _srs_config->get_hls_acodec(req->vhost);
|
||||||
|
if (default_acodec_str == "mp3") {
|
||||||
|
default_acodec = SrsAudioCodecIdMP3;
|
||||||
|
} else if (default_acodec_str == "aac") {
|
||||||
|
default_acodec = SrsAudioCodecIdAAC;
|
||||||
|
} else if (default_acodec_str == "an") {
|
||||||
|
default_acodec = SrsAudioCodecIdDisabled;
|
||||||
|
} else {
|
||||||
|
srs_warn("hls: use aac for other codec=%s", default_acodec_str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the default vcodec from config.
|
||||||
|
SrsVideoCodecId default_vcodec = SrsVideoCodecIdAVC;
|
||||||
|
if (true) {
|
||||||
|
std::string default_vcodec_str = _srs_config->get_hls_vcodec(req->vhost);
|
||||||
|
if (default_vcodec_str == "h264") {
|
||||||
|
default_vcodec = SrsVideoCodecIdAVC;
|
||||||
|
} else if (default_vcodec_str == "vn") {
|
||||||
|
default_vcodec = SrsVideoCodecIdDisabled;
|
||||||
|
} else {
|
||||||
|
srs_warn("hls: use h264 for other codec=%s", default_vcodec_str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new segment.
|
||||||
|
SrsHlsSegment* seg = new SrsHlsSegment(context, default_acodec, default_vcodec, writer);
|
||||||
|
seg->sequence_no = sequence_num++;
|
||||||
|
seg->set_path(hls_path + "/" + req->app + "/" + ts_url);
|
||||||
|
seg->uri = ts_url;
|
||||||
|
seg->set_sequence_header(discon);
|
||||||
|
|
||||||
|
seg->append(0);
|
||||||
|
seg->append(ts_duration * 1000);
|
||||||
|
|
||||||
|
segments->append(seg);
|
||||||
|
|
||||||
|
discon = false;
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue