winlin

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

@@ -38,7 +38,6 @@ using namespace std; @@ -38,7 +38,6 @@ using namespace std;
38 #include <srs_kernel_utility.hpp> 38 #include <srs_kernel_utility.hpp>
39 #include <srs_protocol_buffer.hpp> 39 #include <srs_protocol_buffer.hpp>
40 #include <srs_kernel_file.hpp> 40 #include <srs_kernel_file.hpp>
41 -#include <srs_kernel_flv.hpp>  
42 #include <srs_core_autofree.hpp> 41 #include <srs_core_autofree.hpp>
43 42
44 #define SRS_DEFAULT_HTTP_PORT 80 43 #define SRS_DEFAULT_HTTP_PORT 80
@@ -289,23 +288,23 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* @@ -289,23 +288,23 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
289 if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) { 288 if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) {
290 std::string start = r->query_get("start"); 289 std::string start = r->query_get("start");
291 if (start.empty()) { 290 if (start.empty()) {
292 - return serve_file(fullpath, w, r); 291 + return serve_file(w, r, fullpath);
293 } 292 }
294 293
295 int offset = ::atoi(start.c_str()); 294 int offset = ::atoi(start.c_str());
296 if (offset <= 0) { 295 if (offset <= 0) {
297 - return serve_file(fullpath, w, r); 296 + return serve_file(w, r, fullpath);
298 } 297 }
299 298
300 - return serve_flv_stream(fullpath, w, r, offset); 299 + return serve_flv_stream(w, r, fullpath, offset);
301 } else { 300 } else {
302 - return serve_file(fullpath, w, r); 301 + return serve_file(w, r, fullpath);
303 } 302 }
304 303
305 return ret; 304 return ret;
306 } 305 }
307 306
308 -int SrsGoHttpFileServer::serve_file(string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) 307 +int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
309 { 308 {
310 int ret = ERROR_SUCCESS; 309 int ret = ERROR_SUCCESS;
311 310
@@ -345,110 +344,35 @@ int SrsGoHttpFileServer::serve_file(string fullpath, ISrsGoHttpResponseWriter* w @@ -345,110 +344,35 @@ int SrsGoHttpFileServer::serve_file(string fullpath, ISrsGoHttpResponseWriter* w
345 344
346 // write body. 345 // write body.
347 int64_t left = length; 346 int64_t left = length;
348 - char* buf = r->http_ts_send_buffer();  
349 -  
350 - while (left > 0) {  
351 - ssize_t nread = -1;  
352 - if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) {  
353 - srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret);  
354 - break;  
355 - }  
356 -  
357 - left -= nread;  
358 - if ((ret = w->write(buf, nread)) != ERROR_SUCCESS) {  
359 - break;  
360 - } 347 + if ((ret = copy(&fs, w, r, left)) != ERROR_SUCCESS) {
  348 + srs_warn("read file=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
  349 + return ret;
361 } 350 }
362 351
363 return ret; 352 return ret;
364 } 353 }
365 354
366 -int SrsGoHttpFileServer::serve_flv_stream(string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int offset) 355 +int SrsGoHttpFileServer::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
367 { 356 {
368 - int ret = ERROR_SUCCESS;  
369 -  
370 - SrsFileReader fs;  
371 -  
372 - // open flv file  
373 - if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {  
374 - return ret;  
375 - }  
376 -  
377 - if (offset > fs.filesize()) {  
378 - ret = ERROR_HTTP_FLV_OFFSET_OVERFLOW;  
379 - srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d",  
380 - fullpath.c_str(), fs.filesize(), offset, ret);  
381 - return ret;  
382 - }  
383 -  
384 - SrsFlvVodStreamDecoder ffd;  
385 -  
386 - // open fast decoder  
387 - if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) {  
388 - return ret;  
389 - }  
390 -  
391 - // save header, send later.  
392 - char flv_header[13];  
393 -  
394 - // send flv header  
395 - if ((ret = ffd.read_header_ext(flv_header)) != ERROR_SUCCESS) {  
396 - return ret;  
397 - }  
398 -  
399 - // save sequence header, send later  
400 - char* sh_data = NULL;  
401 - int sh_size = 0;  
402 -  
403 - if (true) {  
404 - // send sequence header  
405 - int64_t start = 0;  
406 - if ((ret = ffd.read_sequence_header_summary(&start, &sh_size)) != ERROR_SUCCESS) {  
407 - return ret;  
408 - }  
409 - if (sh_size <= 0) {  
410 - ret = ERROR_HTTP_FLV_SEQUENCE_HEADER;  
411 - srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret);  
412 - return ret;  
413 - }  
414 - }  
415 - sh_data = new char[sh_size];  
416 - SrsAutoFree(char, sh_data);  
417 - if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) {  
418 - return ret;  
419 - }  
420 -  
421 - // seek to data offset  
422 - int64_t left = fs.filesize() - offset;  
423 -  
424 - // write http header for ts.  
425 - w->header()->set_content_length((int)(sizeof(flv_header) + sh_size + left));  
426 - w->header()->set_content_type("video/x-flv"); 357 + return serve_file(w, r, fullpath);
  358 +}
427 359
428 - // write flv header and sequence header.  
429 - if ((ret = w->write(flv_header, sizeof(flv_header))) != ERROR_SUCCESS) {  
430 - return ret;  
431 - }  
432 - if (sh_size > 0 && (ret = w->write(sh_data, sh_size)) != ERROR_SUCCESS) {  
433 - return ret;  
434 - } 360 +int SrsGoHttpFileServer::copy(SrsFileReader* fs, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int size)
  361 +{
  362 + int ret = ERROR_SUCCESS;
435 363
436 - // write body. 364 + int left = size;
437 char* buf = r->http_ts_send_buffer(); 365 char* buf = r->http_ts_send_buffer();
438 - if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) {  
439 - return ret;  
440 - }  
441 366
442 - // send data  
443 while (left > 0) { 367 while (left > 0) {
444 ssize_t nread = -1; 368 ssize_t nread = -1;
445 - if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) {  
446 - return ret; 369 + if ((ret = fs->read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) {
  370 + break;
447 } 371 }
448 372
449 left -= nread; 373 left -= nread;
450 if ((ret = w->write(buf, nread)) != ERROR_SUCCESS) { 374 if ((ret = w->write(buf, nread)) != ERROR_SUCCESS) {
451 - return ret; 375 + break;
452 } 376 }
453 } 377 }
454 378
@@ -40,12 +40,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -40,12 +40,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 40
41 #include <srs_app_st.hpp> 41 #include <srs_app_st.hpp>
42 42
43 -class SrsSimpleBuffer;  
44 class SrsRequest; 43 class SrsRequest;
45 class SrsStSocket; 44 class SrsStSocket;
46 class SrsHttpUri; 45 class SrsHttpUri;
47 class SrsHttpMessage; 46 class SrsHttpMessage;
48 -class SrsHttpHandler; 47 +class SrsFileReader;
  48 +class SrsSimpleBuffer;
49 class ISrsGoHttpResponseWriter; 49 class ISrsGoHttpResponseWriter;
50 50
51 // http specification 51 // http specification
@@ -197,16 +197,27 @@ public: @@ -197,16 +197,27 @@ public:
197 // http.Handle("/", SrsGoHttpFileServer("static-dir")) 197 // http.Handle("/", SrsGoHttpFileServer("static-dir"))
198 class SrsGoHttpFileServer : public ISrsGoHttpHandler 198 class SrsGoHttpFileServer : public ISrsGoHttpHandler
199 { 199 {
200 -private: 200 +protected:
201 std::string dir; 201 std::string dir;
202 public: 202 public:
203 SrsGoHttpFileServer(std::string root_dir); 203 SrsGoHttpFileServer(std::string root_dir);
204 virtual ~SrsGoHttpFileServer(); 204 virtual ~SrsGoHttpFileServer();
205 public: 205 public:
206 virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); 206 virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
207 -private:  
208 - virtual int serve_file(std::string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);  
209 - virtual int serve_flv_stream(std::string fullpath, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int offset); 207 +protected:
  208 + /**
  209 + * serve the file by specified path.
  210 + */
  211 + virtual int serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
  212 + /**
  213 + * when access flv file with start=xxx.
  214 + */
  215 + virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
  216 +protected:
  217 + /**
  218 + * copy the fs to response writer in size bytes.
  219 + */
  220 + virtual int copy(SrsFileReader* fs, ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, int size);
210 }; 221 };
211 222
212 // the mux entry for server mux. 223 // the mux entry for server mux.
@@ -39,6 +39,101 @@ using namespace std; @@ -39,6 +39,101 @@ using namespace std;
39 #include <srs_core_autofree.hpp> 39 #include <srs_core_autofree.hpp>
40 #include <srs_app_config.hpp> 40 #include <srs_app_config.hpp>
41 #include <srs_kernel_utility.hpp> 41 #include <srs_kernel_utility.hpp>
  42 +#include <srs_kernel_file.hpp>
  43 +#include <srs_kernel_flv.hpp>
  44 +
  45 +SrsVodStream::SrsVodStream(string root_dir)
  46 + : SrsGoHttpFileServer(root_dir)
  47 +{
  48 +}
  49 +
  50 +SrsVodStream::~SrsVodStream()
  51 +{
  52 +}
  53 +
  54 +int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
  55 +{
  56 + int ret = ERROR_SUCCESS;
  57 +
  58 + SrsFileReader fs;
  59 +
  60 + // open flv file
  61 + if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {
  62 + return ret;
  63 + }
  64 +
  65 + if (offset > fs.filesize()) {
  66 + ret = ERROR_HTTP_FLV_OFFSET_OVERFLOW;
  67 + srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d",
  68 + fullpath.c_str(), fs.filesize(), offset, ret);
  69 + return ret;
  70 + }
  71 +
  72 + SrsFlvVodStreamDecoder ffd;
  73 +
  74 + // open fast decoder
  75 + if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) {
  76 + return ret;
  77 + }
  78 +
  79 + // save header, send later.
  80 + char flv_header[13];
  81 +
  82 + // send flv header
  83 + if ((ret = ffd.read_header_ext(flv_header)) != ERROR_SUCCESS) {
  84 + return ret;
  85 + }
  86 +
  87 + // save sequence header, send later
  88 + char* sh_data = NULL;
  89 + int sh_size = 0;
  90 +
  91 + if (true) {
  92 + // send sequence header
  93 + int64_t start = 0;
  94 + if ((ret = ffd.read_sequence_header_summary(&start, &sh_size)) != ERROR_SUCCESS) {
  95 + return ret;
  96 + }
  97 + if (sh_size <= 0) {
  98 + ret = ERROR_HTTP_FLV_SEQUENCE_HEADER;
  99 + srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret);
  100 + return ret;
  101 + }
  102 + }
  103 + sh_data = new char[sh_size];
  104 + SrsAutoFree(char, sh_data);
  105 + if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) {
  106 + return ret;
  107 + }
  108 +
  109 + // seek to data offset
  110 + int64_t left = fs.filesize() - offset;
  111 +
  112 + // write http header for ts.
  113 + w->header()->set_content_length((int)(sizeof(flv_header) + sh_size + left));
  114 + w->header()->set_content_type("video/x-flv");
  115 +
  116 + // write flv header and sequence header.
  117 + if ((ret = w->write(flv_header, sizeof(flv_header))) != ERROR_SUCCESS) {
  118 + return ret;
  119 + }
  120 + if (sh_size > 0 && (ret = w->write(sh_data, sh_size)) != ERROR_SUCCESS) {
  121 + return ret;
  122 + }
  123 +
  124 + // write body.
  125 + if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) {
  126 + return ret;
  127 + }
  128 +
  129 + // send data
  130 + if ((ret = copy(&fs, w, r, left)) != ERROR_SUCCESS) {
  131 + srs_warn("read flv=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
  132 + return ret;
  133 + }
  134 +
  135 + return ret;
  136 +}
42 137
43 SrsHttpServer::SrsHttpServer() 138 SrsHttpServer::SrsHttpServer()
44 { 139 {
@@ -71,7 +166,7 @@ int SrsHttpServer::initialize() @@ -71,7 +166,7 @@ int SrsHttpServer::initialize()
71 std::string mount = _srs_config->get_vhost_http_mount(vhost); 166 std::string mount = _srs_config->get_vhost_http_mount(vhost);
72 std::string dir = _srs_config->get_vhost_http_dir(vhost); 167 std::string dir = _srs_config->get_vhost_http_dir(vhost);
73 168
74 - if ((ret = mux.handle(mount, new SrsGoHttpFileServer(dir))) != ERROR_SUCCESS) { 169 + if ((ret = mux.handle(mount, new SrsVodStream(dir))) != ERROR_SUCCESS) {
75 srs_error("http: mount dir=%s for vhost=%s failed. ret=%d", dir.c_str(), vhost.c_str(), ret); 170 srs_error("http: mount dir=%s for vhost=%s failed. ret=%d", dir.c_str(), vhost.c_str(), ret);
76 return ret; 171 return ret;
77 } 172 }
@@ -84,7 +179,7 @@ int SrsHttpServer::initialize() @@ -84,7 +179,7 @@ int SrsHttpServer::initialize()
84 if (!default_root_exists) { 179 if (!default_root_exists) {
85 // add root 180 // add root
86 std::string dir = _srs_config->get_http_stream_dir(); 181 std::string dir = _srs_config->get_http_stream_dir();
87 - if ((ret = mux.handle("/", new SrsGoHttpFileServer(dir))) != ERROR_SUCCESS) { 182 + if ((ret = mux.handle("/", new SrsVodStream(dir))) != ERROR_SUCCESS) {
88 srs_error("http: mount root dir=%s failed. ret=%d", dir.c_str(), ret); 183 srs_error("http: mount root dir=%s failed. ret=%d", dir.c_str(), ret);
89 return ret; 184 return ret;
90 } 185 }
@@ -41,7 +41,21 @@ class SrsHttpParser; @@ -41,7 +41,21 @@ class SrsHttpParser;
41 class SrsHttpMessage; 41 class SrsHttpMessage;
42 class SrsHttpHandler; 42 class SrsHttpHandler;
43 43
44 -// for http server. 44 +/**
  45 +* the flv vod stream supports flv?start=offset-bytes.
  46 +* for example, http://server/file.flv?start=10240
  47 +* server will write flv header and sequence header,
  48 +* then seek(10240) and response flv tag data.
  49 +*/
  50 +class SrsVodStream : public SrsGoHttpFileServer
  51 +{
  52 +public:
  53 + SrsVodStream(std::string root_dir);
  54 + virtual ~SrsVodStream();
  55 +protected:
  56 + virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
  57 +};
  58 +
45 class SrsHttpServer 59 class SrsHttpServer
46 { 60 {
47 public: 61 public: