for #179, refine dvr, support callback when reap dvr segment.
正在显示
9 个修改的文件
包含
281 行增加
和
50 行删除
| @@ -297,7 +297,8 @@ vhost dvr.srs.com { | @@ -297,7 +297,8 @@ vhost dvr.srs.com { | ||
| 297 | # vhost, query all dvr of this vhost. | 297 | # vhost, query all dvr of this vhost. |
| 298 | # response in json, where: | 298 | # response in json, where: |
| 299 | # {code:0, dvrs: [{path_tmpl:"./[15].[04].[05].[999].flv", path_dvr:"./22.7.43.312.flv", | 299 | # {code:0, dvrs: [{path_tmpl:"./[15].[04].[05].[999].flv", path_dvr:"./22.7.43.312.flv", |
| 300 | - # wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback" | 300 | + # wait_keyframe:true, vhost:"__defaultVhost", callback:"http://127.0.0.1:8085/api/v1/dvrs", |
| 301 | + # status:"stop"|"start" | ||
| 301 | # }]} | 302 | # }]} |
| 302 | # method=POST | 303 | # method=POST |
| 303 | # to start dvr of specified vhost. | 304 | # to start dvr of specified vhost. |
| @@ -313,6 +314,8 @@ vhost dvr.srs.com { | @@ -313,6 +314,8 @@ vhost dvr.srs.com { | ||
| 313 | # vhost, stop all dvr of this vhost. | 314 | # vhost, stop all dvr of this vhost. |
| 314 | # response in json, where: | 315 | # response in json, where: |
| 315 | # {code:0} | 316 | # {code:0} |
| 317 | + # when reap segment, the callback POST request in json: | ||
| 318 | + # {action:"on_dvr_reap_segment"} | ||
| 316 | # default: session | 319 | # default: session |
| 317 | dvr_plan session; | 320 | dvr_plan session; |
| 318 | # the dvr output path. | 321 | # the dvr output path. |
| @@ -253,7 +253,7 @@ class RESTDvrs(object): | @@ -253,7 +253,7 @@ class RESTDvrs(object): | ||
| 253 | return json.dumps(dvrs) | 253 | return json.dumps(dvrs) |
| 254 | 254 | ||
| 255 | ''' | 255 | ''' |
| 256 | - for SRS hook: on_dvr | 256 | + for SRS hook: on_dvr, on_dvr_reap_segment |
| 257 | on_dvr: | 257 | on_dvr: |
| 258 | when srs reap a dvr file, call the hook, | 258 | when srs reap a dvr file, call the hook, |
| 259 | the request in the POST data string is a object encode by json: | 259 | the request in the POST data string is a object encode by json: |
| @@ -265,6 +265,17 @@ class RESTDvrs(object): | @@ -265,6 +265,17 @@ class RESTDvrs(object): | ||
| 265 | "cwd": "/usr/local/srs", | 265 | "cwd": "/usr/local/srs", |
| 266 | "file": "./objs/nginx/html/live/livestream.1420254068776.flv" | 266 | "file": "./objs/nginx/html/live/livestream.1420254068776.flv" |
| 267 | } | 267 | } |
| 268 | + on_dvr_reap_segment: | ||
| 269 | + when api dvr specifes the callback when reap flv segment, call the hook, | ||
| 270 | + the request in the POST data string is a object encode by json: | ||
| 271 | + { | ||
| 272 | + "action": "on_dvr_reap_segment", | ||
| 273 | + "client_id": 1985, | ||
| 274 | + "vhost": "video.test.com", "app": "live", | ||
| 275 | + "stream": "livestream", | ||
| 276 | + "cwd": "/usr/local/srs", | ||
| 277 | + "file": "./objs/nginx/html/live/livestream.1420254068776.flv" | ||
| 278 | + } | ||
| 268 | if valid, the hook must return HTTP code 200(Stauts OK) and response | 279 | if valid, the hook must return HTTP code 200(Stauts OK) and response |
| 269 | an int value specifies the error code(0 corresponding to success): | 280 | an int value specifies the error code(0 corresponding to success): |
| 270 | 0 | 281 | 0 |
| @@ -287,6 +298,8 @@ class RESTDvrs(object): | @@ -287,6 +298,8 @@ class RESTDvrs(object): | ||
| 287 | action = json_req["action"] | 298 | action = json_req["action"] |
| 288 | if action == "on_dvr": | 299 | if action == "on_dvr": |
| 289 | code = self.__on_dvr(json_req) | 300 | code = self.__on_dvr(json_req) |
| 301 | + if action == "on_dvr_reap_segment": | ||
| 302 | + code = self.__on_dvr_reap_segment(json_req) | ||
| 290 | else: | 303 | else: |
| 291 | trace("invalid request action: %s"%(json_req["action"])) | 304 | trace("invalid request action: %s"%(json_req["action"])) |
| 292 | code = Error.request_invalid_action | 305 | code = Error.request_invalid_action |
| @@ -308,6 +321,18 @@ class RESTDvrs(object): | @@ -308,6 +321,18 @@ class RESTDvrs(object): | ||
| 308 | 321 | ||
| 309 | return code | 322 | return code |
| 310 | 323 | ||
| 324 | + def __on_dvr_reap_segment(self, req): | ||
| 325 | + code = Error.success | ||
| 326 | + | ||
| 327 | + trace("srs %s: client id=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%( | ||
| 328 | + req["action"], req["client_id"], req["vhost"], req["app"], req["stream"], | ||
| 329 | + req["cwd"], req["file"] | ||
| 330 | + )) | ||
| 331 | + | ||
| 332 | + # TODO: process the on_dvr event | ||
| 333 | + | ||
| 334 | + return code | ||
| 335 | + | ||
| 311 | ''' | 336 | ''' |
| 312 | handle the sessions requests: client play/stop stream | 337 | handle the sessions requests: client play/stop stream |
| 313 | ''' | 338 | ''' |
| @@ -3342,6 +3342,13 @@ bool SrsConfig::get_dvr_enabled(string vhost) | @@ -3342,6 +3342,13 @@ bool SrsConfig::get_dvr_enabled(string vhost) | ||
| 3342 | return false; | 3342 | return false; |
| 3343 | } | 3343 | } |
| 3344 | 3344 | ||
| 3345 | +void SrsConfig::set_dvr_enabled(string vhost, bool enabled) | ||
| 3346 | +{ | ||
| 3347 | + SrsConfDirective* conf = create_directive(vhost, "dvr", "enabled"); | ||
| 3348 | + conf->args.clear(); | ||
| 3349 | + conf->args.push_back(enabled? "on":"off"); | ||
| 3350 | +} | ||
| 3351 | + | ||
| 3345 | string SrsConfig::get_dvr_path(string vhost) | 3352 | string SrsConfig::get_dvr_path(string vhost) |
| 3346 | { | 3353 | { |
| 3347 | SrsConfDirective* dvr = get_dvr(vhost); | 3354 | SrsConfDirective* dvr = get_dvr(vhost); |
| @@ -923,6 +923,7 @@ public: | @@ -923,6 +923,7 @@ public: | ||
| 923 | * whether dvr is enabled. | 923 | * whether dvr is enabled. |
| 924 | */ | 924 | */ |
| 925 | virtual bool get_dvr_enabled(std::string vhost); | 925 | virtual bool get_dvr_enabled(std::string vhost); |
| 926 | + virtual void set_dvr_enabled(std::string vhost, bool enabled); | ||
| 926 | /** | 927 | /** |
| 927 | * get the dvr path, the flv file to save in. | 928 | * get the dvr path, the flv file to save in. |
| 928 | */ | 929 | */ |
| @@ -144,15 +144,15 @@ int SrsFlvSegment::open(bool use_tmp_file) | @@ -144,15 +144,15 @@ int SrsFlvSegment::open(bool use_tmp_file) | ||
| 144 | return ret; | 144 | return ret; |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | + | ||
| 148 | + // initialize the encoder. | ||
| 149 | + if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) { | ||
| 150 | + srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret); | ||
| 151 | + return ret; | ||
| 152 | + } | ||
| 147 | 153 | ||
| 148 | // when exists, donot write flv header. | 154 | // when exists, donot write flv header. |
| 149 | if (fresh_flv_file) { | 155 | if (fresh_flv_file) { |
| 150 | - // initialize the encoder. | ||
| 151 | - if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) { | ||
| 152 | - srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret); | ||
| 153 | - return ret; | ||
| 154 | - } | ||
| 155 | - | ||
| 156 | // write the flv header to writer. | 156 | // write the flv header to writer. |
| 157 | if ((ret = enc->write_header()) != ERROR_SUCCESS) { | 157 | if ((ret = enc->write_header()) != ERROR_SUCCESS) { |
| 158 | srs_error("write flv header failed. ret=%d", ret); | 158 | srs_error("write flv header failed. ret=%d", ret); |
| @@ -195,6 +195,8 @@ int SrsFlvSegment::close() | @@ -195,6 +195,8 @@ int SrsFlvSegment::close() | ||
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | + // TODO: FIXME: the http callback is async, which will trigger thread switch, | ||
| 199 | + // so the on_video maybe invoked during the http callback, and error. | ||
| 198 | if ((ret = plan->on_reap_segment()) != ERROR_SUCCESS) { | 200 | if ((ret = plan->on_reap_segment()) != ERROR_SUCCESS) { |
| 199 | srs_error("dvr: notify plan to reap segment failed. ret=%d", ret); | 201 | srs_error("dvr: notify plan to reap segment failed. ret=%d", ret); |
| 200 | return ret; | 202 | return ret; |
| @@ -743,10 +745,15 @@ SrsDvrApiPlan::SrsDvrApiPlan() | @@ -743,10 +745,15 @@ SrsDvrApiPlan::SrsDvrApiPlan() | ||
| 743 | { | 745 | { |
| 744 | autostart = false; | 746 | autostart = false; |
| 745 | started = false; | 747 | started = false; |
| 748 | + | ||
| 749 | + metadata = sh_audio = sh_video = NULL; | ||
| 746 | } | 750 | } |
| 747 | 751 | ||
| 748 | SrsDvrApiPlan::~SrsDvrApiPlan() | 752 | SrsDvrApiPlan::~SrsDvrApiPlan() |
| 749 | { | 753 | { |
| 754 | + srs_freep(metadata); | ||
| 755 | + srs_freep(sh_audio); | ||
| 756 | + srs_freep(sh_video); | ||
| 750 | } | 757 | } |
| 751 | 758 | ||
| 752 | int SrsDvrApiPlan::initialize(SrsSource* s, SrsRequest* r) | 759 | int SrsDvrApiPlan::initialize(SrsSource* s, SrsRequest* r) |
| @@ -787,6 +794,8 @@ int SrsDvrApiPlan::on_publish() | @@ -787,6 +794,8 @@ int SrsDvrApiPlan::on_publish() | ||
| 787 | return ret; | 794 | return ret; |
| 788 | } | 795 | } |
| 789 | 796 | ||
| 797 | + dvr_enabled = true; | ||
| 798 | + | ||
| 790 | if ((ret = segment->close()) != ERROR_SUCCESS) { | 799 | if ((ret = segment->close()) != ERROR_SUCCESS) { |
| 791 | return ret; | 800 | return ret; |
| 792 | } | 801 | } |
| @@ -794,8 +803,17 @@ int SrsDvrApiPlan::on_publish() | @@ -794,8 +803,17 @@ int SrsDvrApiPlan::on_publish() | ||
| 794 | if ((ret = segment->open()) != ERROR_SUCCESS) { | 803 | if ((ret = segment->open()) != ERROR_SUCCESS) { |
| 795 | return ret; | 804 | return ret; |
| 796 | } | 805 | } |
| 797 | - | ||
| 798 | - dvr_enabled = true; | 806 | + |
| 807 | + // update sequence header | ||
| 808 | + if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) { | ||
| 809 | + return ret; | ||
| 810 | + } | ||
| 811 | + if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) { | ||
| 812 | + return ret; | ||
| 813 | + } | ||
| 814 | + if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) { | ||
| 815 | + return ret; | ||
| 816 | + } | ||
| 799 | 817 | ||
| 800 | return ret; | 818 | return ret; |
| 801 | } | 819 | } |
| @@ -804,6 +822,48 @@ void SrsDvrApiPlan::on_unpublish() | @@ -804,6 +822,48 @@ void SrsDvrApiPlan::on_unpublish() | ||
| 804 | { | 822 | { |
| 805 | } | 823 | } |
| 806 | 824 | ||
| 825 | +int SrsDvrApiPlan::on_meta_data(SrsSharedPtrMessage* __metadata) | ||
| 826 | +{ | ||
| 827 | + int ret = ERROR_SUCCESS; | ||
| 828 | + | ||
| 829 | + srs_freep(metadata); | ||
| 830 | + metadata = __metadata->copy(); | ||
| 831 | + | ||
| 832 | + return ret; | ||
| 833 | +} | ||
| 834 | + | ||
| 835 | +int SrsDvrApiPlan::on_audio(SrsSharedPtrMessage* __audio) | ||
| 836 | +{ | ||
| 837 | + int ret = ERROR_SUCCESS; | ||
| 838 | + | ||
| 839 | + if (SrsFlvCodec::audio_is_sequence_header(__audio->payload, __audio->size)) { | ||
| 840 | + srs_freep(sh_audio); | ||
| 841 | + sh_audio = __audio->copy(); | ||
| 842 | + } | ||
| 843 | + | ||
| 844 | + if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) { | ||
| 845 | + return ret; | ||
| 846 | + } | ||
| 847 | + | ||
| 848 | + return ret; | ||
| 849 | +} | ||
| 850 | + | ||
| 851 | +int SrsDvrApiPlan::on_video(SrsSharedPtrMessage* __video) | ||
| 852 | +{ | ||
| 853 | + int ret = ERROR_SUCCESS; | ||
| 854 | + | ||
| 855 | + if (SrsFlvCodec::video_is_sequence_header(__video->payload, __video->size)) { | ||
| 856 | + srs_freep(sh_video); | ||
| 857 | + sh_video = __video->copy(); | ||
| 858 | + } | ||
| 859 | + | ||
| 860 | + if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) { | ||
| 861 | + return ret; | ||
| 862 | + } | ||
| 863 | + | ||
| 864 | + return ret; | ||
| 865 | +} | ||
| 866 | + | ||
| 807 | int SrsDvrApiPlan::set_path_tmpl(string path_tmpl) | 867 | int SrsDvrApiPlan::set_path_tmpl(string path_tmpl) |
| 808 | { | 868 | { |
| 809 | _srs_config->set_dvr_path(req->vhost, path_tmpl); | 869 | _srs_config->set_dvr_path(req->vhost, path_tmpl); |
| @@ -830,6 +890,9 @@ int SrsDvrApiPlan::start() | @@ -830,6 +890,9 @@ int SrsDvrApiPlan::start() | ||
| 830 | return ret; | 890 | return ret; |
| 831 | } | 891 | } |
| 832 | 892 | ||
| 893 | + // enable the config. | ||
| 894 | + _srs_config->set_dvr_enabled(req->vhost, true); | ||
| 895 | + | ||
| 833 | // stop dvr | 896 | // stop dvr |
| 834 | if (dvr_enabled) { | 897 | if (dvr_enabled) { |
| 835 | // ignore error. | 898 | // ignore error. |
| @@ -862,16 +925,58 @@ int SrsDvrApiPlan::dumps(stringstream& ss) | @@ -862,16 +925,58 @@ int SrsDvrApiPlan::dumps(stringstream& ss) | ||
| 862 | << __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT | 925 | << __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT |
| 863 | << __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT | 926 | << __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT |
| 864 | << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT | 927 | << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT |
| 865 | - << __SRS_JFIELD_STR("callback", callback) | 928 | + << __SRS_JFIELD_STR("callback", callback) << __SRS_JFIELD_CONT |
| 929 | + << __SRS_JFIELD_STR("status", (dvr_enabled? "start":"stop")) | ||
| 866 | << __SRS_JOBJECT_END; | 930 | << __SRS_JOBJECT_END; |
| 867 | 931 | ||
| 868 | return ret; | 932 | return ret; |
| 869 | } | 933 | } |
| 870 | 934 | ||
| 935 | +int SrsDvrApiPlan::stop() | ||
| 936 | +{ | ||
| 937 | + int ret = ERROR_SUCCESS; | ||
| 938 | + | ||
| 939 | + _srs_config->set_dvr_enabled(req->vhost, false); | ||
| 940 | + started = false; | ||
| 941 | + | ||
| 942 | + // stop dvr | ||
| 943 | + if (dvr_enabled) { | ||
| 944 | + // ignore error. | ||
| 945 | + int ret = segment->close(); | ||
| 946 | + if (ret != ERROR_SUCCESS) { | ||
| 947 | + srs_warn("ignore flv close error. ret=%d", ret); | ||
| 948 | + } | ||
| 949 | + | ||
| 950 | + dvr_enabled = false; | ||
| 951 | + } | ||
| 952 | + | ||
| 953 | + srs_trace("dvr: stop dvr of vhost=%s", req->vhost.c_str()); | ||
| 954 | + | ||
| 955 | + return ret; | ||
| 956 | +} | ||
| 957 | + | ||
| 871 | int SrsDvrApiPlan::on_reap_segment() | 958 | int SrsDvrApiPlan::on_reap_segment() |
| 872 | { | 959 | { |
| 873 | - // TODO: FIXME: implements it. | ||
| 874 | - return ERROR_SUCCESS; | 960 | + int ret = ERROR_SUCCESS; |
| 961 | + | ||
| 962 | +#ifdef SRS_AUTO_HTTP_CALLBACK | ||
| 963 | + // HTTP: callback | ||
| 964 | + if (callback.empty()) { | ||
| 965 | + srs_warn("dvr: ignore for callback empty, vhost=%s", req->vhost.c_str()); | ||
| 966 | + return ret; | ||
| 967 | + } | ||
| 968 | + | ||
| 969 | + int connection_id = _srs_context->get_id(); | ||
| 970 | + std::string cwd = _srs_config->cwd(); | ||
| 971 | + std::string file = segment->get_path(); | ||
| 972 | + std::string url = callback; | ||
| 973 | + if ((ret = SrsHttpHooks::on_dvr_reap_segment(url, connection_id, req, cwd, file)) != ERROR_SUCCESS) { | ||
| 974 | + srs_error("hook client on_dvr_reap_segment failed. url=%s, ret=%d", url.c_str(), ret); | ||
| 975 | + return ret; | ||
| 976 | + } | ||
| 977 | +#endif | ||
| 978 | + | ||
| 979 | + return ret; | ||
| 875 | } | 980 | } |
| 876 | 981 | ||
| 877 | SrsDvrAppendPlan::SrsDvrAppendPlan() | 982 | SrsDvrAppendPlan::SrsDvrAppendPlan() |
| @@ -909,30 +1014,30 @@ void SrsDvrAppendPlan::on_unpublish() | @@ -909,30 +1014,30 @@ void SrsDvrAppendPlan::on_unpublish() | ||
| 909 | { | 1014 | { |
| 910 | } | 1015 | } |
| 911 | 1016 | ||
| 912 | -int SrsDvrAppendPlan::on_audio(SrsSharedPtrMessage* audio) | 1017 | +int SrsDvrAppendPlan::on_audio(SrsSharedPtrMessage* __audio) |
| 913 | { | 1018 | { |
| 914 | int ret = ERROR_SUCCESS; | 1019 | int ret = ERROR_SUCCESS; |
| 915 | 1020 | ||
| 916 | - if ((ret = update_duration(audio)) != ERROR_SUCCESS) { | 1021 | + if ((ret = update_duration(__audio)) != ERROR_SUCCESS) { |
| 917 | return ret; | 1022 | return ret; |
| 918 | } | 1023 | } |
| 919 | 1024 | ||
| 920 | - if ((ret = SrsDvrPlan::on_audio(audio)) != ERROR_SUCCESS) { | 1025 | + if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) { |
| 921 | return ret; | 1026 | return ret; |
| 922 | } | 1027 | } |
| 923 | 1028 | ||
| 924 | return ret; | 1029 | return ret; |
| 925 | } | 1030 | } |
| 926 | 1031 | ||
| 927 | -int SrsDvrAppendPlan::on_video(SrsSharedPtrMessage* video) | 1032 | +int SrsDvrAppendPlan::on_video(SrsSharedPtrMessage* __video) |
| 928 | { | 1033 | { |
| 929 | int ret = ERROR_SUCCESS; | 1034 | int ret = ERROR_SUCCESS; |
| 930 | 1035 | ||
| 931 | - if ((ret = update_duration(video)) != ERROR_SUCCESS) { | 1036 | + if ((ret = update_duration(__video)) != ERROR_SUCCESS) { |
| 932 | return ret; | 1037 | return ret; |
| 933 | } | 1038 | } |
| 934 | 1039 | ||
| 935 | - if ((ret = SrsDvrPlan::on_video(video)) != ERROR_SUCCESS) { | 1040 | + if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) { |
| 936 | return ret; | 1041 | return ret; |
| 937 | } | 1042 | } |
| 938 | 1043 | ||
| @@ -1038,40 +1143,40 @@ int SrsDvrSegmentPlan::on_meta_data(SrsSharedPtrMessage* __metadata) | @@ -1038,40 +1143,40 @@ int SrsDvrSegmentPlan::on_meta_data(SrsSharedPtrMessage* __metadata) | ||
| 1038 | return ret; | 1143 | return ret; |
| 1039 | } | 1144 | } |
| 1040 | 1145 | ||
| 1041 | -int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* audio) | 1146 | +int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* __audio) |
| 1042 | { | 1147 | { |
| 1043 | int ret = ERROR_SUCCESS; | 1148 | int ret = ERROR_SUCCESS; |
| 1044 | 1149 | ||
| 1045 | - if (SrsFlvCodec::audio_is_sequence_header(audio->payload, audio->size)) { | 1150 | + if (SrsFlvCodec::audio_is_sequence_header(__audio->payload, __audio->size)) { |
| 1046 | srs_freep(sh_audio); | 1151 | srs_freep(sh_audio); |
| 1047 | - sh_audio = audio->copy(); | 1152 | + sh_audio = __audio->copy(); |
| 1048 | } | 1153 | } |
| 1049 | 1154 | ||
| 1050 | - if ((ret = update_duration(audio)) != ERROR_SUCCESS) { | 1155 | + if ((ret = update_duration(__audio)) != ERROR_SUCCESS) { |
| 1051 | return ret; | 1156 | return ret; |
| 1052 | } | 1157 | } |
| 1053 | 1158 | ||
| 1054 | - if ((ret = SrsDvrPlan::on_audio(audio)) != ERROR_SUCCESS) { | 1159 | + if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) { |
| 1055 | return ret; | 1160 | return ret; |
| 1056 | } | 1161 | } |
| 1057 | 1162 | ||
| 1058 | return ret; | 1163 | return ret; |
| 1059 | } | 1164 | } |
| 1060 | 1165 | ||
| 1061 | -int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* video) | 1166 | +int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* __video) |
| 1062 | { | 1167 | { |
| 1063 | int ret = ERROR_SUCCESS; | 1168 | int ret = ERROR_SUCCESS; |
| 1064 | 1169 | ||
| 1065 | - if (SrsFlvCodec::video_is_sequence_header(video->payload, video->size)) { | 1170 | + if (SrsFlvCodec::video_is_sequence_header(__video->payload, __video->size)) { |
| 1066 | srs_freep(sh_video); | 1171 | srs_freep(sh_video); |
| 1067 | - sh_video = video->copy(); | 1172 | + sh_video = __video->copy(); |
| 1068 | } | 1173 | } |
| 1069 | 1174 | ||
| 1070 | - if ((ret = update_duration(video)) != ERROR_SUCCESS) { | 1175 | + if ((ret = update_duration(__video)) != ERROR_SUCCESS) { |
| 1071 | return ret; | 1176 | return ret; |
| 1072 | } | 1177 | } |
| 1073 | 1178 | ||
| 1074 | - if ((ret = SrsDvrPlan::on_video(video)) != ERROR_SUCCESS) { | 1179 | + if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) { |
| 1075 | return ret; | 1180 | return ret; |
| 1076 | } | 1181 | } |
| 1077 | 1182 | ||
| @@ -1240,6 +1345,30 @@ int SrsApiDvrPool::create(SrsJsonAny* json) | @@ -1240,6 +1345,30 @@ int SrsApiDvrPool::create(SrsJsonAny* json) | ||
| 1240 | return dvr->start(); | 1345 | return dvr->start(); |
| 1241 | } | 1346 | } |
| 1242 | 1347 | ||
| 1348 | +int SrsApiDvrPool::stop(string vhost) | ||
| 1349 | +{ | ||
| 1350 | + int ret = ERROR_SUCCESS; | ||
| 1351 | + | ||
| 1352 | + std::vector<SrsDvrApiPlan*> plans; | ||
| 1353 | + for (int i = 0; i < (int)dvrs.size(); i++) { | ||
| 1354 | + SrsDvrApiPlan* plan = dvrs.at(i); | ||
| 1355 | + if (!vhost.empty() && plan->req->vhost != vhost) { | ||
| 1356 | + continue; | ||
| 1357 | + } | ||
| 1358 | + plans.push_back(plan); | ||
| 1359 | + } | ||
| 1360 | + | ||
| 1361 | + for (int i = 0; i < (int)plans.size(); i++) { | ||
| 1362 | + SrsDvrApiPlan* plan = plans.at(i); | ||
| 1363 | + | ||
| 1364 | + if ((ret = plan->stop()) != ERROR_SUCCESS) { | ||
| 1365 | + return ret; | ||
| 1366 | + } | ||
| 1367 | + } | ||
| 1368 | + | ||
| 1369 | + return ret; | ||
| 1370 | +} | ||
| 1371 | + | ||
| 1243 | SrsDvr::SrsDvr(SrsSource* s) | 1372 | SrsDvr::SrsDvr(SrsSource* s) |
| 1244 | { | 1373 | { |
| 1245 | source = s; | 1374 | source = s; |
| @@ -237,6 +237,11 @@ public: | @@ -237,6 +237,11 @@ public: | ||
| 237 | class SrsDvrApiPlan : public SrsDvrPlan | 237 | class SrsDvrApiPlan : public SrsDvrPlan |
| 238 | { | 238 | { |
| 239 | private: | 239 | private: |
| 240 | + // cache the metadata and sequence header, for new segment maybe opened. | ||
| 241 | + SrsSharedPtrMessage* sh_audio; | ||
| 242 | + SrsSharedPtrMessage* sh_video; | ||
| 243 | + SrsSharedPtrMessage* metadata; | ||
| 244 | +private: | ||
| 240 | std::string callback; | 245 | std::string callback; |
| 241 | bool autostart; | 246 | bool autostart; |
| 242 | bool started; | 247 | bool started; |
| @@ -247,12 +252,16 @@ public: | @@ -247,12 +252,16 @@ public: | ||
| 247 | virtual int initialize(SrsSource* s, SrsRequest* r); | 252 | virtual int initialize(SrsSource* s, SrsRequest* r); |
| 248 | virtual int on_publish(); | 253 | virtual int on_publish(); |
| 249 | virtual void on_unpublish(); | 254 | virtual void on_unpublish(); |
| 255 | + virtual int on_meta_data(SrsSharedPtrMessage* __metadata); | ||
| 256 | + virtual int on_audio(SrsSharedPtrMessage* __audio); | ||
| 257 | + virtual int on_video(SrsSharedPtrMessage* __video); | ||
| 250 | public: | 258 | public: |
| 251 | virtual int set_path_tmpl(std::string path_tmpl); | 259 | virtual int set_path_tmpl(std::string path_tmpl); |
| 252 | virtual int set_callback(std::string value); | 260 | virtual int set_callback(std::string value); |
| 253 | virtual int set_wait_keyframe(bool wait_keyframe); | 261 | virtual int set_wait_keyframe(bool wait_keyframe); |
| 254 | virtual int start(); | 262 | virtual int start(); |
| 255 | virtual int dumps(std::stringstream& ss); | 263 | virtual int dumps(std::stringstream& ss); |
| 264 | + virtual int stop(); | ||
| 256 | protected: | 265 | protected: |
| 257 | virtual int on_reap_segment(); | 266 | virtual int on_reap_segment(); |
| 258 | }; | 267 | }; |
| @@ -270,14 +279,8 @@ public: | @@ -270,14 +279,8 @@ public: | ||
| 270 | public: | 279 | public: |
| 271 | virtual int on_publish(); | 280 | virtual int on_publish(); |
| 272 | virtual void on_unpublish(); | 281 | virtual void on_unpublish(); |
| 273 | - /** | ||
| 274 | - * @param audio, directly ptr, copy it if need to save it. | ||
| 275 | - */ | ||
| 276 | - virtual int on_audio(SrsSharedPtrMessage* audio); | ||
| 277 | - /** | ||
| 278 | - * @param video, directly ptr, copy it if need to save it. | ||
| 279 | - */ | ||
| 280 | - virtual int on_video(SrsSharedPtrMessage* video); | 282 | + virtual int on_audio(SrsSharedPtrMessage* __audio); |
| 283 | + virtual int on_video(SrsSharedPtrMessage* __video); | ||
| 281 | private: | 284 | private: |
| 282 | virtual int update_duration(SrsSharedPtrMessage* msg); | 285 | virtual int update_duration(SrsSharedPtrMessage* msg); |
| 283 | }; | 286 | }; |
| @@ -300,18 +303,9 @@ public: | @@ -300,18 +303,9 @@ public: | ||
| 300 | virtual int initialize(SrsSource* source, SrsRequest* req); | 303 | virtual int initialize(SrsSource* source, SrsRequest* req); |
| 301 | virtual int on_publish(); | 304 | virtual int on_publish(); |
| 302 | virtual void on_unpublish(); | 305 | virtual void on_unpublish(); |
| 303 | - /** | ||
| 304 | - * when got metadata. | ||
| 305 | - */ | ||
| 306 | virtual int on_meta_data(SrsSharedPtrMessage* __metadata); | 306 | virtual int on_meta_data(SrsSharedPtrMessage* __metadata); |
| 307 | - /** | ||
| 308 | - * @param audio, directly ptr, copy it if need to save it. | ||
| 309 | - */ | ||
| 310 | - virtual int on_audio(SrsSharedPtrMessage* audio); | ||
| 311 | - /** | ||
| 312 | - * @param video, directly ptr, copy it if need to save it. | ||
| 313 | - */ | ||
| 314 | - virtual int on_video(SrsSharedPtrMessage* video); | 307 | + virtual int on_audio(SrsSharedPtrMessage* __audio); |
| 308 | + virtual int on_video(SrsSharedPtrMessage* __video); | ||
| 315 | private: | 309 | private: |
| 316 | virtual int update_duration(SrsSharedPtrMessage* msg); | 310 | virtual int update_duration(SrsSharedPtrMessage* msg); |
| 317 | }; | 311 | }; |
| @@ -334,6 +328,7 @@ public: | @@ -334,6 +328,7 @@ public: | ||
| 334 | public: | 328 | public: |
| 335 | virtual int dumps(std::string vhost, std::stringstream& ss); | 329 | virtual int dumps(std::string vhost, std::stringstream& ss); |
| 336 | virtual int create(SrsJsonAny* json); | 330 | virtual int create(SrsJsonAny* json); |
| 331 | + virtual int stop(std::string vhost); | ||
| 337 | }; | 332 | }; |
| 338 | 333 | ||
| 339 | /** | 334 | /** |
| @@ -501,8 +501,8 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | @@ -501,8 +501,8 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | ||
| 501 | << __SRS_JFIELD_ORG("dvrs", data.str()) | 501 | << __SRS_JFIELD_ORG("dvrs", data.str()) |
| 502 | << __SRS_JOBJECT_END; | 502 | << __SRS_JOBJECT_END; |
| 503 | } else if (r->is_http_post()) { | 503 | } else if (r->is_http_post()) { |
| 504 | - char* body = (char*)r->body().c_str(); | ||
| 505 | - SrsJsonAny* json = SrsJsonAny::loads(body); | 504 | + std::string body = r->body(); |
| 505 | + SrsJsonAny* json = SrsJsonAny::loads((char*)body.c_str()); | ||
| 506 | int ret = ERROR_SUCCESS; | 506 | int ret = ERROR_SUCCESS; |
| 507 | if (!json) { | 507 | if (!json) { |
| 508 | ret = ERROR_HTTP_JSON_REQUIRED; | 508 | ret = ERROR_HTTP_JSON_REQUIRED; |
| @@ -513,6 +513,12 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | @@ -513,6 +513,12 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | ||
| 513 | ss << __SRS_JOBJECT_START | 513 | ss << __SRS_JOBJECT_START |
| 514 | << __SRS_JFIELD_ERROR(ret) | 514 | << __SRS_JFIELD_ERROR(ret) |
| 515 | << __SRS_JOBJECT_END; | 515 | << __SRS_JOBJECT_END; |
| 516 | + } else if (r->is_http_delete()) { | ||
| 517 | + int ret = pool->stop(r->query_get("vhost")); | ||
| 518 | + | ||
| 519 | + ss << __SRS_JOBJECT_START | ||
| 520 | + << __SRS_JFIELD_ERROR(ret) | ||
| 521 | + << __SRS_JOBJECT_END; | ||
| 516 | } else { | 522 | } else { |
| 517 | ss << __SRS_JOBJECT_START | 523 | ss << __SRS_JOBJECT_START |
| 518 | << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST) | 524 | << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST) |
| @@ -436,4 +436,60 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req, | @@ -436,4 +436,60 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req, | ||
| 436 | return ret; | 436 | return ret; |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | +int SrsHttpHooks::on_dvr_reap_segment(string url, int client_id, SrsRequest* req, string cwd, string file) | ||
| 440 | +{ | ||
| 441 | + int ret = ERROR_SUCCESS; | ||
| 442 | + | ||
| 443 | + SrsHttpUri uri; | ||
| 444 | + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { | ||
| 445 | + srs_error("http uri parse on_dvr_reap_segment url failed, ignored. " | ||
| 446 | + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret); | ||
| 447 | + return ret; | ||
| 448 | + } | ||
| 449 | + | ||
| 450 | + std::stringstream ss; | ||
| 451 | + ss << __SRS_JOBJECT_START | ||
| 452 | + << __SRS_JFIELD_STR("action", "on_dvr_reap_segment") << __SRS_JFIELD_CONT | ||
| 453 | + << __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT | ||
| 454 | + << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT | ||
| 455 | + << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT | ||
| 456 | + << __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_CONT | ||
| 457 | + << __SRS_JFIELD_STR("cwd", cwd) << __SRS_JFIELD_CONT | ||
| 458 | + << __SRS_JFIELD_STR("file", file) | ||
| 459 | + << __SRS_JOBJECT_END; | ||
| 460 | + std::string data = ss.str(); | ||
| 461 | + std::string res; | ||
| 462 | + int status_code; | ||
| 463 | + | ||
| 464 | + SrsHttpClient http; | ||
| 465 | + if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) { | ||
| 466 | + srs_error("http post on_dvr_reap_segment uri failed, ignored. " | ||
| 467 | + "client_id=%d, url=%s, request=%s, response=%s, ret=%d", | ||
| 468 | + client_id, url.c_str(), data.c_str(), res.c_str(), ret); | ||
| 469 | + return ret; | ||
| 470 | + } | ||
| 471 | + | ||
| 472 | + // ensure the http status is ok. | ||
| 473 | + // https://github.com/winlinvip/simple-rtmp-server/issues/158 | ||
| 474 | + if (status_code != SRS_CONSTS_HTTP_OK) { | ||
| 475 | + ret = ERROR_HTTP_STATUS_INVLIAD; | ||
| 476 | + srs_error("http hook on_dvr_reap_segment status failed. " | ||
| 477 | + "client_id=%d, code=%d, ret=%d", client_id, status_code, ret); | ||
| 478 | + return ret; | ||
| 479 | + } | ||
| 480 | + | ||
| 481 | + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) { | ||
| 482 | + ret = ERROR_HTTP_DATA_INVLIAD; | ||
| 483 | + srs_warn("http hook on_dvr_reap_segment validate failed, ignored. " | ||
| 484 | + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret); | ||
| 485 | + return ret; | ||
| 486 | + } | ||
| 487 | + | ||
| 488 | + srs_trace("http hook on_dvr_reap_segment success. " | ||
| 489 | + "client_id=%d, url=%s, request=%s, response=%s, ret=%d", | ||
| 490 | + client_id, url.c_str(), data.c_str(), res.c_str(), ret); | ||
| 491 | + | ||
| 492 | + return ret; | ||
| 493 | +} | ||
| 494 | + | ||
| 439 | #endif | 495 | #endif |
| @@ -104,6 +104,15 @@ public: | @@ -104,6 +104,15 @@ public: | ||
| 104 | * @param file the file path, can be relative or absolute path. | 104 | * @param file the file path, can be relative or absolute path. |
| 105 | */ | 105 | */ |
| 106 | static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file); | 106 | static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file); |
| 107 | + /** | ||
| 108 | + * when dvr reap segment, callback. | ||
| 109 | + * @param client_id the id of client on server. | ||
| 110 | + * @param url the api server url, to process the event. | ||
| 111 | + * ignore if empty. | ||
| 112 | + * @param cwd the current work directory, used to resolve the reltive file path. | ||
| 113 | + * @param file the file path, can be relative or absolute path. | ||
| 114 | + */ | ||
| 115 | + static int on_dvr_reap_segment(std::string url, int client_id, SrsRequest* req, std::string cwd, std::string file); | ||
| 107 | }; | 116 | }; |
| 108 | 117 | ||
| 109 | #endif | 118 | #endif |
-
请 注册 或 登录 后发表评论