正在显示
9 个修改的文件
包含
209 行增加
和
49 行删除
| @@ -566,6 +566,8 @@ Supported operating systems and hardware: | @@ -566,6 +566,8 @@ Supported operating systems and hardware: | ||
| 566 | 566 | ||
| 567 | ### SRS 2.0 history | 567 | ### SRS 2.0 history |
| 568 | 568 | ||
| 569 | +* v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts. | ||
| 570 | +* v2.0, 2015-04-10, refine the hls deviation for floor algorithm. | ||
| 569 | * v2.0, 2015-04-08, for [#375](https://github.com/winlinvip/simple-rtmp-server/issues/375), fix hls bug, keep cc continous between ts files. 2.0.159. | 571 | * v2.0, 2015-04-08, for [#375](https://github.com/winlinvip/simple-rtmp-server/issues/375), fix hls bug, keep cc continous between ts files. 2.0.159. |
| 570 | * v2.0, 2015-04-04, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), rewrite annexb mux for ts, refer to apple sample. 2.0.157. | 572 | * v2.0, 2015-04-04, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), rewrite annexb mux for ts, refer to apple sample. 2.0.157. |
| 571 | * v2.0, 2015-04-03, enhanced avc decode, parse the sps get width+height. 2.0.156. | 573 | * v2.0, 2015-04-03, enhanced avc decode, parse the sps get width+height. 2.0.156. |
| @@ -618,6 +618,15 @@ vhost with-hls.srs.com { | @@ -618,6 +618,15 @@ vhost with-hls.srs.com { | ||
| 618 | # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com | 618 | # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com |
| 619 | # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#http-callback | 619 | # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#http-callback |
| 620 | # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#http-callback | 620 | # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#http-callback |
| 621 | + | ||
| 622 | + # on_hls_notify, never config in here, should config in http_hooks. | ||
| 623 | + # we support the variables to generate the notify url: | ||
| 624 | + # [app], replace with the app. | ||
| 625 | + # [stream], replace with the stream. | ||
| 626 | + # [ts_url], replace with the ts url. | ||
| 627 | + # for the hls http callback, @see http_hooks.on_hls_notify of vhost hooks.callback.srs.com | ||
| 628 | + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#on-hls-notify | ||
| 629 | + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#on-hls-notify | ||
| 621 | } | 630 | } |
| 622 | } | 631 | } |
| 623 | # the vhost with hls disabled. | 632 | # the vhost with hls disabled. |
| @@ -768,6 +777,14 @@ vhost hooks.callback.srs.com { | @@ -768,6 +777,14 @@ vhost hooks.callback.srs.com { | ||
| 768 | # an int value specifies the error code(0 corresponding to success): | 777 | # an int value specifies the error code(0 corresponding to success): |
| 769 | # 0 | 778 | # 0 |
| 770 | on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls; | 779 | on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls; |
| 780 | + # when srs reap a ts file of hls, call this hook, | ||
| 781 | + # used to push file to cdn network, by get the ts file from cdn network. | ||
| 782 | + # so we use HTTP GET and use the variable following: | ||
| 783 | + # [app], replace with the app. | ||
| 784 | + # [stream], replace with the stream. | ||
| 785 | + # [ts_url], replace with the ts url. | ||
| 786 | + # ignore any return data of server. | ||
| 787 | + on_hls_notify http://127.0.0.1:8085/api/v1/hls/[app]/[stream][ts_url]; | ||
| 771 | } | 788 | } |
| 772 | } | 789 | } |
| 773 | 790 |
| @@ -314,10 +314,24 @@ handle the hls requests: hls stream. | @@ -314,10 +314,24 @@ handle the hls requests: hls stream. | ||
| 314 | class RESTHls(object): | 314 | class RESTHls(object): |
| 315 | exposed = True | 315 | exposed = True |
| 316 | 316 | ||
| 317 | - def GET(self): | 317 | + ''' |
| 318 | + for SRS hook: on_hls_notify | ||
| 319 | + on_hls_notify: | ||
| 320 | + when srs reap a ts file of hls, call this hook, | ||
| 321 | + used to push file to cdn network, by get the ts file from cdn network. | ||
| 322 | + so we use HTTP GET and use the variable following: | ||
| 323 | + [app], replace with the app. | ||
| 324 | + [stream], replace with the stream. | ||
| 325 | + [ts_url], replace with the ts url. | ||
| 326 | + ignore any return data of server. | ||
| 327 | + ''' | ||
| 328 | + def GET(self, *args, **kwargs): | ||
| 318 | enable_crossdomain() | 329 | enable_crossdomain() |
| 319 | 330 | ||
| 320 | - hls = {} | 331 | + hls = { |
| 332 | + "args": args, | ||
| 333 | + "kwargs": kwargs | ||
| 334 | + } | ||
| 321 | return json.dumps(hls) | 335 | return json.dumps(hls) |
| 322 | 336 | ||
| 323 | ''' | 337 | ''' |
| @@ -1499,7 +1499,7 @@ int SrsConfig::check_config() | @@ -1499,7 +1499,7 @@ int SrsConfig::check_config() | ||
| 1499 | string m = conf->at(j)->name.c_str(); | 1499 | string m = conf->at(j)->name.c_str(); |
| 1500 | if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" | 1500 | if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" |
| 1501 | && m != "on_unpublish" && m != "on_play" && m != "on_stop" | 1501 | && m != "on_unpublish" && m != "on_play" && m != "on_stop" |
| 1502 | - && m != "on_dvr" && m != "on_hls" | 1502 | + && m != "on_dvr" && m != "on_hls" && m != "on_hls_notify" |
| 1503 | ) { | 1503 | ) { |
| 1504 | ret = ERROR_SYSTEM_CONFIG_INVALID; | 1504 | ret = ERROR_SYSTEM_CONFIG_INVALID; |
| 1505 | srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); | 1505 | srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); |
| @@ -2429,6 +2429,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost) | @@ -2429,6 +2429,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost) | ||
| 2429 | return conf->get("on_hls"); | 2429 | return conf->get("on_hls"); |
| 2430 | } | 2430 | } |
| 2431 | 2431 | ||
| 2432 | +SrsConfDirective* SrsConfig::get_vhost_on_hls_notify(string vhost) | ||
| 2433 | +{ | ||
| 2434 | + SrsConfDirective* conf = get_vhost_http_hooks(vhost); | ||
| 2435 | + | ||
| 2436 | + if (!conf) { | ||
| 2437 | + return NULL; | ||
| 2438 | + } | ||
| 2439 | + | ||
| 2440 | + return conf->get("on_hls_notify"); | ||
| 2441 | +} | ||
| 2442 | + | ||
| 2432 | bool SrsConfig::get_bw_check_enabled(string vhost) | 2443 | bool SrsConfig::get_bw_check_enabled(string vhost) |
| 2433 | { | 2444 | { |
| 2434 | SrsConfDirective* conf = get_vhost(vhost); | 2445 | SrsConfDirective* conf = get_vhost(vhost); |
| @@ -646,6 +646,11 @@ public: | @@ -646,6 +646,11 @@ public: | ||
| 646 | * @return the on_hls callback directive, the args is the url to callback. | 646 | * @return the on_hls callback directive, the args is the url to callback. |
| 647 | */ | 647 | */ |
| 648 | virtual SrsConfDirective* get_vhost_on_hls(std::string vhost); | 648 | virtual SrsConfDirective* get_vhost_on_hls(std::string vhost); |
| 649 | + /** | ||
| 650 | + * get the on_hls_notify callbacks of vhost. | ||
| 651 | + * @return the on_hls_notify callback directive, the args is the url to callback. | ||
| 652 | + */ | ||
| 653 | + virtual SrsConfDirective* get_vhost_on_hls_notify(std::string vhost); | ||
| 649 | // bwct(bandwidth check tool) section | 654 | // bwct(bandwidth check tool) section |
| 650 | public: | 655 | public: |
| 651 | /** | 656 | /** |
| @@ -59,10 +59,10 @@ using namespace std; | @@ -59,10 +59,10 @@ using namespace std; | ||
| 59 | // drop the segment when duration of ts too small. | 59 | // drop the segment when duration of ts too small. |
| 60 | #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 | 60 | #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 |
| 61 | 61 | ||
| 62 | -// startup piece, the first piece, fragment percent to reap. | ||
| 63 | -#define SRS_HLS_FLOOR_STARTUP_PERCENT 0.1 | ||
| 64 | // fragment plus the deviation percent. | 62 | // fragment plus the deviation percent. |
| 65 | #define SRS_HLS_FLOOR_REAP_PERCENT 0.2 | 63 | #define SRS_HLS_FLOOR_REAP_PERCENT 0.2 |
| 64 | +// reset the piece id when deviation overflow this. | ||
| 65 | +#define SRS_JUMP_WHEN_PIECE_DEVIATION 10 | ||
| 66 | 66 | ||
| 67 | ISrsHlsHandler::ISrsHlsHandler() | 67 | ISrsHlsHandler::ISrsHlsHandler() |
| 68 | { | 68 | { |
| @@ -213,9 +213,49 @@ int SrsDvrAsyncCallOnHls::call() | @@ -213,9 +213,49 @@ int SrsDvrAsyncCallOnHls::call() | ||
| 213 | 213 | ||
| 214 | string SrsDvrAsyncCallOnHls::to_string() | 214 | string SrsDvrAsyncCallOnHls::to_string() |
| 215 | { | 215 | { |
| 216 | - std::stringstream ss; | ||
| 217 | - ss << "vhost=" << req->vhost << ", file=" << path; | ||
| 218 | - return ss.str(); | 216 | + return "on_hls: " + path; |
| 217 | +} | ||
| 218 | + | ||
| 219 | +SrsDvrAsyncCallOnHlsNotify::SrsDvrAsyncCallOnHlsNotify(SrsRequest* r, string u) | ||
| 220 | +{ | ||
| 221 | + req = r; | ||
| 222 | + ts_url = u; | ||
| 223 | +} | ||
| 224 | + | ||
| 225 | +SrsDvrAsyncCallOnHlsNotify::~SrsDvrAsyncCallOnHlsNotify() | ||
| 226 | +{ | ||
| 227 | +} | ||
| 228 | + | ||
| 229 | +int SrsDvrAsyncCallOnHlsNotify::call() | ||
| 230 | +{ | ||
| 231 | + int ret = ERROR_SUCCESS; | ||
| 232 | + | ||
| 233 | +#ifdef SRS_AUTO_HTTP_CALLBACK | ||
| 234 | + // http callback for on_hls_notify in config. | ||
| 235 | + if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { | ||
| 236 | + // HTTP: on_hls | ||
| 237 | + SrsConfDirective* on_hls = _srs_config->get_vhost_on_hls_notify(req->vhost); | ||
| 238 | + if (!on_hls) { | ||
| 239 | + srs_info("ignore the empty http callback: on_hls_notify"); | ||
| 240 | + return ret; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + for (int i = 0; i < (int)on_hls->args.size(); i++) { | ||
| 244 | + std::string url = on_hls->args.at(i); | ||
| 245 | + if ((ret = SrsHttpHooks::on_hls_notify(url, req, ts_url)) != ERROR_SUCCESS) { | ||
| 246 | + srs_error("hook client on_hls_notify failed. url=%s, ret=%d", url.c_str(), ret); | ||
| 247 | + return ret; | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | +#endif | ||
| 252 | + | ||
| 253 | + return ret; | ||
| 254 | +} | ||
| 255 | + | ||
| 256 | +string SrsDvrAsyncCallOnHlsNotify::to_string() | ||
| 257 | +{ | ||
| 258 | + return "on_hls_notify: " + ts_url; | ||
| 219 | } | 259 | } |
| 220 | 260 | ||
| 221 | SrsHlsMuxer::SrsHlsMuxer() | 261 | SrsHlsMuxer::SrsHlsMuxer() |
| @@ -224,7 +264,7 @@ SrsHlsMuxer::SrsHlsMuxer() | @@ -224,7 +264,7 @@ SrsHlsMuxer::SrsHlsMuxer() | ||
| 224 | handler = NULL; | 264 | handler = NULL; |
| 225 | hls_fragment = hls_window = 0; | 265 | hls_fragment = hls_window = 0; |
| 226 | hls_aof_ratio = 1.0; | 266 | hls_aof_ratio = 1.0; |
| 227 | - hls_fragment_deviation = 0; | 267 | + deviation_ts = 0; |
| 228 | hls_cleanup = true; | 268 | hls_cleanup = true; |
| 229 | previous_floor_ts = 0; | 269 | previous_floor_ts = 0; |
| 230 | accept_floor_ts = 0; | 270 | accept_floor_ts = 0; |
| @@ -269,26 +309,14 @@ double SrsHlsMuxer::duration() | @@ -269,26 +309,14 @@ double SrsHlsMuxer::duration() | ||
| 269 | return current? current->duration:0; | 309 | return current? current->duration:0; |
| 270 | } | 310 | } |
| 271 | 311 | ||
| 272 | -double SrsHlsMuxer::deviation() | ||
| 273 | -{ | ||
| 274 | - // no floor, no deviation. | ||
| 275 | - if (!hls_ts_floor) { | ||
| 276 | - return 0; | ||
| 277 | - } | ||
| 278 | - | ||
| 279 | - return hls_fragment_deviation; | ||
| 280 | -} | ||
| 281 | - | ||
| 282 | -int SrsHlsMuxer::absolute_deviation() | 312 | +int SrsHlsMuxer::deviation() |
| 283 | { | 313 | { |
| 284 | // no floor, no deviation. | 314 | // no floor, no deviation. |
| 285 | if (!hls_ts_floor) { | 315 | if (!hls_ts_floor) { |
| 286 | return 0; | 316 | return 0; |
| 287 | } | 317 | } |
| 288 | 318 | ||
| 289 | - // accept the floor ts for the first piece. | ||
| 290 | - int64_t floor_ts = (int64_t)(srs_get_system_time_ms() / (1000 * hls_fragment)); | ||
| 291 | - return (int)(accept_floor_ts - (floor_ts - 1)); | 319 | + return deviation_ts; |
| 292 | } | 320 | } |
| 293 | 321 | ||
| 294 | int SrsHlsMuxer::initialize(ISrsHlsHandler* h) | 322 | int SrsHlsMuxer::initialize(ISrsHlsHandler* h) |
| @@ -323,9 +351,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | @@ -323,9 +351,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | ||
| 323 | previous_floor_ts = 0; | 351 | previous_floor_ts = 0; |
| 324 | accept_floor_ts = 0; | 352 | accept_floor_ts = 0; |
| 325 | hls_window = window; | 353 | hls_window = window; |
| 326 | - // for the first time, we set to -N% of fragment, | ||
| 327 | - // that is, the first piece always smaller. | ||
| 328 | - hls_fragment_deviation = -1 * (fragment * SRS_HLS_FLOOR_STARTUP_PERCENT); | 354 | + deviation_ts = 0; |
| 329 | 355 | ||
| 330 | // generate the m3u8 dir and path. | 356 | // generate the m3u8 dir and path. |
| 331 | m3u8 = path + "/" + m3u8_file; | 357 | m3u8 = path + "/" + m3u8_file; |
| @@ -412,26 +438,39 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) | @@ -412,26 +438,39 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) | ||
| 412 | ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream); | 438 | ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream); |
| 413 | if (hls_ts_floor) { | 439 | if (hls_ts_floor) { |
| 414 | // accept the floor ts for the first piece. | 440 | // accept the floor ts for the first piece. |
| 415 | - int64_t floor_ts = (int64_t)(srs_get_system_time_ms() / (1000 * hls_fragment)); | 441 | + int64_t current_floor_ts = (int64_t)(srs_get_system_time_ms() / (1000 * hls_fragment)); |
| 416 | if (!accept_floor_ts) { | 442 | if (!accept_floor_ts) { |
| 417 | - accept_floor_ts = floor_ts - 1; | 443 | + accept_floor_ts = current_floor_ts - 1; |
| 418 | } else { | 444 | } else { |
| 419 | accept_floor_ts++; | 445 | accept_floor_ts++; |
| 420 | } | 446 | } |
| 421 | 447 | ||
| 448 | + // jump when deviation more than 10p | ||
| 449 | + if (accept_floor_ts - current_floor_ts > SRS_JUMP_WHEN_PIECE_DEVIATION) { | ||
| 450 | + srs_warn("hls: jmp for ts deviation, current=%"PRId64", accept=%"PRId64, current_floor_ts, accept_floor_ts); | ||
| 451 | + accept_floor_ts = current_floor_ts - 1; | ||
| 452 | + } | ||
| 453 | + | ||
| 454 | + // when reap ts, adjust the deviation. | ||
| 455 | + deviation_ts = (int)(accept_floor_ts - current_floor_ts); | ||
| 456 | + | ||
| 457 | + // dup/jmp detect for ts in floor mode. | ||
| 458 | + if (previous_floor_ts && previous_floor_ts != current_floor_ts - 1) { | ||
| 459 | + srs_warn("hls: dup or jmp for floor ts, previous=%"PRId64", current=%"PRId64", accept=%"PRId64", deviation=%d", | ||
| 460 | + previous_floor_ts, current_floor_ts, accept_floor_ts, deviation_ts); | ||
| 461 | + } | ||
| 462 | + previous_floor_ts = current_floor_ts; | ||
| 463 | + | ||
| 422 | // we always ensure the piece is increase one by one. | 464 | // we always ensure the piece is increase one by one. |
| 423 | std::stringstream ts_floor; | 465 | std::stringstream ts_floor; |
| 424 | ts_floor << accept_floor_ts; | 466 | ts_floor << accept_floor_ts; |
| 425 | ts_file = srs_string_replace(ts_file, "[timestamp]", ts_floor.str()); | 467 | ts_file = srs_string_replace(ts_file, "[timestamp]", ts_floor.str()); |
| 426 | 468 | ||
| 427 | - // dup/jmp detect for ts in floor mode. | ||
| 428 | - if (previous_floor_ts && previous_floor_ts != floor_ts - 1) { | ||
| 429 | - srs_warn("hls: dup or jmp for floor ts, previous=%"PRId64", current=%"PRId64", ts=%s, deviation=%.2f", | ||
| 430 | - previous_floor_ts, floor_ts, ts_file.c_str(), hls_fragment_deviation); | ||
| 431 | - } | ||
| 432 | - previous_floor_ts = floor_ts; | 469 | + // TODO: FIMXE: we must use the accept ts floor time to generate the hour variable. |
| 470 | + ts_file = srs_path_build_timestamp(ts_file); | ||
| 471 | + } else { | ||
| 472 | + ts_file = srs_path_build_timestamp(ts_file); | ||
| 433 | } | 473 | } |
| 434 | - ts_file = srs_path_build_timestamp(ts_file); | ||
| 435 | if (true) { | 474 | if (true) { |
| 436 | std::stringstream ss; | 475 | std::stringstream ss; |
| 437 | ss << current->sequence_no; | 476 | ss << current->sequence_no; |
| @@ -497,7 +536,7 @@ bool SrsHlsMuxer::is_segment_overflow() | @@ -497,7 +536,7 @@ bool SrsHlsMuxer::is_segment_overflow() | ||
| 497 | srs_assert(current); | 536 | srs_assert(current); |
| 498 | 537 | ||
| 499 | // use N% deviation, to smoother. | 538 | // use N% deviation, to smoother. |
| 500 | - double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * hls_fragment_deviation : 0.0; | 539 | + double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0.0; |
| 501 | 540 | ||
| 502 | return current->duration >= hls_fragment + deviation; | 541 | return current->duration >= hls_fragment + deviation; |
| 503 | } | 542 | } |
| @@ -594,19 +633,19 @@ int SrsHlsMuxer::segment_close(string log_desc) | @@ -594,19 +633,19 @@ int SrsHlsMuxer::segment_close(string log_desc) | ||
| 594 | if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { | 633 | if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { |
| 595 | segments.push_back(current); | 634 | segments.push_back(current); |
| 596 | 635 | ||
| 597 | - // when reap ts, adjust the deviation. | ||
| 598 | - if (hls_ts_floor) { | ||
| 599 | - hls_fragment_deviation += (double)(hls_fragment - current->duration); | 636 | + // use async to call the http hooks, for it will cause thread switch. |
| 637 | + if ((ret = async->call(new SrsDvrAsyncCallOnHls(req, current->full_path, current->sequence_no, current->duration))) != ERROR_SUCCESS) { | ||
| 638 | + return ret; | ||
| 600 | } | 639 | } |
| 601 | 640 | ||
| 602 | // use async to call the http hooks, for it will cause thread switch. | 641 | // use async to call the http hooks, for it will cause thread switch. |
| 603 | - if ((ret = async->call(new SrsDvrAsyncCallOnHls(req, current->full_path, current->sequence_no, current->duration))) != ERROR_SUCCESS) { | 642 | + if ((ret = async->call(new SrsDvrAsyncCallOnHlsNotify(req, current->uri))) != ERROR_SUCCESS) { |
| 604 | return ret; | 643 | return ret; |
| 605 | } | 644 | } |
| 606 | 645 | ||
| 607 | - srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64", deviation=%.2f", | 646 | + srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64, |
| 608 | log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration, | 647 | log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration, |
| 609 | - current->segment_start_dts, hls_fragment_deviation); | 648 | + current->segment_start_dts); |
| 610 | 649 | ||
| 611 | // notify handler for update ts. | 650 | // notify handler for update ts. |
| 612 | srs_assert(current->writer); | 651 | srs_assert(current->writer); |
| @@ -1222,9 +1261,9 @@ void SrsHls::hls_show_mux_log() | @@ -1222,9 +1261,9 @@ void SrsHls::hls_show_mux_log() | ||
| 1222 | // the run time is not equals to stream time, | 1261 | // the run time is not equals to stream time, |
| 1223 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/81#issuecomment-48100994 | 1262 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/81#issuecomment-48100994 |
| 1224 | // it's ok. | 1263 | // it's ok. |
| 1225 | - srs_trace("-> "SRS_CONSTS_LOG_HLS" time=%"PRId64", stream dts=%"PRId64"(%"PRId64"ms), sno=%d, ts=%s, dur=%.2f, dva=%.2fs/%dp", | 1264 | + srs_trace("-> "SRS_CONSTS_LOG_HLS" time=%"PRId64", stream dts=%"PRId64"(%"PRId64"ms), sno=%d, ts=%s, dur=%.2f, dva=%dp", |
| 1226 | pprint->age(), stream_dts, stream_dts / 90, muxer->sequence_no(), muxer->ts_url().c_str(), | 1265 | pprint->age(), stream_dts, stream_dts / 90, muxer->sequence_no(), muxer->ts_url().c_str(), |
| 1227 | - muxer->duration(), muxer->deviation(), muxer->absolute_deviation()); | 1266 | + muxer->duration(), muxer->deviation()); |
| 1228 | } | 1267 | } |
| 1229 | } | 1268 | } |
| 1230 | 1269 |
| @@ -157,7 +157,7 @@ public: | @@ -157,7 +157,7 @@ public: | ||
| 157 | }; | 157 | }; |
| 158 | 158 | ||
| 159 | /** | 159 | /** |
| 160 | - * the dvr async call. | 160 | + * the hls async call: on_hls |
| 161 | */ | 161 | */ |
| 162 | class SrsDvrAsyncCallOnHls : public ISrsDvrAsyncCall | 162 | class SrsDvrAsyncCallOnHls : public ISrsDvrAsyncCall |
| 163 | { | 163 | { |
| @@ -175,6 +175,22 @@ public: | @@ -175,6 +175,22 @@ public: | ||
| 175 | }; | 175 | }; |
| 176 | 176 | ||
| 177 | /** | 177 | /** |
| 178 | + * the hls async call: on_hls_notify | ||
| 179 | + */ | ||
| 180 | +class SrsDvrAsyncCallOnHlsNotify : public ISrsDvrAsyncCall | ||
| 181 | +{ | ||
| 182 | +private: | ||
| 183 | + std::string ts_url; | ||
| 184 | + SrsRequest* req; | ||
| 185 | +public: | ||
| 186 | + SrsDvrAsyncCallOnHlsNotify(SrsRequest* r, std::string u); | ||
| 187 | + virtual ~SrsDvrAsyncCallOnHlsNotify(); | ||
| 188 | +public: | ||
| 189 | + virtual int call(); | ||
| 190 | + virtual std::string to_string(); | ||
| 191 | +}; | ||
| 192 | + | ||
| 193 | +/** | ||
| 178 | * muxer the HLS stream(m3u8 and ts files). | 194 | * muxer the HLS stream(m3u8 and ts files). |
| 179 | * generally, the m3u8 muxer only provides methods to open/close segments, | 195 | * generally, the m3u8 muxer only provides methods to open/close segments, |
| 180 | * to flush video/audio, without any mechenisms. | 196 | * to flush video/audio, without any mechenisms. |
| @@ -199,9 +215,9 @@ private: | @@ -199,9 +215,9 @@ private: | ||
| 199 | private: | 215 | private: |
| 200 | // whether use floor algorithm for timestamp. | 216 | // whether use floor algorithm for timestamp. |
| 201 | bool hls_ts_floor; | 217 | bool hls_ts_floor; |
| 202 | - // the deviation in seconds to adjust the fragment to be more | 218 | + // the deviation in piece to adjust the fragment to be more |
| 203 | // bigger or smaller. | 219 | // bigger or smaller. |
| 204 | - double hls_fragment_deviation; | 220 | + int deviation_ts; |
| 205 | // the previous reap floor timestamp, | 221 | // the previous reap floor timestamp, |
| 206 | // used to detect the dup or jmp or ts. | 222 | // used to detect the dup or jmp or ts. |
| 207 | int64_t accept_floor_ts; | 223 | int64_t accept_floor_ts; |
| @@ -242,8 +258,7 @@ public: | @@ -242,8 +258,7 @@ public: | ||
| 242 | virtual int sequence_no(); | 258 | virtual int sequence_no(); |
| 243 | virtual std::string ts_url(); | 259 | virtual std::string ts_url(); |
| 244 | virtual double duration(); | 260 | virtual double duration(); |
| 245 | - virtual double deviation(); | ||
| 246 | - virtual int absolute_deviation(); | 261 | + virtual int deviation(); |
| 247 | public: | 262 | public: |
| 248 | /** | 263 | /** |
| 249 | * initialize the hls muxer. | 264 | * initialize the hls muxer. |
| @@ -37,6 +37,7 @@ using namespace std; | @@ -37,6 +37,7 @@ using namespace std; | ||
| 37 | #include <srs_app_http_client.hpp> | 37 | #include <srs_app_http_client.hpp> |
| 38 | #include <srs_core_autofree.hpp> | 38 | #include <srs_core_autofree.hpp> |
| 39 | #include <srs_app_config.hpp> | 39 | #include <srs_app_config.hpp> |
| 40 | +#include <srs_kernel_utility.hpp> | ||
| 40 | 41 | ||
| 41 | #define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS) | 42 | #define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS) |
| 42 | 43 | ||
| @@ -325,6 +326,55 @@ int SrsHttpHooks::on_hls(string url, SrsRequest* req, string file, int sn, doubl | @@ -325,6 +326,55 @@ int SrsHttpHooks::on_hls(string url, SrsRequest* req, string file, int sn, doubl | ||
| 325 | return ret; | 326 | return ret; |
| 326 | } | 327 | } |
| 327 | 328 | ||
| 329 | +int SrsHttpHooks::on_hls_notify(std::string url, SrsRequest* req, std::string ts_url) | ||
| 330 | +{ | ||
| 331 | + int ret = ERROR_SUCCESS; | ||
| 332 | + | ||
| 333 | + int client_id = _srs_context->get_id(); | ||
| 334 | + std::string cwd = _srs_config->cwd(); | ||
| 335 | + | ||
| 336 | + if (srs_string_starts_with(ts_url, "http://") || srs_string_starts_with(ts_url, "https://")) { | ||
| 337 | + url = ts_url; | ||
| 338 | + } | ||
| 339 | + | ||
| 340 | + url = srs_string_replace(url, "[app]", req->app); | ||
| 341 | + url = srs_string_replace(url, "[stream]", req->stream); | ||
| 342 | + url = srs_string_replace(url, "[ts_url]", ts_url); | ||
| 343 | + | ||
| 344 | + SrsHttpUri uri; | ||
| 345 | + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { | ||
| 346 | + srs_error("http: post failed. url=%s, ret=%d", url.c_str(), ret); | ||
| 347 | + return ret; | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + SrsHttpClient http; | ||
| 351 | + if ((ret = http.initialize(uri.get_host(), uri.get_port())) != ERROR_SUCCESS) { | ||
| 352 | + return ret; | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + SrsHttpMessage* msg = NULL; | ||
| 356 | + if ((ret = http.get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) { | ||
| 357 | + return ret; | ||
| 358 | + } | ||
| 359 | + SrsAutoFree(SrsHttpMessage, msg); | ||
| 360 | + | ||
| 361 | + ISrsHttpResponseReader* br = msg->body_reader(); | ||
| 362 | + while (!br->eof()) { | ||
| 363 | + std::string data; | ||
| 364 | + if ((ret = br->read(data)) != ERROR_SUCCESS) { | ||
| 365 | + break; | ||
| 366 | + } | ||
| 367 | + } | ||
| 368 | + | ||
| 369 | + srs_trace("http hook on_hls_notify success. client_id=%d, url=%s, code=%d, ret=%d", | ||
| 370 | + client_id, url.c_str(), msg->status_code(), ret); | ||
| 371 | + | ||
| 372 | + // ignore any error for on_hls_notify. | ||
| 373 | + ret = ERROR_SUCCESS; | ||
| 374 | + | ||
| 375 | + return ret; | ||
| 376 | +} | ||
| 377 | + | ||
| 328 | int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& res) | 378 | int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& res) |
| 329 | { | 379 | { |
| 330 | int ret = ERROR_SUCCESS; | 380 | int ret = ERROR_SUCCESS; |
| @@ -105,6 +105,13 @@ public: | @@ -105,6 +105,13 @@ public: | ||
| 105 | * @param duration the segment duration in seconds. | 105 | * @param duration the segment duration in seconds. |
| 106 | */ | 106 | */ |
| 107 | static int on_hls(std::string url, SrsRequest* req, std::string file, int sn, double duration); | 107 | static int on_hls(std::string url, SrsRequest* req, std::string file, int sn, double duration); |
| 108 | + /** | ||
| 109 | + * when hls reap segment, callback. | ||
| 110 | + * @param url the api server url, to process the event. | ||
| 111 | + * ignore if empty. | ||
| 112 | + * @param ts_url the ts uri, used to replace the variable [ts_url] in url. | ||
| 113 | + */ | ||
| 114 | + static int on_hls_notify(std::string url, SrsRequest* req, std::string ts_url); | ||
| 108 | private: | 115 | private: |
| 109 | static int do_post(std::string url, std::string req, int& code, std::string& res); | 116 | static int do_post(std::string url, std::string req, int& code, std::string& res); |
| 110 | }; | 117 | }; |
-
请 注册 或 登录 后发表评论