refine code for #277, extract the flv vod stream.

pull/133/head
winlin 10 years ago
parent e71bc0cbc5
commit c695a8fcbd

@ -38,7 +38,6 @@ using namespace std;
#include <srs_kernel_utility.hpp> #include <srs_kernel_utility.hpp>
#include <srs_protocol_buffer.hpp> #include <srs_protocol_buffer.hpp>
#include <srs_kernel_file.hpp> #include <srs_kernel_file.hpp>
#include <srs_kernel_flv.hpp>
#include <srs_core_autofree.hpp> #include <srs_core_autofree.hpp>
#define SRS_DEFAULT_HTTP_PORT 80 #define SRS_DEFAULT_HTTP_PORT 80
@ -289,23 +288,23 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) { if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) {
std::string start = r->query_get("start"); std::string start = r->query_get("start");
if (start.empty()) { if (start.empty()) {
return serve_file(fullpath, w, r); return serve_file(w, r, fullpath);
} }
int offset = ::atoi(start.c_str()); int offset = ::atoi(start.c_str());
if (offset <= 0) { if (offset <= 0) {
return serve_file(fullpath, w, r); return serve_file(w, r, fullpath);
} }
return serve_flv_stream(fullpath, w, r, offset); return serve_flv_stream(w, r, fullpath, offset);
} else { } else {
return serve_file(fullpath, w, r); return serve_file(w, r, fullpath);
} }
return ret; return ret;
} }
int SrsGoHttpFileServer::serve_file(string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -345,110 +344,35 @@ int SrsGoHttpFileServer::serve_file(string fullpath, ISrsGoHttpResponseWriter* w
// write body. // write body.
int64_t left = length; int64_t left = length;
char* buf = r->http_ts_send_buffer(); if ((ret = copy(&fs, w, r, left)) != ERROR_SUCCESS) {
srs_warn("read file=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
while (left > 0) { return ret;
ssize_t nread = -1;
if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) {
srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret);
break;
}
left -= nread;
if ((ret = w->write(buf, nread)) != ERROR_SUCCESS) {
break;
}
} }
return ret; return ret;
} }
int SrsGoHttpFileServer::serve_flv_stream(string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int offset) int SrsGoHttpFileServer::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
{ {
int ret = ERROR_SUCCESS; return serve_file(w, r, fullpath);
}
SrsFileReader fs;
// open flv file
if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {
return ret;
}
if (offset > fs.filesize()) {
ret = ERROR_HTTP_FLV_OFFSET_OVERFLOW;
srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d",
fullpath.c_str(), fs.filesize(), offset, ret);
return ret;
}
SrsFlvVodStreamDecoder ffd;
// open fast decoder
if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) {
return ret;
}
// save header, send later.
char flv_header[13];
// send flv header
if ((ret = ffd.read_header_ext(flv_header)) != ERROR_SUCCESS) {
return ret;
}
// save sequence header, send later
char* sh_data = NULL;
int sh_size = 0;
if (true) {
// send sequence header
int64_t start = 0;
if ((ret = ffd.read_sequence_header_summary(&start, &sh_size)) != ERROR_SUCCESS) {
return ret;
}
if (sh_size <= 0) {
ret = ERROR_HTTP_FLV_SEQUENCE_HEADER;
srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret);
return ret;
}
}
sh_data = new char[sh_size];
SrsAutoFree(char, sh_data);
if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) {
return ret;
}
// seek to data offset
int64_t left = fs.filesize() - offset;
// write http header for ts. int SrsGoHttpFileServer::copy(SrsFileReader* fs, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int size)
w->header()->set_content_length((int)(sizeof(flv_header) + sh_size + left)); {
w->header()->set_content_type("video/x-flv"); int ret = ERROR_SUCCESS;
// write flv header and sequence header.
if ((ret = w->write(flv_header, sizeof(flv_header))) != ERROR_SUCCESS) {
return ret;
}
if (sh_size > 0 && (ret = w->write(sh_data, sh_size)) != ERROR_SUCCESS) {
return ret;
}
// write body. int left = size;
char* buf = r->http_ts_send_buffer(); char* buf = r->http_ts_send_buffer();
if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) {
return ret;
}
// send data
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) { if ((ret = fs->read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) {
return ret; break;
} }
left -= nread; left -= nread;
if ((ret = w->write(buf, nread)) != ERROR_SUCCESS) { if ((ret = w->write(buf, nread)) != ERROR_SUCCESS) {
return ret; break;
} }
} }

@ -40,12 +40,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_app_st.hpp> #include <srs_app_st.hpp>
class SrsSimpleBuffer;
class SrsRequest; class SrsRequest;
class SrsStSocket; class SrsStSocket;
class SrsHttpUri; class SrsHttpUri;
class SrsHttpMessage; class SrsHttpMessage;
class SrsHttpHandler; class SrsFileReader;
class SrsSimpleBuffer;
class ISrsGoHttpResponseWriter; class ISrsGoHttpResponseWriter;
// http specification // http specification
@ -197,16 +197,27 @@ public:
// http.Handle("/", SrsGoHttpFileServer("static-dir")) // http.Handle("/", SrsGoHttpFileServer("static-dir"))
class SrsGoHttpFileServer : public ISrsGoHttpHandler class SrsGoHttpFileServer : public ISrsGoHttpHandler
{ {
private: protected:
std::string dir; std::string dir;
public: public:
SrsGoHttpFileServer(std::string root_dir); SrsGoHttpFileServer(std::string root_dir);
virtual ~SrsGoHttpFileServer(); virtual ~SrsGoHttpFileServer();
public: public:
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
private: protected:
virtual int serve_file(std::string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); /**
virtual int serve_flv_stream(std::string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int offset); * serve the file by specified path.
*/
virtual int serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
/**
* when access flv file with start=xxx.
*/
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
protected:
/**
* copy the fs to response writer in size bytes.
*/
virtual int copy(SrsFileReader* fs, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int size);
}; };
// the mux entry for server mux. // the mux entry for server mux.

@ -39,6 +39,101 @@ using namespace std;
#include <srs_core_autofree.hpp> #include <srs_core_autofree.hpp>
#include <srs_app_config.hpp> #include <srs_app_config.hpp>
#include <srs_kernel_utility.hpp> #include <srs_kernel_utility.hpp>
#include <srs_kernel_file.hpp>
#include <srs_kernel_flv.hpp>
SrsVodStream::SrsVodStream(string root_dir)
: SrsGoHttpFileServer(root_dir)
{
}
SrsVodStream::~SrsVodStream()
{
}
int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
{
int ret = ERROR_SUCCESS;
SrsFileReader fs;
// open flv file
if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {
return ret;
}
if (offset > fs.filesize()) {
ret = ERROR_HTTP_FLV_OFFSET_OVERFLOW;
srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d",
fullpath.c_str(), fs.filesize(), offset, ret);
return ret;
}
SrsFlvVodStreamDecoder ffd;
// open fast decoder
if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) {
return ret;
}
// save header, send later.
char flv_header[13];
// send flv header
if ((ret = ffd.read_header_ext(flv_header)) != ERROR_SUCCESS) {
return ret;
}
// save sequence header, send later
char* sh_data = NULL;
int sh_size = 0;
if (true) {
// send sequence header
int64_t start = 0;
if ((ret = ffd.read_sequence_header_summary(&start, &sh_size)) != ERROR_SUCCESS) {
return ret;
}
if (sh_size <= 0) {
ret = ERROR_HTTP_FLV_SEQUENCE_HEADER;
srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret);
return ret;
}
}
sh_data = new char[sh_size];
SrsAutoFree(char, sh_data);
if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) {
return ret;
}
// seek to data offset
int64_t left = fs.filesize() - offset;
// write http header for ts.
w->header()->set_content_length((int)(sizeof(flv_header) + sh_size + left));
w->header()->set_content_type("video/x-flv");
// write flv header and sequence header.
if ((ret = w->write(flv_header, sizeof(flv_header))) != ERROR_SUCCESS) {
return ret;
}
if (sh_size > 0 && (ret = w->write(sh_data, sh_size)) != ERROR_SUCCESS) {
return ret;
}
// write body.
if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) {
return ret;
}
// send data
if ((ret = copy(&fs, w, r, left)) != ERROR_SUCCESS) {
srs_warn("read flv=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
return ret;
}
return ret;
}
SrsHttpServer::SrsHttpServer() SrsHttpServer::SrsHttpServer()
{ {
@ -71,7 +166,7 @@ int SrsHttpServer::initialize()
std::string mount = _srs_config->get_vhost_http_mount(vhost); std::string mount = _srs_config->get_vhost_http_mount(vhost);
std::string dir = _srs_config->get_vhost_http_dir(vhost); std::string dir = _srs_config->get_vhost_http_dir(vhost);
if ((ret = mux.handle(mount, new SrsGoHttpFileServer(dir))) != ERROR_SUCCESS) { if ((ret = mux.handle(mount, new SrsVodStream(dir))) != ERROR_SUCCESS) {
srs_error("http: mount dir=%s for vhost=%s failed. ret=%d", dir.c_str(), vhost.c_str(), ret); srs_error("http: mount dir=%s for vhost=%s failed. ret=%d", dir.c_str(), vhost.c_str(), ret);
return ret; return ret;
} }
@ -84,7 +179,7 @@ int SrsHttpServer::initialize()
if (!default_root_exists) { if (!default_root_exists) {
// add root // add root
std::string dir = _srs_config->get_http_stream_dir(); std::string dir = _srs_config->get_http_stream_dir();
if ((ret = mux.handle("/", new SrsGoHttpFileServer(dir))) != ERROR_SUCCESS) { if ((ret = mux.handle("/", new SrsVodStream(dir))) != ERROR_SUCCESS) {
srs_error("http: mount root dir=%s failed. ret=%d", dir.c_str(), ret); srs_error("http: mount root dir=%s failed. ret=%d", dir.c_str(), ret);
return ret; return ret;
} }

@ -41,7 +41,21 @@ class SrsHttpParser;
class SrsHttpMessage; class SrsHttpMessage;
class SrsHttpHandler; class SrsHttpHandler;
// for http server. /**
* the flv vod stream supports flv?start=offset-bytes.
* for example, http://server/file.flv?start=10240
* server will write flv header and sequence header,
* then seek(10240) and response flv tag data.
*/
class SrsVodStream : public SrsGoHttpFileServer
{
public:
SrsVodStream(std::string root_dir);
virtual ~SrsVodStream();
protected:
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
};
class SrsHttpServer class SrsHttpServer
{ {
public: public:

Loading…
Cancel
Save