for #299, srs http server support dash, flash request range in range or bytes.
正在显示
5 个修改的文件
包含
113 行增加
和
4 行删除
| @@ -134,6 +134,14 @@ http_server { | @@ -134,6 +134,14 @@ http_server { | ||
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | ############################################################################################# | 136 | ############################################################################################# |
| 137 | +# Streamer sections | ||
| 138 | +############################################################################################# | ||
| 139 | +# the streamer cast stream from other protocol to SRS over RTMP. | ||
| 140 | +# @see https://github.com/winlinvip/simple-rtmp-server/tree/develop#stream-architecture | ||
| 141 | +streamer { | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +############################################################################################# | ||
| 137 | # RTMP/HTTP VHOST sections | 145 | # RTMP/HTTP VHOST sections |
| 138 | ############################################################################################# | 146 | ############################################################################################# |
| 139 | # vhost list, the __defaultVhost__ is the default vhost | 147 | # vhost list, the __defaultVhost__ is the default vhost |
| @@ -317,6 +317,40 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* | @@ -317,6 +317,40 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* | ||
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | return serve_flv_stream(w, r, fullpath, offset); | 319 | return serve_flv_stream(w, r, fullpath, offset); |
| 320 | + } else if (srs_string_ends_with(fullpath, ".mp4")) { | ||
| 321 | + // for flash to request mp4 range in query string. | ||
| 322 | + // for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd | ||
| 323 | + std::string range = r->query_get("range"); | ||
| 324 | + // or, use bytes to request range, | ||
| 325 | + // for example, http://dashas.castlabs.com/demo/try.html | ||
| 326 | + if (range.empty()) { | ||
| 327 | + range = r->query_get("bytes"); | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + // rollback to serve whole file. | ||
| 331 | + size_t pos = string::npos; | ||
| 332 | + if (range.empty() || (pos = range.find("-")) == string::npos) { | ||
| 333 | + return serve_file(w, r, fullpath); | ||
| 334 | + } | ||
| 335 | + | ||
| 336 | + // parse the start in query string | ||
| 337 | + int start = 0; | ||
| 338 | + if (pos > 0) { | ||
| 339 | + start = ::atoi(range.substr(0, pos).c_str()); | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + // parse end in query string. | ||
| 343 | + int end = -1; | ||
| 344 | + if (pos < range.length() - 1) { | ||
| 345 | + end = ::atoi(range.substr(pos + 1).c_str()); | ||
| 346 | + } | ||
| 347 | + | ||
| 348 | + // invalid param, serve as whole mp4 file. | ||
| 349 | + if (start < 0 || (end != -1 && start > end)) { | ||
| 350 | + return serve_file(w, r, fullpath); | ||
| 351 | + } | ||
| 352 | + | ||
| 353 | + return serve_mp4_range(w, r, fullpath, start, end); | ||
| 320 | } | 354 | } |
| 321 | 355 | ||
| 322 | // serve common static file. | 356 | // serve common static file. |
| @@ -377,7 +411,7 @@ int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* | @@ -377,7 +411,7 @@ int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* | ||
| 377 | } | 411 | } |
| 378 | 412 | ||
| 379 | if (_mime.find(ext) == _mime.end()) { | 413 | if (_mime.find(ext) == _mime.end()) { |
| 380 | - w->header()->set_content_type("text/html;charset=utf-8"); | 414 | + w->header()->set_content_type("application/octet-stream"); |
| 381 | } else { | 415 | } else { |
| 382 | w->header()->set_content_type(_mime[ext]); | 416 | w->header()->set_content_type(_mime[ext]); |
| 383 | } | 417 | } |
| @@ -398,6 +432,11 @@ int SrsGoHttpFileServer::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMe | @@ -398,6 +432,11 @@ int SrsGoHttpFileServer::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMe | ||
| 398 | return serve_file(w, r, fullpath); | 432 | return serve_file(w, r, fullpath); |
| 399 | } | 433 | } |
| 400 | 434 | ||
| 435 | +int SrsGoHttpFileServer::serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end) | ||
| 436 | +{ | ||
| 437 | + return serve_file(w, r, fullpath); | ||
| 438 | +} | ||
| 439 | + | ||
| 401 | int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size) | 440 | int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size) |
| 402 | { | 441 | { |
| 403 | int ret = ERROR_SUCCESS; | 442 | int ret = ERROR_SUCCESS; |
| @@ -407,7 +446,8 @@ int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, Sr | @@ -407,7 +446,8 @@ int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, Sr | ||
| 407 | 446 | ||
| 408 | while (left > 0) { | 447 | while (left > 0) { |
| 409 | ssize_t nread = -1; | 448 | ssize_t nread = -1; |
| 410 | - if ((ret = fs->read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) { | 449 | + int max_read = srs_min(left, __SRS_HTTP_TS_SEND_BUFFER_SIZE); |
| 450 | + if ((ret = fs->read(buf, max_read, &nread)) != ERROR_SUCCESS) { | ||
| 411 | break; | 451 | break; |
| 412 | } | 452 | } |
| 413 | 453 |
| @@ -213,13 +213,20 @@ public: | @@ -213,13 +213,20 @@ public: | ||
| 213 | virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); | 213 | virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); |
| 214 | protected: | 214 | protected: |
| 215 | /** | 215 | /** |
| 216 | - * serve the file by specified path. | 216 | + * serve the file by specified path |
| 217 | */ | 217 | */ |
| 218 | virtual int serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath); | 218 | virtual int serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath); |
| 219 | /** | 219 | /** |
| 220 | - * when access flv file with start=xxx. | 220 | + * when access flv file with x.flv?start=xxx |
| 221 | */ | 221 | */ |
| 222 | virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset); | 222 | virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset); |
| 223 | + /** | ||
| 224 | + * when access mp4 file with x.mp4?range=start-end | ||
| 225 | + * @param start the start offset in bytes. | ||
| 226 | + * @param end the end offset in bytes. -1 to end of file. | ||
| 227 | + * @remark response data in [start, end]. | ||
| 228 | + */ | ||
| 229 | + virtual int serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end); | ||
| 223 | protected: | 230 | protected: |
| 224 | /** | 231 | /** |
| 225 | * copy the fs to response writer in size bytes. | 232 | * copy the fs to response writer in size bytes. |
| @@ -141,6 +141,59 @@ int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* | @@ -141,6 +141,59 @@ int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* | ||
| 141 | return ret; | 141 | return ret; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | +int SrsVodStream::serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end) | ||
| 145 | +{ | ||
| 146 | + int ret = ERROR_SUCCESS; | ||
| 147 | + | ||
| 148 | + srs_assert(start >= 0); | ||
| 149 | + srs_assert(end == -1 || end >= 0); | ||
| 150 | + | ||
| 151 | + SrsFileReader fs; | ||
| 152 | + | ||
| 153 | + // open flv file | ||
| 154 | + if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { | ||
| 155 | + return ret; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + // parse -1 to whole file. | ||
| 159 | + if (end == -1) { | ||
| 160 | + end = fs.filesize(); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + if (end > fs.filesize() || start > end) { | ||
| 164 | + ret = ERROR_HTTP_REMUX_OFFSET_OVERFLOW; | ||
| 165 | + srs_warn("http mp4 streaming %s overflow. size=%"PRId64", offset=%d, ret=%d", | ||
| 166 | + fullpath.c_str(), fs.filesize(), start, ret); | ||
| 167 | + return ret; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + // seek to data offset, [start, end] for range. | ||
| 171 | + int64_t left = end - start + 1; | ||
| 172 | + | ||
| 173 | + // write http header for ts. | ||
| 174 | + w->header()->set_content_length(left); | ||
| 175 | + w->header()->set_content_type("video/mp4"); | ||
| 176 | + | ||
| 177 | + // status code 206 to make dash.as happy. | ||
| 178 | + w->write_header(SRS_CONSTS_HTTP_PartialContent); | ||
| 179 | + | ||
| 180 | + // response the content range header. | ||
| 181 | + std::stringstream content_range; | ||
| 182 | + content_range << "bytes " << start << "-" << end << "/" << fs.filesize(); | ||
| 183 | + w->header()->set("Content-Range", content_range.str()); | ||
| 184 | + | ||
| 185 | + // write body. | ||
| 186 | + fs.lseek(start); | ||
| 187 | + | ||
| 188 | + // send data | ||
| 189 | + if ((ret = copy(w, &fs, r, left)) != ERROR_SUCCESS) { | ||
| 190 | + srs_warn("read mp4=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret); | ||
| 191 | + return ret; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + return ret; | ||
| 195 | +} | ||
| 196 | + | ||
| 144 | SrsStreamCache::SrsStreamCache(SrsSource* s, SrsRequest* r) | 197 | SrsStreamCache::SrsStreamCache(SrsSource* s, SrsRequest* r) |
| 145 | { | 198 | { |
| 146 | req = r->copy(); | 199 | req = r->copy(); |
| @@ -66,6 +66,7 @@ public: | @@ -66,6 +66,7 @@ public: | ||
| 66 | virtual ~SrsVodStream(); | 66 | virtual ~SrsVodStream(); |
| 67 | protected: | 67 | protected: |
| 68 | virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset); | 68 | virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset); |
| 69 | + virtual int serve_mp4_range(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end); | ||
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 71 | /** | 72 | /** |
-
请 注册 或 登录 后发表评论