mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 11:51:57 +00:00
for #299, srs http server support dash, flash request range in range or bytes.
This commit is contained in:
parent
1e26f54b5c
commit
e0ee8de2fb
5 changed files with 113 additions and 4 deletions
|
@ -133,6 +133,14 @@ http_server {
|
||||||
dir ./objs/nginx/html;
|
dir ./objs/nginx/html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
# Streamer sections
|
||||||
|
#############################################################################################
|
||||||
|
# the streamer cast stream from other protocol to SRS over RTMP.
|
||||||
|
# @see https://github.com/winlinvip/simple-rtmp-server/tree/develop#stream-architecture
|
||||||
|
streamer {
|
||||||
|
}
|
||||||
|
|
||||||
#############################################################################################
|
#############################################################################################
|
||||||
# RTMP/HTTP VHOST sections
|
# RTMP/HTTP VHOST sections
|
||||||
#############################################################################################
|
#############################################################################################
|
||||||
|
|
|
@ -317,6 +317,40 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
|
||||||
}
|
}
|
||||||
|
|
||||||
return serve_flv_stream(w, r, fullpath, offset);
|
return serve_flv_stream(w, r, fullpath, offset);
|
||||||
|
} else if (srs_string_ends_with(fullpath, ".mp4")) {
|
||||||
|
// for flash to request mp4 range in query string.
|
||||||
|
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
|
||||||
|
std::string range = r->query_get("range");
|
||||||
|
// or, use bytes to request range,
|
||||||
|
// for example, http://dashas.castlabs.com/demo/try.html
|
||||||
|
if (range.empty()) {
|
||||||
|
range = r->query_get("bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
// rollback to serve whole file.
|
||||||
|
size_t pos = string::npos;
|
||||||
|
if (range.empty() || (pos = range.find("-")) == string::npos) {
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the start in query string
|
||||||
|
int start = 0;
|
||||||
|
if (pos > 0) {
|
||||||
|
start = ::atoi(range.substr(0, pos).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse end in query string.
|
||||||
|
int end = -1;
|
||||||
|
if (pos < range.length() - 1) {
|
||||||
|
end = ::atoi(range.substr(pos + 1).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalid param, serve as whole mp4 file.
|
||||||
|
if (start < 0 || (end != -1 && start > end)) {
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serve_mp4_range(w, r, fullpath, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// serve common static file.
|
// serve common static file.
|
||||||
|
@ -377,7 +411,7 @@ int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_mime.find(ext) == _mime.end()) {
|
if (_mime.find(ext) == _mime.end()) {
|
||||||
w->header()->set_content_type("text/html;charset=utf-8");
|
w->header()->set_content_type("application/octet-stream");
|
||||||
} else {
|
} else {
|
||||||
w->header()->set_content_type(_mime[ext]);
|
w->header()->set_content_type(_mime[ext]);
|
||||||
}
|
}
|
||||||
|
@ -398,6 +432,11 @@ int SrsGoHttpFileServer::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMe
|
||||||
return serve_file(w, r, fullpath);
|
return serve_file(w, r, fullpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsGoHttpFileServer::serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
||||||
|
{
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size)
|
int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
@ -407,7 +446,8 @@ int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, Sr
|
||||||
|
|
||||||
while (left > 0) {
|
while (left > 0) {
|
||||||
ssize_t nread = -1;
|
ssize_t nread = -1;
|
||||||
if ((ret = fs->read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) {
|
int max_read = srs_min(left, __SRS_HTTP_TS_SEND_BUFFER_SIZE);
|
||||||
|
if ((ret = fs->read(buf, max_read, &nread)) != ERROR_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,13 +213,20 @@ public:
|
||||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* serve the file by specified path.
|
* serve the file by specified path
|
||||||
*/
|
*/
|
||||||
virtual int serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
virtual int serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||||
/**
|
/**
|
||||||
* when access flv file with start=xxx.
|
* when access flv file with x.flv?start=xxx
|
||||||
*/
|
*/
|
||||||
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||||
|
/**
|
||||||
|
* when access mp4 file with x.mp4?range=start-end
|
||||||
|
* @param start the start offset in bytes.
|
||||||
|
* @param end the end offset in bytes. -1 to end of file.
|
||||||
|
* @remark response data in [start, end].
|
||||||
|
*/
|
||||||
|
virtual int serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* copy the fs to response writer in size bytes.
|
* copy the fs to response writer in size bytes.
|
||||||
|
|
|
@ -141,6 +141,59 @@ int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsVodStream::serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
srs_assert(start >= 0);
|
||||||
|
srs_assert(end == -1 || end >= 0);
|
||||||
|
|
||||||
|
SrsFileReader fs;
|
||||||
|
|
||||||
|
// open flv file
|
||||||
|
if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse -1 to whole file.
|
||||||
|
if (end == -1) {
|
||||||
|
end = fs.filesize();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end > fs.filesize() || start > end) {
|
||||||
|
ret = ERROR_HTTP_REMUX_OFFSET_OVERFLOW;
|
||||||
|
srs_warn("http mp4 streaming %s overflow. size=%"PRId64", offset=%d, ret=%d",
|
||||||
|
fullpath.c_str(), fs.filesize(), start, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// seek to data offset, [start, end] for range.
|
||||||
|
int64_t left = end - start + 1;
|
||||||
|
|
||||||
|
// write http header for ts.
|
||||||
|
w->header()->set_content_length(left);
|
||||||
|
w->header()->set_content_type("video/mp4");
|
||||||
|
|
||||||
|
// status code 206 to make dash.as happy.
|
||||||
|
w->write_header(SRS_CONSTS_HTTP_PartialContent);
|
||||||
|
|
||||||
|
// response the content range header.
|
||||||
|
std::stringstream content_range;
|
||||||
|
content_range << "bytes " << start << "-" << end << "/" << fs.filesize();
|
||||||
|
w->header()->set("Content-Range", content_range.str());
|
||||||
|
|
||||||
|
// write body.
|
||||||
|
fs.lseek(start);
|
||||||
|
|
||||||
|
// send data
|
||||||
|
if ((ret = copy(w, &fs, r, left)) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("read mp4=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
SrsStreamCache::SrsStreamCache(SrsSource* s, SrsRequest* r)
|
SrsStreamCache::SrsStreamCache(SrsSource* s, SrsRequest* r)
|
||||||
{
|
{
|
||||||
req = r->copy();
|
req = r->copy();
|
||||||
|
|
|
@ -66,6 +66,7 @@ public:
|
||||||
virtual ~SrsVodStream();
|
virtual ~SrsVodStream();
|
||||||
protected:
|
protected:
|
||||||
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||||
|
virtual int serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue