正在显示
5 个修改的文件
包含
101 行增加
和
72 行删除
| @@ -325,6 +325,56 @@ class RESTSessions(object): | @@ -325,6 +325,56 @@ class RESTSessions(object): | ||
| 325 | # TODO: process the on_stop event | 325 | # TODO: process the on_stop event |
| 326 | 326 | ||
| 327 | return code | 327 | return code |
| 328 | + | ||
| 329 | +# the rest dvrs, when dvr got keyframe, call this api. | ||
| 330 | +class RESTDvrs(object): | ||
| 331 | + exposed = True | ||
| 332 | + def __init__(self): | ||
| 333 | + pass | ||
| 334 | + # the dvrs POST api specified in following. | ||
| 335 | + # | ||
| 336 | + # when dvr got an keyframe, call the hook, | ||
| 337 | + # the request in the POST data string is a object encode by json: | ||
| 338 | + # { | ||
| 339 | + # "action": "on_dvr_keyframe", | ||
| 340 | + # "vhost": "video.test.com", "app": "live", | ||
| 341 | + # "stream": "livestream" | ||
| 342 | + # } | ||
| 343 | + # | ||
| 344 | + # if valid, the hook must return HTTP code 200(Stauts OK) and response | ||
| 345 | + # an int value specifies the error code(0 corresponding to success): | ||
| 346 | + # 0 | ||
| 347 | + def POST(self): | ||
| 348 | + enable_crossdomain() | ||
| 349 | + | ||
| 350 | + req = cherrypy.request.body.read() | ||
| 351 | + trace("post to sessions, req=%s"%(req)) | ||
| 352 | + try: | ||
| 353 | + json_req = json.loads(req) | ||
| 354 | + except Exception, ex: | ||
| 355 | + code = Error.system_parse_json | ||
| 356 | + trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code)) | ||
| 357 | + return str(code) | ||
| 358 | + | ||
| 359 | + action = json_req["action"] | ||
| 360 | + if action == "on_dvr_keyframe": | ||
| 361 | + code = self.__on_dvr_keyframe(json_req) | ||
| 362 | + else: | ||
| 363 | + code = Errors.request_invalid_action | ||
| 364 | + trace("invalid request action: %s, code=%s"%(json_req["action"], code)) | ||
| 365 | + | ||
| 366 | + return str(code) | ||
| 367 | + | ||
| 368 | + def __on_dvr_keyframe(self, req): | ||
| 369 | + code = Error.success | ||
| 370 | + | ||
| 371 | + trace("srs %s: vhost=%s, app=%s, stream=%s"%( | ||
| 372 | + req["action"], req["vhost"], req["app"], req["stream"] | ||
| 373 | + )) | ||
| 374 | + | ||
| 375 | + # TODO: process the on_dvr_keyframe event | ||
| 376 | + | ||
| 377 | + return code | ||
| 328 | 378 | ||
| 329 | global_arm_server_id = os.getpid(); | 379 | global_arm_server_id = os.getpid(); |
| 330 | class ArmServer: | 380 | class ArmServer: |
| @@ -930,6 +980,7 @@ class V1(object): | @@ -930,6 +980,7 @@ class V1(object): | ||
| 930 | self.clients = RESTClients() | 980 | self.clients = RESTClients() |
| 931 | self.streams = RESTStreams() | 981 | self.streams = RESTStreams() |
| 932 | self.sessions = RESTSessions() | 982 | self.sessions = RESTSessions() |
| 983 | + self.dvrs = RESTDvrs() | ||
| 933 | self.chats = RESTChats() | 984 | self.chats = RESTChats() |
| 934 | self.servers = RESTServers() | 985 | self.servers = RESTServers() |
| 935 | self.nodes = RESTNodes() | 986 | self.nodes = RESTNodes() |
| @@ -303,10 +303,12 @@ SrsFlvSegment::SrsFlvSegment() | @@ -303,10 +303,12 @@ SrsFlvSegment::SrsFlvSegment() | ||
| 303 | segment_has_keyframe = false; | 303 | segment_has_keyframe = false; |
| 304 | duration = 0; | 304 | duration = 0; |
| 305 | starttime = -1; | 305 | starttime = -1; |
| 306 | + stream_starttime = 0; | ||
| 306 | } | 307 | } |
| 307 | 308 | ||
| 308 | void SrsFlvSegment::reset() | 309 | void SrsFlvSegment::reset() |
| 309 | { | 310 | { |
| 311 | + segment_has_keyframe = false; | ||
| 310 | duration = 0; | 312 | duration = 0; |
| 311 | starttime = -1; | 313 | starttime = -1; |
| 312 | } | 314 | } |
| @@ -319,7 +321,7 @@ SrsDvrPlan::SrsDvrPlan() | @@ -319,7 +321,7 @@ SrsDvrPlan::SrsDvrPlan() | ||
| 319 | dvr_enabled = false; | 321 | dvr_enabled = false; |
| 320 | fs = new SrsFileStream(); | 322 | fs = new SrsFileStream(); |
| 321 | enc = new SrsFlvEncoder(); | 323 | enc = new SrsFlvEncoder(); |
| 322 | - segment = NULL; | 324 | + segment = new SrsFlvSegment(); |
| 323 | } | 325 | } |
| 324 | 326 | ||
| 325 | SrsDvrPlan::~SrsDvrPlan() | 327 | SrsDvrPlan::~SrsDvrPlan() |
| @@ -362,6 +364,22 @@ int SrsDvrPlan::on_publish() | @@ -362,6 +364,22 @@ int SrsDvrPlan::on_publish() | ||
| 362 | // always update time cache. | 364 | // always update time cache. |
| 363 | srs_update_system_time_ms(); | 365 | srs_update_system_time_ms(); |
| 364 | 366 | ||
| 367 | + // when republish, stream starting. | ||
| 368 | + segment->stream_starttime = srs_get_system_time_ms(); | ||
| 369 | + | ||
| 370 | + if ((ret = open_new_segment()) != ERROR_SUCCESS) { | ||
| 371 | + return ret; | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + return ret; | ||
| 375 | +} | ||
| 376 | + | ||
| 377 | +int SrsDvrPlan::open_new_segment() | ||
| 378 | +{ | ||
| 379 | + int ret = ERROR_SUCCESS; | ||
| 380 | + | ||
| 381 | + SrsRequest* req = _req; | ||
| 382 | + | ||
| 365 | // new flv file | 383 | // new flv file |
| 366 | std::stringstream path; | 384 | std::stringstream path; |
| 367 | 385 | ||
| @@ -468,8 +486,7 @@ int SrsDvrPlan::flv_open(string stream, string path) | @@ -468,8 +486,7 @@ int SrsDvrPlan::flv_open(string stream, string path) | ||
| 468 | { | 486 | { |
| 469 | int ret = ERROR_SUCCESS; | 487 | int ret = ERROR_SUCCESS; |
| 470 | 488 | ||
| 471 | - srs_freep(segment); | ||
| 472 | - segment = new SrsFlvSegment(); | 489 | + segment->reset(); |
| 473 | 490 | ||
| 474 | std::string tmp_file = path + ".tmp"; | 491 | std::string tmp_file = path + ".tmp"; |
| 475 | if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) { | 492 | if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) { |
| @@ -548,7 +565,7 @@ int SrsDvrPlan::on_dvr_keyframe() | @@ -548,7 +565,7 @@ int SrsDvrPlan::on_dvr_keyframe() | ||
| 548 | 565 | ||
| 549 | for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) { | 566 | for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) { |
| 550 | std::string url = on_dvr_keyframe->args.at(i); | 567 | std::string url = on_dvr_keyframe->args.at(i); |
| 551 | - SrsHttpHooks::on_dvr_keyframe(url, _req); | 568 | + SrsHttpHooks::on_dvr_keyframe(url, _req, segment); |
| 552 | } | 569 | } |
| 553 | #endif | 570 | #endif |
| 554 | 571 | ||
| @@ -620,6 +637,9 @@ int SrsDvrSegmentPlan::on_publish() | @@ -620,6 +637,9 @@ int SrsDvrSegmentPlan::on_publish() | ||
| 620 | int ret = ERROR_SUCCESS; | 637 | int ret = ERROR_SUCCESS; |
| 621 | 638 | ||
| 622 | // if already opened, continue to dvr. | 639 | // if already opened, continue to dvr. |
| 640 | + // the segment plan maybe keep running longer than the encoder. | ||
| 641 | + // for example, segment running, encoder restart, | ||
| 642 | + // the segment plan will just continue going and donot open new segment. | ||
| 623 | if (fs->is_open()) { | 643 | if (fs->is_open()) { |
| 624 | dvr_enabled = true; | 644 | dvr_enabled = true; |
| 625 | return ret; | 645 | return ret; |
| @@ -648,15 +668,14 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) | @@ -648,15 +668,14 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) | ||
| 648 | srs_assert(segment); | 668 | srs_assert(segment); |
| 649 | 669 | ||
| 650 | // reap if exceed duration. | 670 | // reap if exceed duration. |
| 651 | - if (segment->duration > 0 && segment_duration > 0 && segment->duration > segment_duration) { | ||
| 652 | - segment->reset(); | ||
| 653 | - | 671 | + if (segment_duration > 0 && segment->duration > segment_duration) { |
| 654 | if ((ret = flv_close()) != ERROR_SUCCESS) { | 672 | if ((ret = flv_close()) != ERROR_SUCCESS) { |
| 673 | + segment->reset(); | ||
| 655 | return ret; | 674 | return ret; |
| 656 | } | 675 | } |
| 657 | on_unpublish(); | 676 | on_unpublish(); |
| 658 | 677 | ||
| 659 | - if ((ret = on_publish()) != ERROR_SUCCESS) { | 678 | + if ((ret = open_new_segment()) != ERROR_SUCCESS) { |
| 660 | return ret; | 679 | return ret; |
| 661 | } | 680 | } |
| 662 | } | 681 | } |
| @@ -121,11 +121,15 @@ public: | @@ -121,11 +121,15 @@ public: | ||
| 121 | * whether current segment has keyframe. | 121 | * whether current segment has keyframe. |
| 122 | */ | 122 | */ |
| 123 | bool segment_has_keyframe; | 123 | bool segment_has_keyframe; |
| 124 | - /** | ||
| 125 | - * current segment duration and starttime. | ||
| 126 | - */ | 124 | + /** |
| 125 | + * current segment duration and starttime. | ||
| 126 | + */ | ||
| 127 | int64_t duration; | 127 | int64_t duration; |
| 128 | int64_t starttime; | 128 | int64_t starttime; |
| 129 | + /** | ||
| 130 | + * stream start time, to generate atc pts. | ||
| 131 | + */ | ||
| 132 | + int64_t stream_starttime; | ||
| 129 | public: | 133 | public: |
| 130 | SrsFlvSegment(); | 134 | SrsFlvSegment(); |
| 131 | virtual void reset(); | 135 | virtual void reset(); |
| @@ -137,6 +141,7 @@ public: | @@ -137,6 +141,7 @@ public: | ||
| 137 | * 1. filename: the filename for record file. | 141 | * 1. filename: the filename for record file. |
| 138 | * 2. reap flv: when to reap the flv and start new piece. | 142 | * 2. reap flv: when to reap the flv and start new piece. |
| 139 | */ | 143 | */ |
| 144 | +// TODO: FIXME: the plan is too fat, refine me. | ||
| 140 | class SrsDvrPlan | 145 | class SrsDvrPlan |
| 141 | { | 146 | { |
| 142 | protected: | 147 | protected: |
| @@ -165,12 +170,13 @@ public: | @@ -165,12 +170,13 @@ public: | ||
| 165 | protected: | 170 | protected: |
| 166 | virtual int flv_open(std::string stream, std::string path); | 171 | virtual int flv_open(std::string stream, std::string path); |
| 167 | virtual int flv_close(); | 172 | virtual int flv_close(); |
| 173 | + virtual int open_new_segment(); | ||
| 168 | virtual int update_duration(SrsSharedPtrMessage* msg); | 174 | virtual int update_duration(SrsSharedPtrMessage* msg); |
| 169 | private: | 175 | private: |
| 170 | - /** | ||
| 171 | - * when srs reap the flv(close the segment), | ||
| 172 | - * if has keyframe, notice the api. | ||
| 173 | - */ | 176 | + /** |
| 177 | + * when srs reap the flv(close the segment), | ||
| 178 | + * if has keyframe, notice the api. | ||
| 179 | + */ | ||
| 174 | virtual int on_dvr_keyframe(); | 180 | virtual int on_dvr_keyframe(); |
| 175 | public: | 181 | public: |
| 176 | static SrsDvrPlan* create_plan(std::string vhost); | 182 | static SrsDvrPlan* create_plan(std::string vhost); |
| @@ -36,6 +36,7 @@ using namespace std; | @@ -36,6 +36,7 @@ using namespace std; | ||
| 36 | #include <srs_app_socket.hpp> | 36 | #include <srs_app_socket.hpp> |
| 37 | #include <srs_app_http.hpp> | 37 | #include <srs_app_http.hpp> |
| 38 | #include <srs_app_json.hpp> | 38 | #include <srs_app_json.hpp> |
| 39 | +#include <srs_app_dvr.hpp> | ||
| 39 | 40 | ||
| 40 | #define SRS_HTTP_RESPONSE_OK "0" | 41 | #define SRS_HTTP_RESPONSE_OK "0" |
| 41 | 42 | ||
| @@ -194,14 +195,6 @@ int SrsHttpHooks::on_connect(string url, int client_id, string ip, SrsRequest* r | @@ -194,14 +195,6 @@ int SrsHttpHooks::on_connect(string url, int client_id, string ip, SrsRequest* r | ||
| 194 | return ret; | 195 | return ret; |
| 195 | } | 196 | } |
| 196 | 197 | ||
| 197 | - /** | ||
| 198 | - { | ||
| 199 | - "action": "on_connect", | ||
| 200 | - "client_id": 1985, | ||
| 201 | - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", | ||
| 202 | - "pageUrl": "http://www.test.com/live.html" | ||
| 203 | - } | ||
| 204 | - */ | ||
| 205 | std::stringstream ss; | 198 | std::stringstream ss; |
| 206 | ss << JOBJECT_START | 199 | ss << JOBJECT_START |
| 207 | << JFIELD_STR("action", "on_connect") << JFIELD_CONT | 200 | << JFIELD_STR("action", "on_connect") << JFIELD_CONT |
| @@ -247,14 +240,6 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re | @@ -247,14 +240,6 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re | ||
| 247 | return; | 240 | return; |
| 248 | } | 241 | } |
| 249 | 242 | ||
| 250 | - /** | ||
| 251 | - { | ||
| 252 | - "action": "on_close", | ||
| 253 | - "client_id": 1985, | ||
| 254 | - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", | ||
| 255 | - "stream": "livestream" | ||
| 256 | - } | ||
| 257 | - */ | ||
| 258 | std::stringstream ss; | 243 | std::stringstream ss; |
| 259 | ss << JOBJECT_START | 244 | ss << JOBJECT_START |
| 260 | << JFIELD_STR("action", "on_close") << JFIELD_CONT | 245 | << JFIELD_STR("action", "on_close") << JFIELD_CONT |
| @@ -300,14 +285,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r | @@ -300,14 +285,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r | ||
| 300 | return ret; | 285 | return ret; |
| 301 | } | 286 | } |
| 302 | 287 | ||
| 303 | - /** | ||
| 304 | - { | ||
| 305 | - "action": "on_publish", | ||
| 306 | - "client_id": 1985, | ||
| 307 | - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", | ||
| 308 | - "stream": "livestream" | ||
| 309 | - } | ||
| 310 | - */ | ||
| 311 | std::stringstream ss; | 288 | std::stringstream ss; |
| 312 | ss << JOBJECT_START | 289 | ss << JOBJECT_START |
| 313 | << JFIELD_STR("action", "on_publish") << JFIELD_CONT | 290 | << JFIELD_STR("action", "on_publish") << JFIELD_CONT |
| @@ -354,14 +331,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest | @@ -354,14 +331,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest | ||
| 354 | return; | 331 | return; |
| 355 | } | 332 | } |
| 356 | 333 | ||
| 357 | - /** | ||
| 358 | - { | ||
| 359 | - "action": "on_unpublish", | ||
| 360 | - "client_id": 1985, | ||
| 361 | - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", | ||
| 362 | - "stream": "livestream" | ||
| 363 | - } | ||
| 364 | - */ | ||
| 365 | std::stringstream ss; | 334 | std::stringstream ss; |
| 366 | ss << JOBJECT_START | 335 | ss << JOBJECT_START |
| 367 | << JFIELD_STR("action", "on_unpublish") << JFIELD_CONT | 336 | << JFIELD_STR("action", "on_unpublish") << JFIELD_CONT |
| @@ -408,14 +377,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req) | @@ -408,14 +377,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req) | ||
| 408 | return ret; | 377 | return ret; |
| 409 | } | 378 | } |
| 410 | 379 | ||
| 411 | - /** | ||
| 412 | - { | ||
| 413 | - "action": "on_play", | ||
| 414 | - "client_id": 1985, | ||
| 415 | - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", | ||
| 416 | - "stream": "livestream" | ||
| 417 | - } | ||
| 418 | - */ | ||
| 419 | std::stringstream ss; | 380 | std::stringstream ss; |
| 420 | ss << JOBJECT_START | 381 | ss << JOBJECT_START |
| 421 | << JFIELD_STR("action", "on_play") << JFIELD_CONT | 382 | << JFIELD_STR("action", "on_play") << JFIELD_CONT |
| @@ -462,14 +423,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req | @@ -462,14 +423,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req | ||
| 462 | return; | 423 | return; |
| 463 | } | 424 | } |
| 464 | 425 | ||
| 465 | - /** | ||
| 466 | - { | ||
| 467 | - "action": "on_stop", | ||
| 468 | - "client_id": 1985, | ||
| 469 | - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", | ||
| 470 | - "stream": "livestream" | ||
| 471 | - } | ||
| 472 | - */ | ||
| 473 | std::stringstream ss; | 426 | std::stringstream ss; |
| 474 | ss << JOBJECT_START | 427 | ss << JOBJECT_START |
| 475 | << JFIELD_STR("action", "on_stop") << JFIELD_CONT | 428 | << JFIELD_STR("action", "on_stop") << JFIELD_CONT |
| @@ -505,10 +458,15 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req | @@ -505,10 +458,15 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req | ||
| 505 | return; | 458 | return; |
| 506 | } | 459 | } |
| 507 | 460 | ||
| 508 | -void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req) | 461 | +void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* segment) |
| 509 | { | 462 | { |
| 510 | int ret = ERROR_SUCCESS; | 463 | int ret = ERROR_SUCCESS; |
| 511 | 464 | ||
| 465 | + srs_trace("flv segment %s, atc_start=%"PRId64", " | ||
| 466 | + "has_key=%d, starttime=%"PRId64", duration=%d", | ||
| 467 | + segment->current_flv_path.c_str(), segment->stream_starttime, | ||
| 468 | + segment->segment_has_keyframe, segment->starttime, (int)segment->duration); | ||
| 469 | + | ||
| 512 | SrsHttpUri uri; | 470 | SrsHttpUri uri; |
| 513 | if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { | 471 | if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { |
| 514 | srs_warn("http uri parse on_dvr_keyframe url failed, ignored. " | 472 | srs_warn("http uri parse on_dvr_keyframe url failed, ignored. " |
| @@ -516,13 +474,6 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req) | @@ -516,13 +474,6 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req) | ||
| 516 | return; | 474 | return; |
| 517 | } | 475 | } |
| 518 | 476 | ||
| 519 | - /** | ||
| 520 | - { | ||
| 521 | - "action": "on_dvr_keyframe", | ||
| 522 | - "vhost": "video.test.com", "app": "live", | ||
| 523 | - "stream": "livestream" | ||
| 524 | - } | ||
| 525 | - */ | ||
| 526 | std::stringstream ss; | 477 | std::stringstream ss; |
| 527 | ss << JOBJECT_START | 478 | ss << JOBJECT_START |
| 528 | << JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT | 479 | << JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT |
| @@ -37,6 +37,7 @@ class SrsHttpUri; | @@ -37,6 +37,7 @@ class SrsHttpUri; | ||
| 37 | class SrsSocket; | 37 | class SrsSocket; |
| 38 | class SrsRequest; | 38 | class SrsRequest; |
| 39 | class SrsHttpParser; | 39 | class SrsHttpParser; |
| 40 | +class SrsFlvSegment; | ||
| 40 | 41 | ||
| 41 | #include <srs_app_st.hpp> | 42 | #include <srs_app_st.hpp> |
| 42 | 43 | ||
| @@ -126,8 +127,9 @@ public: | @@ -126,8 +127,9 @@ public: | ||
| 126 | * on_dvr_keyframe hook, when dvr get keyframe. | 127 | * on_dvr_keyframe hook, when dvr get keyframe. |
| 127 | * @param url the api server url, to process the event. | 128 | * @param url the api server url, to process the event. |
| 128 | * ignore if empty. | 129 | * ignore if empty. |
| 130 | + * @param segment the current flv segment. | ||
| 129 | */ | 131 | */ |
| 130 | - static void on_dvr_keyframe(std::string url, SrsRequest* req); | 132 | + static void on_dvr_keyframe(std::string url, SrsRequest* req, SrsFlvSegment* segment); |
| 131 | }; | 133 | }; |
| 132 | 134 | ||
| 133 | #endif | 135 | #endif |
-
请 注册 或 登录 后发表评论