winlin

http streaming support flv start index.

@@ -44,7 +44,6 @@ g++ -o ts_info ts_info.cc -g -O0 -ansi @@ -44,7 +44,6 @@ g++ -o ts_info ts_info.cc -g -O0 -ansi
44 44
45 #define trace(msg, ...) printf(msg"\n", ##__VA_ARGS__); 45 #define trace(msg, ...) printf(msg"\n", ##__VA_ARGS__);
46 #define srs_freep(p) delete p; p = NULL 46 #define srs_freep(p) delete p; p = NULL
47 -#define srs_freepa(p) delete[] p; p = NULL  
48 #define srs_assert(p) assert(p) 47 #define srs_assert(p) assert(p)
49 #define srs_min(a, b) ((a)<(b)? (a):(b)) 48 #define srs_min(a, b) ((a)<(b)? (a):(b))
50 49
@@ -263,7 +263,7 @@ int SrsDvrPlan::flv_open(string stream, string path) @@ -263,7 +263,7 @@ int SrsDvrPlan::flv_open(string stream, string path)
263 segment->reset(); 263 segment->reset();
264 264
265 std::string tmp_file = path + ".tmp"; 265 std::string tmp_file = path + ".tmp";
266 - if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) { 266 + if ((ret = fs->open_write(tmp_file)) != ERROR_SUCCESS) {
267 srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret); 267 srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
268 return ret; 268 return ret;
269 } 269 }
@@ -287,9 +287,7 @@ int SrsDvrPlan::flv_close() @@ -287,9 +287,7 @@ int SrsDvrPlan::flv_close()
287 { 287 {
288 int ret = ERROR_SUCCESS; 288 int ret = ERROR_SUCCESS;
289 289
290 - if ((ret = fs->close()) != ERROR_SUCCESS) {  
291 - return ret;  
292 - } 290 + fs->close();
293 291
294 std::string tmp_file = segment->path + ".tmp"; 292 std::string tmp_file = segment->path + ".tmp";
295 if (rename(tmp_file.c_str(), segment->path.c_str()) < 0) { 293 if (rename(tmp_file.c_str(), segment->path.c_str()) < 0) {
@@ -552,7 +550,7 @@ int SrsDvrHssPlan::on_meta_data(SrsOnMetaDataPacket* metadata) @@ -552,7 +550,7 @@ int SrsDvrHssPlan::on_meta_data(SrsOnMetaDataPacket* metadata)
552 << req->stream << ".header.flv"; 550 << req->stream << ".header.flv";
553 551
554 SrsFileStream fs; 552 SrsFileStream fs;
555 - if ((ret = fs.open(path.str().c_str())) != ERROR_SUCCESS) { 553 + if ((ret = fs.open_write(path.str().c_str())) != ERROR_SUCCESS) {
556 return ret; 554 return ret;
557 } 555 }
558 556
@@ -38,6 +38,9 @@ using namespace std; @@ -38,6 +38,9 @@ using namespace std;
38 #include <srs_app_http_hooks.hpp> 38 #include <srs_app_http_hooks.hpp>
39 #include <srs_app_codec.hpp> 39 #include <srs_app_codec.hpp>
40 40
  41 +#define SRS_FLV_TAG_HEADER_SIZE 11
  42 +#define SRS_FLV_PREVIOUS_TAG_SIZE 4
  43 +
41 SrsFileStream::SrsFileStream() 44 SrsFileStream::SrsFileStream()
42 { 45 {
43 fd = -1; 46 fd = -1;
@@ -48,7 +51,7 @@ SrsFileStream::~SrsFileStream() @@ -48,7 +51,7 @@ SrsFileStream::~SrsFileStream()
48 close(); 51 close();
49 } 52 }
50 53
51 -int SrsFileStream::open(string file) 54 +int SrsFileStream::open_write(string file)
52 { 55 {
53 int ret = ERROR_SUCCESS; 56 int ret = ERROR_SUCCESS;
54 57
@@ -72,22 +75,43 @@ int SrsFileStream::open(string file) @@ -72,22 +75,43 @@ int SrsFileStream::open(string file)
72 return ret; 75 return ret;
73 } 76 }
74 77
75 -int SrsFileStream::close() 78 +int SrsFileStream::open_read(string file)
76 { 79 {
77 int ret = ERROR_SUCCESS; 80 int ret = ERROR_SUCCESS;
78 81
79 - if (fd < 0) { 82 + if (fd > 0) {
  83 + ret = ERROR_SYSTEM_FILE_ALREADY_OPENED;
  84 + srs_error("file %s already opened. ret=%d", _file.c_str(), ret);
  85 + return ret;
  86 + }
  87 +
  88 + if ((fd = ::open(file.c_str(), O_RDONLY)) < 0) {
  89 + ret = ERROR_SYSTEM_FILE_OPENE;
  90 + srs_error("open file %s failed. ret=%d", file.c_str(), ret);
80 return ret; 91 return ret;
81 } 92 }
82 93
  94 + _file = file;
  95 +
  96 + return ret;
  97 +}
  98 +
  99 +void SrsFileStream::close()
  100 +{
  101 + int ret = ERROR_SUCCESS;
  102 +
  103 + if (fd < 0) {
  104 + return;
  105 + }
  106 +
83 if (::close(fd) < 0) { 107 if (::close(fd) < 0) {
84 ret = ERROR_SYSTEM_FILE_CLOSE; 108 ret = ERROR_SYSTEM_FILE_CLOSE;
85 srs_error("close file %s failed. ret=%d", _file.c_str(), ret); 109 srs_error("close file %s failed. ret=%d", _file.c_str(), ret);
86 - return ret; 110 + return;
87 } 111 }
88 fd = -1; 112 fd = -1;
89 113
90 - return ret; 114 + return;
91 } 115 }
92 116
93 bool SrsFileStream::is_open() 117 bool SrsFileStream::is_open()
@@ -141,6 +165,24 @@ int64_t SrsFileStream::tellg() @@ -141,6 +165,24 @@ int64_t SrsFileStream::tellg()
141 return (int64_t)::lseek(fd, 0, SEEK_CUR); 165 return (int64_t)::lseek(fd, 0, SEEK_CUR);
142 } 166 }
143 167
  168 +int64_t SrsFileStream::lseek(int64_t offset)
  169 +{
  170 + return (int64_t)::lseek(fd, offset, SEEK_SET);
  171 +}
  172 +
  173 +int64_t SrsFileStream::filesize()
  174 +{
  175 + int64_t cur = tellg();
  176 + int64_t size = (int64_t)::lseek(fd, 0, SEEK_END);
  177 + ::lseek(fd, cur, SEEK_SET);
  178 + return size;
  179 +}
  180 +
  181 +void SrsFileStream::skip(int64_t size)
  182 +{
  183 + ::lseek(fd, size, SEEK_CUR);
  184 +}
  185 +
144 SrsFlvEncoder::SrsFlvEncoder() 186 SrsFlvEncoder::SrsFlvEncoder()
145 { 187 {
146 _fs = NULL; 188 _fs = NULL;
@@ -165,6 +207,7 @@ int SrsFlvEncoder::write_header() @@ -165,6 +207,7 @@ int SrsFlvEncoder::write_header()
165 { 207 {
166 int ret = ERROR_SUCCESS; 208 int ret = ERROR_SUCCESS;
167 209
  210 + // 9bytes header and 4bytes first previous-tag-size
168 static char flv_header[] = { 211 static char flv_header[] = {
169 'F', 'L', 'V', // Signatures "FLV" 212 'F', 'L', 'V', // Signatures "FLV"
170 (char)0x01, // File version (for example, 0x01 for FLV version 1) 213 (char)0x01, // File version (for example, 0x01 for FLV version 1)
@@ -218,6 +261,7 @@ int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size) @@ -218,6 +261,7 @@ int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size)
218 261
219 timestamp &= 0x7fffffff; 262 timestamp &= 0x7fffffff;
220 263
  264 + // 11bytes tag header
221 static char tag_header[] = { 265 static char tag_header[] = {
222 (char)8, // TagType UB [5], 8 = audio 266 (char)8, // TagType UB [5], 8 = audio
223 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. 267 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
@@ -249,6 +293,7 @@ int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size) @@ -249,6 +293,7 @@ int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)
249 293
250 timestamp &= 0x7fffffff; 294 timestamp &= 0x7fffffff;
251 295
  296 + // 11bytes tag header
252 static char tag_header[] = { 297 static char tag_header[] = {
253 (char)9, // TagType UB [5], 9 = video 298 (char)9, // TagType UB [5], 9 = video
254 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. 299 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
@@ -291,8 +336,8 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s @@ -291,8 +336,8 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s
291 } 336 }
292 337
293 // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes. 338 // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes.
294 - static char pre_size[4];  
295 - if ((ret = tag_stream->initialize(pre_size, 4)) != ERROR_SUCCESS) { 339 + static char pre_size[SRS_FLV_PREVIOUS_TAG_SIZE];
  340 + if ((ret = tag_stream->initialize(pre_size, SRS_FLV_PREVIOUS_TAG_SIZE)) != ERROR_SUCCESS) {
296 return ret; 341 return ret;
297 } 342 }
298 tag_stream->write_4bytes(tag_size + header_size); 343 tag_stream->write_4bytes(tag_size + header_size);
@@ -304,3 +349,163 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s @@ -304,3 +349,163 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s
304 return ret; 349 return ret;
305 } 350 }
306 351
  352 +SrsFlvFastDecoder::SrsFlvFastDecoder()
  353 +{
  354 + _fs = NULL;
  355 + tag_stream = new SrsStream();
  356 +}
  357 +
  358 +SrsFlvFastDecoder::~SrsFlvFastDecoder()
  359 +{
  360 + srs_freep(tag_stream);
  361 +}
  362 +
  363 +int SrsFlvFastDecoder::initialize(SrsFileStream* fs)
  364 +{
  365 + int ret = ERROR_SUCCESS;
  366 +
  367 + _fs = fs;
  368 +
  369 + return ret;
  370 +}
  371 +
  372 +int SrsFlvFastDecoder::read_header(char** pdata, int* psize)
  373 +{
  374 + *pdata = NULL;
  375 + *psize = 0;
  376 +
  377 + int ret = ERROR_SUCCESS;
  378 +
  379 + srs_assert(_fs);
  380 +
  381 + // 9bytes header and 4bytes first previous-tag-size
  382 + int size = 13;
  383 + char* buf = new char[size];
  384 +
  385 + if ((ret = _fs->read(buf, size, NULL)) != ERROR_SUCCESS) {
  386 + return ret;
  387 + }
  388 +
  389 + *pdata = buf;
  390 + *psize = size;
  391 +
  392 + return ret;
  393 +}
  394 +
  395 +int SrsFlvFastDecoder::read_sequence_header(int64_t* pstart, int* psize)
  396 +{
  397 + *pstart = 0;
  398 + *psize = 0;
  399 +
  400 + int ret = ERROR_SUCCESS;
  401 +
  402 + srs_assert(_fs);
  403 +
  404 + // simply, the first video/audio must be the sequence header.
  405 + // and must be a sequence video and audio.
  406 +
  407 + // 11bytes tag header
  408 + static char tag_header[] = {
  409 + (char)0x00, // TagType UB [5], 9 = video, 8 = audio, 18 = script data
  410 + (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
  411 + (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
  412 + (char)0x00, // TimestampExtended UI8
  413 + (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
  414 + };
  415 +
  416 + // discovery the sequence header video and audio.
  417 + // @remark, maybe no video or no audio.
  418 + bool got_video = false;
  419 + bool got_audio = false;
  420 + // audio/video sequence and data offset.
  421 + int64_t av_sequence_offset_start = -1;
  422 + int64_t av_sequence_offset_end = -1;
  423 + for (;;) {
  424 + if ((ret = _fs->read(tag_header, SRS_FLV_TAG_HEADER_SIZE, NULL)) != ERROR_SUCCESS) {
  425 + return ret;
  426 + }
  427 +
  428 + if ((ret = tag_stream->initialize(tag_header, SRS_FLV_TAG_HEADER_SIZE)) != ERROR_SUCCESS) {
  429 + return ret;
  430 + }
  431 +
  432 + int8_t tag_type = tag_stream->read_1bytes();
  433 + int32_t data_size = tag_stream->read_3bytes();
  434 +
  435 + bool is_video = tag_type == 0x09;
  436 + bool is_audio = tag_type == 0x08;
  437 + bool is_not_av = !is_video && !is_audio;
  438 + if (is_not_av) {
  439 + // skip body and tag size.
  440 + _fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
  441 + continue;
  442 + }
  443 +
  444 + // if video duplicated, no audio
  445 + if (is_video && got_video) {
  446 + break;
  447 + }
  448 + // if audio duplicated, no video
  449 + if (is_audio && got_audio) {
  450 + break;
  451 + }
  452 +
  453 + // video
  454 + if (is_video) {
  455 + srs_assert(!got_video);
  456 + got_video = true;
  457 +
  458 + if (av_sequence_offset_start < 0) {
  459 + av_sequence_offset_start = _fs->tellg() - SRS_FLV_TAG_HEADER_SIZE;
  460 + }
  461 + av_sequence_offset_end = _fs->tellg() + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
  462 + _fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
  463 + }
  464 +
  465 + // audio
  466 + if (is_audio) {
  467 + srs_assert(!got_audio);
  468 + got_audio = true;
  469 +
  470 + if (av_sequence_offset_start < 0) {
  471 + av_sequence_offset_start = _fs->tellg() - SRS_FLV_TAG_HEADER_SIZE;
  472 + }
  473 + av_sequence_offset_end = _fs->tellg() + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
  474 + _fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
  475 + }
  476 + }
  477 +
  478 + // seek to the sequence header start offset.
  479 + if (av_sequence_offset_start > 0) {
  480 + _fs->lseek(av_sequence_offset_start);
  481 + *pstart = av_sequence_offset_start;
  482 + *psize = (int)(av_sequence_offset_end - av_sequence_offset_start);
  483 + }
  484 +
  485 + return ret;
  486 +}
  487 +
  488 +int SrsFlvFastDecoder::lseek(int64_t offset)
  489 +{
  490 + int ret = ERROR_SUCCESS;
  491 +
  492 + srs_assert(_fs);
  493 +
  494 + if (offset >= _fs->filesize()) {
  495 + ret = ERROR_SYSTEM_FILE_EOF;
  496 + srs_warn("flv fast decoder seek overflow file, "
  497 + "size=%"PRId64", offset=%"PRId64", ret=%d",
  498 + _fs->filesize(), offset, ret);
  499 + return ret;
  500 + }
  501 +
  502 + if (_fs->lseek(offset) < 0) {
  503 + ret = ERROR_SYSTEM_FILE_SEEK;
  504 + srs_warn("flv fast decoder seek error, "
  505 + "size=%"PRId64", offset=%"PRId64", ret=%d",
  506 + _fs->filesize(), offset, ret);
  507 + return ret;
  508 + }
  509 +
  510 + return ret;
  511 +}
@@ -43,8 +43,9 @@ public: @@ -43,8 +43,9 @@ public:
43 SrsFileStream(); 43 SrsFileStream();
44 virtual ~SrsFileStream(); 44 virtual ~SrsFileStream();
45 public: 45 public:
46 - virtual int open(std::string file);  
47 - virtual int close(); 46 + virtual int open_write(std::string file);
  47 + virtual int open_read(std::string file);
  48 + virtual void close();
48 virtual bool is_open(); 49 virtual bool is_open();
49 public: 50 public:
50 /** 51 /**
@@ -59,6 +60,9 @@ public: @@ -59,6 +60,9 @@ public:
59 * tell current offset of stream. 60 * tell current offset of stream.
60 */ 61 */
61 virtual int64_t tellg(); 62 virtual int64_t tellg();
  63 + virtual int64_t lseek(int64_t offset);
  64 + virtual int64_t filesize();
  65 + virtual void skip(int64_t size);
62 }; 66 };
63 67
64 /** 68 /**
@@ -104,4 +108,38 @@ private: @@ -104,4 +108,38 @@ private:
104 virtual int write_tag(char* header, int header_size, char* tag, int tag_size); 108 virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
105 }; 109 };
106 110
  111 +/**
  112 +* decode flv fast by only decoding the header and tag.
  113 +*/
  114 +class SrsFlvFastDecoder
  115 +{
  116 +private:
  117 + SrsFileStream* _fs;
  118 +private:
  119 + SrsStream* tag_stream;
  120 +public:
  121 + SrsFlvFastDecoder();
  122 + virtual ~SrsFlvFastDecoder();
  123 +public:
  124 + /**
  125 + * initialize the underlayer file stream,
  126 + * user can initialize multiple times to encode multiple flv files.
  127 + */
  128 + virtual int initialize(SrsFileStream* fs);
  129 +public:
  130 + /**
  131 + * read the flv header and size.
  132 + */
  133 + virtual int read_header(char** pdata, int* psize);
  134 + /**
  135 + * read the sequence header and size.
  136 + */
  137 + virtual int read_sequence_header(int64_t* pstart, int* psize);
  138 +public:
  139 + /**
  140 + * for start offset, seed to this position and response flv stream.
  141 + */
  142 + virtual int lseek(int64_t offset);
  143 +};
  144 +
107 #endif 145 #endif
@@ -707,6 +707,28 @@ void SrsHttpMessage::append_body(const char* body, int length) @@ -707,6 +707,28 @@ void SrsHttpMessage::append_body(const char* body, int length)
707 _body->append(body, length); 707 _body->append(body, length);
708 } 708 }
709 709
  710 +string SrsHttpMessage::query_get(string key)
  711 +{
  712 + std::string q = query();
  713 + size_t pos = std::string::npos;
  714 +
  715 + // must format as key=value&...&keyN=valueN
  716 + if ((pos = key.find("=")) != key.length() - 1) {
  717 + key = key + "=";
  718 + }
  719 +
  720 + if ((pos = q.find(key)) == std::string::npos) {
  721 + return "";
  722 + }
  723 +
  724 + std::string v = q.substr(pos + key.length());
  725 + if ((pos = v.find("&")) != std::string::npos) {
  726 + v = v.substr(0, pos);
  727 + }
  728 +
  729 + return v;
  730 +}
  731 +
710 int SrsHttpMessage::request_header_count() 732 int SrsHttpMessage::request_header_count()
711 { 733 {
712 return (int)headers.size(); 734 return (int)headers.size();
@@ -359,6 +359,13 @@ public: @@ -359,6 +359,13 @@ public:
359 virtual void set_requires_crossdomain(bool requires_crossdomain); 359 virtual void set_requires_crossdomain(bool requires_crossdomain);
360 virtual void append_body(const char* body, int length); 360 virtual void append_body(const char* body, int length);
361 public: 361 public:
  362 + /**
  363 + * get the param in query string,
  364 + * for instance, query is "start=100&end=200",
  365 + * then query_get("start") is "100", and query_get("end") is "200"
  366 + */
  367 + virtual std::string query_get(std::string key);
  368 +public:
362 virtual int request_header_count(); 369 virtual int request_header_count();
363 virtual std::string request_header_key_at(int index); 370 virtual std::string request_header_key_at(int index);
364 virtual std::string request_header_value_at(int index); 371 virtual std::string request_header_value_at(int index);
@@ -25,12 +25,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -25,12 +25,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 25
26 #ifdef SRS_AUTO_HTTP_SERVER 26 #ifdef SRS_AUTO_HTTP_SERVER
27 27
28 -#include <sstream>  
29 -using namespace std;  
30 -  
31 #include <sys/types.h> 28 #include <sys/types.h>
32 #include <sys/stat.h> 29 #include <sys/stat.h>
33 #include <fcntl.h> 30 #include <fcntl.h>
  31 +#include <stdlib.h>
  32 +
  33 +#include <sstream>
  34 +using namespace std;
34 35
35 #include <srs_kernel_log.hpp> 36 #include <srs_kernel_log.hpp>
36 #include <srs_kernel_error.hpp> 37 #include <srs_kernel_error.hpp>
@@ -39,6 +40,7 @@ using namespace std; @@ -39,6 +40,7 @@ using namespace std;
39 #include <srs_core_autofree.hpp> 40 #include <srs_core_autofree.hpp>
40 #include <srs_app_json.hpp> 41 #include <srs_app_json.hpp>
41 #include <srs_app_config.hpp> 42 #include <srs_app_config.hpp>
  43 +#include <srs_app_flv.hpp>
42 44
43 #define SRS_HTTP_DEFAULT_PAGE "index.html" 45 #define SRS_HTTP_DEFAULT_PAGE "index.html"
44 46
@@ -166,7 +168,17 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) @@ -166,7 +168,17 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
166 if (srs_string_ends_with(fullpath, ".ts")) { 168 if (srs_string_ends_with(fullpath, ".ts")) {
167 return response_ts_file(skt, req, fullpath); 169 return response_ts_file(skt, req, fullpath);
168 } else if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) { 170 } else if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) {
169 - return response_flv_file(skt, req, fullpath); 171 + std::string start = req->query_get("start");
  172 + if (start.empty()) {
  173 + return response_flv_file(skt, req, fullpath);
  174 + }
  175 +
  176 + int offset = ::atoi(start.c_str());
  177 + if (offset <= 0) {
  178 + return response_flv_file(skt, req, fullpath);
  179 + }
  180 +
  181 + return response_flv_file2(skt, req, fullpath, offset);
170 } else { 182 } else {
171 return response_regular_file(skt, req, fullpath); 183 return response_regular_file(skt, req, fullpath);
172 } 184 }
@@ -283,6 +295,112 @@ int SrsHttpVhost::response_flv_file(SrsSocket* skt, SrsHttpMessage* req, string @@ -283,6 +295,112 @@ int SrsHttpVhost::response_flv_file(SrsSocket* skt, SrsHttpMessage* req, string
283 return ret; 295 return ret;
284 } 296 }
285 297
  298 +int SrsHttpVhost::response_flv_file2(SrsSocket* skt, SrsHttpMessage* req, string fullpath, int offset)
  299 +{
  300 + int ret = ERROR_SUCCESS;
  301 +
  302 + SrsFileStream fs;
  303 +
  304 + // open flv file
  305 + if ((ret = fs.open_read(fullpath)) != ERROR_SUCCESS) {
  306 + return ret;
  307 + }
  308 +
  309 + if (offset > fs.filesize()) {
  310 + ret = ERROR_HTTP_FLV_OFFSET_OVERFLOW;
  311 + srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d",
  312 + fullpath.c_str(), fs.filesize(), offset, ret);
  313 + return ret;
  314 + }
  315 +
  316 + SrsFlvFastDecoder ffd;
  317 +
  318 + // open fast decoder
  319 + if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) {
  320 + return ret;
  321 + }
  322 +
  323 + // save header, send later.
  324 + char* flv_header = NULL;
  325 + int flv_size = 0;
  326 +
  327 + // send flv header
  328 + if ((ret = ffd.read_header(&flv_header, &flv_size)) != ERROR_SUCCESS) {
  329 + return ret;
  330 + }
  331 + SrsAutoFree(char, flv_header);
  332 +
  333 + // save sequence header, send later
  334 + char* sh_data = NULL;
  335 + int sh_size = 0;
  336 +
  337 + if (true) {
  338 + // send sequence header
  339 + int64_t start = 0;
  340 + if ((ret = ffd.read_sequence_header(&start, &sh_size)) != ERROR_SUCCESS) {
  341 + return ret;
  342 + }
  343 + if (sh_size <= 0) {
  344 + ret = ERROR_HTTP_FLV_SEQUENCE_HEADER;
  345 + srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret);
  346 + return ret;
  347 + }
  348 + }
  349 + sh_data = new char[sh_size];
  350 + SrsAutoFree(char, sh_data);
  351 + if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) {
  352 + return ret;
  353 + }
  354 +
  355 + // seek to data offset
  356 + int64_t left = fs.filesize() - offset;
  357 +
  358 + // write http header for ts.
  359 + std::stringstream ss;
  360 +
  361 + res_status_line(ss)->res_content_type_flv(ss)
  362 + ->res_content_length(ss, (int)(flv_size + sh_size + left));
  363 +
  364 + if (req->requires_crossdomain()) {
  365 + res_enable_crossdomain(ss);
  366 + }
  367 +
  368 + res_header_eof(ss);
  369 +
  370 + // flush http header to peer
  371 + if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) {
  372 + return ret;
  373 + }
  374 +
  375 + if (flv_size > 0 && (ret = skt->write(flv_header, flv_size, NULL)) != ERROR_SUCCESS) {
  376 + return ret;
  377 + }
  378 + if (sh_size > 0 && (ret = skt->write(sh_data, sh_size, NULL)) != ERROR_SUCCESS) {
  379 + return ret;
  380 + }
  381 +
  382 + // write body.
  383 + char* buf = req->http_ts_send_buffer();
  384 + if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) {
  385 + return ret;
  386 + }
  387 +
  388 + // send data
  389 + while (left > 0) {
  390 + ssize_t nread = -1;
  391 + if ((ret = fs.read(buf, HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) {
  392 + return ret;
  393 + }
  394 +
  395 + left -= nread;
  396 + if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) {
  397 + return ret;
  398 + }
  399 + }
  400 +
  401 + return ret;
  402 +}
  403 +
286 int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath) 404 int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath)
287 { 405 {
288 int ret = ERROR_SUCCESS; 406 int ret = ERROR_SUCCESS;
@@ -72,6 +72,7 @@ protected: @@ -72,6 +72,7 @@ protected:
72 private: 72 private:
73 virtual int response_regular_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); 73 virtual int response_regular_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath);
74 virtual int response_flv_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); 74 virtual int response_flv_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath);
  75 + virtual int response_flv_file2(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath, int offset);
75 virtual int response_ts_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); 76 virtual int response_ts_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath);
76 virtual std::string get_request_file(SrsHttpMessage* req); 77 virtual std::string get_request_file(SrsHttpMessage* req);
77 public: 78 public:
@@ -306,6 +306,7 @@ int SrsRtmpConn::stream_service_cycle() @@ -306,6 +306,7 @@ int SrsRtmpConn::stream_service_cycle()
306 case SrsRtmpConnPlay: { 306 case SrsRtmpConnPlay: {
307 srs_verbose("start to play stream %s.", req->stream.c_str()); 307 srs_verbose("start to play stream %s.", req->stream.c_str());
308 308
  309 + // notice edge to start for the first client.
309 if (vhost_is_edge) { 310 if (vhost_is_edge) {
310 if ((ret = source->on_edge_start_play()) != ERROR_SUCCESS) { 311 if ((ret = source->on_edge_start_play()) != ERROR_SUCCESS) {
311 srs_error("notice edge start play stream failed. ret=%d", ret); 312 srs_error("notice edge start play stream failed. ret=%d", ret);
@@ -313,6 +314,7 @@ int SrsRtmpConn::stream_service_cycle() @@ -313,6 +314,7 @@ int SrsRtmpConn::stream_service_cycle()
313 } 314 }
314 } 315 }
315 316
  317 + // response connection start play
316 if ((ret = rtmp->start_play(res->stream_id)) != ERROR_SUCCESS) { 318 if ((ret = rtmp->start_play(res->stream_id)) != ERROR_SUCCESS) {
317 srs_error("start to play stream failed. ret=%d", ret); 319 srs_error("start to play stream failed. ret=%d", ret);
318 return ret; 320 return ret;
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "114" 34 +#define VERSION_REVISION "113"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"
@@ -117,6 +117,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -117,6 +117,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
117 #define ERROR_SYSTEM_FILE_EOF 428 117 #define ERROR_SYSTEM_FILE_EOF 428
118 #define ERROR_SYSTEM_FILE_RENAME 429 118 #define ERROR_SYSTEM_FILE_RENAME 429
119 #define ERROR_SYSTEM_CREATE_PIPE 430 119 #define ERROR_SYSTEM_CREATE_PIPE 430
  120 +#define ERROR_SYSTEM_FILE_SEEK 431
120 121
121 // see librtmp. 122 // see librtmp.
122 // failed when open ssl create the dh 123 // failed when open ssl create the dh
@@ -184,6 +185,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -184,6 +185,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
184 #define ERROR_HTTP_OPEN_FILE 805 185 #define ERROR_HTTP_OPEN_FILE 805
185 #define ERROR_HTTP_READ_FILE 806 186 #define ERROR_HTTP_READ_FILE 806
186 #define ERROR_HTTP_API_LOGS 807 187 #define ERROR_HTTP_API_LOGS 807
  188 +#define ERROR_HTTP_FLV_SEQUENCE_HEADER 808
  189 +#define ERROR_HTTP_FLV_OFFSET_OVERFLOW 809
187 190
188 // system control message, 191 // system control message,
189 // not an error, but special control logic. 192 // not an error, but special control logic.