正在显示
9 个修改的文件
包含
320 行增加
和
21 行删除
| @@ -296,15 +296,14 @@ vhost dvr.srs.com { | @@ -296,15 +296,14 @@ vhost dvr.srs.com { | ||
| 296 | # request params, for example ?vhost=__defaultVhost__, where: | 296 | # request params, for example ?vhost=__defaultVhost__, where: |
| 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: [{plan:"api", path:"./objs/nginx/html", | ||
| 300 | - # autostart:true, wait_keyframe:true, jitter:"full" | 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" | ||
| 301 | # }]} | 301 | # }]} |
| 302 | # method=POST | 302 | # method=POST |
| 303 | # to start dvr of specified vhost. | 303 | # to start dvr of specified vhost. |
| 304 | # request should encode in json, specifies the dvr to create, where: | 304 | # request should encode in json, specifies the dvr to create, where: |
| 305 | - # {plan:"api", path:"./objs/nginx/html", | ||
| 306 | - # autostart:true, wait_keyframe:true, jitter:"full", | ||
| 307 | - # vhost:"__defaultVhost", callback:"http://dvr/callback" | 305 | + # {path_tmpl:"./[15].[04].[05].[999].flv", |
| 306 | + # wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback" | ||
| 308 | # } | 307 | # } |
| 309 | # response in json, where: | 308 | # response in json, where: |
| 310 | # {code:0} | 309 | # {code:0} |
| @@ -329,7 +328,7 @@ vhost dvr.srs.com { | @@ -329,7 +328,7 @@ vhost dvr.srs.com { | ||
| 329 | # [05], repleace this const to current second. | 328 | # [05], repleace this const to current second. |
| 330 | # [999], repleace this const to current millisecond. | 329 | # [999], repleace this const to current millisecond. |
| 331 | # [timestamp],replace this const to current UNIX timestamp in ms. | 330 | # [timestamp],replace this const to current UNIX timestamp in ms. |
| 332 | - # @remark we use golang time format "2006-01-02 15:04:05.999" | 331 | + # @remark we use golang time format "2006-01-02 15:04:05.999" as "[2006]-[01]-[02]_[15].[04].[05]_[999]" |
| 333 | # for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776 | 332 | # for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776 |
| 334 | # 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename): | 333 | # 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename): |
| 335 | # dvr_path ./objs/nginx/html; | 334 | # dvr_path ./objs/nginx/html; |
| @@ -1977,6 +1977,38 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc) | @@ -1977,6 +1977,38 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc) | ||
| 1977 | return ::atoi(conf->arg0().c_str()); | 1977 | return ::atoi(conf->arg0().c_str()); |
| 1978 | } | 1978 | } |
| 1979 | 1979 | ||
| 1980 | +SrsConfDirective* SrsConfig::create_directive(string vhost, string directive, string sub_directive) | ||
| 1981 | +{ | ||
| 1982 | + SrsConfDirective* vhost_conf = get_vhost(vhost); | ||
| 1983 | + | ||
| 1984 | + if (!vhost_conf) { | ||
| 1985 | + vhost_conf = new SrsConfDirective(); | ||
| 1986 | + root->directives.push_back(vhost_conf); | ||
| 1987 | + } | ||
| 1988 | + | ||
| 1989 | + if (directive.empty()) { | ||
| 1990 | + return vhost_conf; | ||
| 1991 | + } | ||
| 1992 | + | ||
| 1993 | + SrsConfDirective* dir = vhost_conf->get(directive); | ||
| 1994 | + if (!dir) { | ||
| 1995 | + dir = new SrsConfDirective(); | ||
| 1996 | + vhost_conf->directives.push_back(dir); | ||
| 1997 | + } | ||
| 1998 | + | ||
| 1999 | + if (sub_directive.empty()) { | ||
| 2000 | + return dir; | ||
| 2001 | + } | ||
| 2002 | + | ||
| 2003 | + SrsConfDirective* sdir = dir->get(sub_directive); | ||
| 2004 | + if (!sdir) { | ||
| 2005 | + sdir = new SrsConfDirective(); | ||
| 2006 | + dir->directives.push_back(sdir); | ||
| 2007 | + } | ||
| 2008 | + | ||
| 2009 | + return sdir; | ||
| 2010 | +} | ||
| 2011 | + | ||
| 1980 | SrsConfDirective* SrsConfig::get_vhost(string vhost) | 2012 | SrsConfDirective* SrsConfig::get_vhost(string vhost) |
| 1981 | { | 2013 | { |
| 1982 | srs_assert(root); | 2014 | srs_assert(root); |
| @@ -3327,6 +3359,13 @@ string SrsConfig::get_dvr_path(string vhost) | @@ -3327,6 +3359,13 @@ string SrsConfig::get_dvr_path(string vhost) | ||
| 3327 | return conf->arg0(); | 3359 | return conf->arg0(); |
| 3328 | } | 3360 | } |
| 3329 | 3361 | ||
| 3362 | +void SrsConfig::set_dvr_path(string vhost, string path) | ||
| 3363 | +{ | ||
| 3364 | + SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_path"); | ||
| 3365 | + conf->args.clear(); | ||
| 3366 | + conf->args.push_back(path); | ||
| 3367 | +} | ||
| 3368 | + | ||
| 3330 | string SrsConfig::get_dvr_plan(string vhost) | 3369 | string SrsConfig::get_dvr_plan(string vhost) |
| 3331 | { | 3370 | { |
| 3332 | SrsConfDirective* dvr = get_dvr(vhost); | 3371 | SrsConfDirective* dvr = get_dvr(vhost); |
| @@ -3378,6 +3417,13 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost) | @@ -3378,6 +3417,13 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost) | ||
| 3378 | return false; | 3417 | return false; |
| 3379 | } | 3418 | } |
| 3380 | 3419 | ||
| 3420 | +void SrsConfig::set_dvr_wait_keyframe(string vhost, bool wait_keyframe) | ||
| 3421 | +{ | ||
| 3422 | + SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_wait_keyframe"); | ||
| 3423 | + conf->args.clear(); | ||
| 3424 | + conf->args.push_back(wait_keyframe? "on":"off"); | ||
| 3425 | +} | ||
| 3426 | + | ||
| 3381 | bool SrsConfig::get_dvr_autostart(string vhost) | 3427 | bool SrsConfig::get_dvr_autostart(string vhost) |
| 3382 | { | 3428 | { |
| 3383 | SrsConfDirective* dvr = get_dvr(vhost); | 3429 | SrsConfDirective* dvr = get_dvr(vhost); |
| @@ -452,6 +452,14 @@ public: | @@ -452,6 +452,14 @@ public: | ||
| 452 | * get the max udp port for rtp of stream caster rtsp. | 452 | * get the max udp port for rtp of stream caster rtsp. |
| 453 | */ | 453 | */ |
| 454 | virtual int get_stream_caster_rtp_port_max(SrsConfDirective* sc); | 454 | virtual int get_stream_caster_rtp_port_max(SrsConfDirective* sc); |
| 455 | +private: | ||
| 456 | + /** | ||
| 457 | + * create directive under vhost. | ||
| 458 | + * @param directive, get the directive of vhost. get vhost if directive is empty. | ||
| 459 | + * @param sub_directive, get the sub directive of vhost. get directive if sub-directive is empty. | ||
| 460 | + * @return the vhost(empty directive and sub-directive); the directive(empty sub-directive); the sub-directive. | ||
| 461 | + */ | ||
| 462 | + virtual SrsConfDirective* create_directive(std::string vhost, std::string directive, std::string sub_directive); | ||
| 455 | // vhost specified section | 463 | // vhost specified section |
| 456 | public: | 464 | public: |
| 457 | /** | 465 | /** |
| @@ -919,6 +927,7 @@ public: | @@ -919,6 +927,7 @@ public: | ||
| 919 | * get the dvr path, the flv file to save in. | 927 | * get the dvr path, the flv file to save in. |
| 920 | */ | 928 | */ |
| 921 | virtual std::string get_dvr_path(std::string vhost); | 929 | virtual std::string get_dvr_path(std::string vhost); |
| 930 | + virtual void set_dvr_path(std::string vhost, std::string path); | ||
| 922 | /** | 931 | /** |
| 923 | * get the plan of dvr, how to reap the flv file. | 932 | * get the plan of dvr, how to reap the flv file. |
| 924 | */ | 933 | */ |
| @@ -931,6 +940,7 @@ public: | @@ -931,6 +940,7 @@ public: | ||
| 931 | * whether wait keyframe to reap segment. | 940 | * whether wait keyframe to reap segment. |
| 932 | */ | 941 | */ |
| 933 | virtual bool get_dvr_wait_keyframe(std::string vhost); | 942 | virtual bool get_dvr_wait_keyframe(std::string vhost); |
| 943 | + virtual void set_dvr_wait_keyframe(std::string vhost, bool wait_keyframe); | ||
| 934 | /** | 944 | /** |
| 935 | * whether autostart for dvr. wait api to start dvr if false. | 945 | * whether autostart for dvr. wait api to start dvr if false. |
| 936 | */ | 946 | */ |
| @@ -194,6 +194,11 @@ int SrsFlvSegment::close() | @@ -194,6 +194,11 @@ int SrsFlvSegment::close() | ||
| 194 | return ret; | 194 | return ret; |
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | + | ||
| 198 | + if ((ret = plan->on_reap_segment()) != ERROR_SUCCESS) { | ||
| 199 | + srs_error("dvr: notify plan to reap segment failed. ret=%d", ret); | ||
| 200 | + return ret; | ||
| 201 | + } | ||
| 197 | 202 | ||
| 198 | #ifdef SRS_AUTO_HTTP_CALLBACK | 203 | #ifdef SRS_AUTO_HTTP_CALLBACK |
| 199 | if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { | 204 | if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { |
| @@ -405,6 +410,11 @@ int SrsFlvSegment::update_flv_metadata() | @@ -405,6 +410,11 @@ int SrsFlvSegment::update_flv_metadata() | ||
| 405 | return ret; | 410 | return ret; |
| 406 | } | 411 | } |
| 407 | 412 | ||
| 413 | +string SrsFlvSegment::get_path() | ||
| 414 | +{ | ||
| 415 | + return path; | ||
| 416 | +} | ||
| 417 | + | ||
| 408 | string SrsFlvSegment::generate_path() | 418 | string SrsFlvSegment::generate_path() |
| 409 | { | 419 | { |
| 410 | // the path in config, for example, | 420 | // the path in config, for example, |
| @@ -657,6 +667,11 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video) | @@ -657,6 +667,11 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video) | ||
| 657 | return ret; | 667 | return ret; |
| 658 | } | 668 | } |
| 659 | 669 | ||
| 670 | +int SrsDvrPlan::on_reap_segment() | ||
| 671 | +{ | ||
| 672 | + return ERROR_SUCCESS; | ||
| 673 | +} | ||
| 674 | + | ||
| 660 | SrsDvrPlan* SrsDvrPlan::create_plan(string vhost) | 675 | SrsDvrPlan* SrsDvrPlan::create_plan(string vhost) |
| 661 | { | 676 | { |
| 662 | std::string plan = _srs_config->get_dvr_plan(vhost); | 677 | std::string plan = _srs_config->get_dvr_plan(vhost); |
| @@ -726,12 +741,32 @@ void SrsDvrSessionPlan::on_unpublish() | @@ -726,12 +741,32 @@ void SrsDvrSessionPlan::on_unpublish() | ||
| 726 | 741 | ||
| 727 | SrsDvrApiPlan::SrsDvrApiPlan() | 742 | SrsDvrApiPlan::SrsDvrApiPlan() |
| 728 | { | 743 | { |
| 744 | + autostart = false; | ||
| 745 | + started = false; | ||
| 729 | } | 746 | } |
| 730 | 747 | ||
| 731 | SrsDvrApiPlan::~SrsDvrApiPlan() | 748 | SrsDvrApiPlan::~SrsDvrApiPlan() |
| 732 | { | 749 | { |
| 733 | } | 750 | } |
| 734 | 751 | ||
| 752 | +int SrsDvrApiPlan::initialize(SrsSource* s, SrsRequest* r) | ||
| 753 | +{ | ||
| 754 | + int ret = ERROR_SUCCESS; | ||
| 755 | + | ||
| 756 | + if ((ret = SrsDvrPlan::initialize(s, r)) != ERROR_SUCCESS) { | ||
| 757 | + return ret; | ||
| 758 | + } | ||
| 759 | + | ||
| 760 | + SrsApiDvrPool* pool = SrsApiDvrPool::instance(); | ||
| 761 | + if ((ret = pool->add_dvr(this)) != ERROR_SUCCESS) { | ||
| 762 | + return ret; | ||
| 763 | + } | ||
| 764 | + | ||
| 765 | + autostart = _srs_config->get_dvr_autostart(r->vhost); | ||
| 766 | + | ||
| 767 | + return ret; | ||
| 768 | +} | ||
| 769 | + | ||
| 735 | int SrsDvrApiPlan::on_publish() | 770 | int SrsDvrApiPlan::on_publish() |
| 736 | { | 771 | { |
| 737 | int ret = ERROR_SUCCESS; | 772 | int ret = ERROR_SUCCESS; |
| @@ -745,6 +780,13 @@ int SrsDvrApiPlan::on_publish() | @@ -745,6 +780,13 @@ int SrsDvrApiPlan::on_publish() | ||
| 745 | return ret; | 780 | return ret; |
| 746 | } | 781 | } |
| 747 | 782 | ||
| 783 | + // api disabled dvr when not autostart. | ||
| 784 | + bool autostart = _srs_config->get_dvr_autostart(req->vhost); | ||
| 785 | + if (!autostart && !started) { | ||
| 786 | + srs_warn("dvr: api not start and disabled for not autostart."); | ||
| 787 | + return ret; | ||
| 788 | + } | ||
| 789 | + | ||
| 748 | if ((ret = segment->close()) != ERROR_SUCCESS) { | 790 | if ((ret = segment->close()) != ERROR_SUCCESS) { |
| 749 | return ret; | 791 | return ret; |
| 750 | } | 792 | } |
| @@ -760,18 +802,76 @@ int SrsDvrApiPlan::on_publish() | @@ -760,18 +802,76 @@ int SrsDvrApiPlan::on_publish() | ||
| 760 | 802 | ||
| 761 | void SrsDvrApiPlan::on_unpublish() | 803 | void SrsDvrApiPlan::on_unpublish() |
| 762 | { | 804 | { |
| 763 | - // support multiple publish. | ||
| 764 | - if (!dvr_enabled) { | ||
| 765 | - return; | 805 | +} |
| 806 | + | ||
| 807 | +int SrsDvrApiPlan::set_path_tmpl(string path_tmpl) | ||
| 808 | +{ | ||
| 809 | + _srs_config->set_dvr_path(req->vhost, path_tmpl); | ||
| 810 | + return ERROR_SUCCESS; | ||
| 811 | +} | ||
| 812 | + | ||
| 813 | +int SrsDvrApiPlan::set_callback(string value) | ||
| 814 | +{ | ||
| 815 | + callback = value; | ||
| 816 | + return ERROR_SUCCESS; | ||
| 817 | +} | ||
| 818 | + | ||
| 819 | +int SrsDvrApiPlan::set_wait_keyframe(bool wait_keyframe) | ||
| 820 | +{ | ||
| 821 | + _srs_config->set_dvr_wait_keyframe(req->vhost, wait_keyframe); | ||
| 822 | + return ERROR_SUCCESS; | ||
| 823 | +} | ||
| 824 | + | ||
| 825 | +int SrsDvrApiPlan::start() | ||
| 826 | +{ | ||
| 827 | + int ret = ERROR_SUCCESS; | ||
| 828 | + | ||
| 829 | + if (started) { | ||
| 830 | + return ret; | ||
| 766 | } | 831 | } |
| 832 | + | ||
| 833 | + // stop dvr | ||
| 834 | + if (dvr_enabled) { | ||
| 835 | + // ignore error. | ||
| 836 | + int ret = segment->close(); | ||
| 837 | + if (ret != ERROR_SUCCESS) { | ||
| 838 | + srs_warn("ignore flv close error. ret=%d", ret); | ||
| 839 | + } | ||
| 767 | 840 | ||
| 768 | - // ignore error. | ||
| 769 | - int ret = segment->close(); | ||
| 770 | - if (ret != ERROR_SUCCESS) { | ||
| 771 | - srs_warn("ignore flv close error. ret=%d", ret); | 841 | + dvr_enabled = false; |
| 772 | } | 842 | } |
| 773 | - | ||
| 774 | - dvr_enabled = false; | 843 | + |
| 844 | + // start dvr | ||
| 845 | + if ((ret = on_publish()) != ERROR_SUCCESS) { | ||
| 846 | + return ret; | ||
| 847 | + } | ||
| 848 | + | ||
| 849 | + started = true; | ||
| 850 | + return ret; | ||
| 851 | +} | ||
| 852 | + | ||
| 853 | +int SrsDvrApiPlan::dumps(stringstream& ss) | ||
| 854 | +{ | ||
| 855 | + int ret = ERROR_SUCCESS; | ||
| 856 | + | ||
| 857 | + bool wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost); | ||
| 858 | + std::string path_template = _srs_config->get_dvr_path(req->vhost); | ||
| 859 | + | ||
| 860 | + ss << __SRS_JOBJECT_START | ||
| 861 | + << __SRS_JFIELD_STR("path_tmpl", path_template) << __SRS_JFIELD_CONT | ||
| 862 | + << __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT | ||
| 863 | + << __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT | ||
| 864 | + << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT | ||
| 865 | + << __SRS_JFIELD_STR("callback", callback) | ||
| 866 | + << __SRS_JOBJECT_END; | ||
| 867 | + | ||
| 868 | + return ret; | ||
| 869 | +} | ||
| 870 | + | ||
| 871 | +int SrsDvrApiPlan::on_reap_segment() | ||
| 872 | +{ | ||
| 873 | + // TODO: FIXME: implements it. | ||
| 874 | + return ERROR_SUCCESS; | ||
| 775 | } | 875 | } |
| 776 | 876 | ||
| 777 | SrsDvrAppendPlan::SrsDvrAppendPlan() | 877 | SrsDvrAppendPlan::SrsDvrAppendPlan() |
| @@ -1043,16 +1143,103 @@ SrsApiDvrPool::SrsApiDvrPool() | @@ -1043,16 +1143,103 @@ SrsApiDvrPool::SrsApiDvrPool() | ||
| 1043 | 1143 | ||
| 1044 | SrsApiDvrPool::~SrsApiDvrPool() | 1144 | SrsApiDvrPool::~SrsApiDvrPool() |
| 1045 | { | 1145 | { |
| 1146 | + dvrs.clear(); | ||
| 1046 | } | 1147 | } |
| 1047 | 1148 | ||
| 1048 | -int SrsApiDvrPool::dumps(stringstream& ss) | 1149 | +int SrsApiDvrPool::add_dvr(SrsDvrApiPlan* dvr) |
| 1150 | +{ | ||
| 1151 | + dvrs.push_back(dvr); | ||
| 1152 | + return ERROR_SUCCESS; | ||
| 1153 | +} | ||
| 1154 | + | ||
| 1155 | +int SrsApiDvrPool::dumps(string vhost, stringstream& ss) | ||
| 1049 | { | 1156 | { |
| 1050 | int ret = ERROR_SUCCESS; | 1157 | int ret = ERROR_SUCCESS; |
| 1051 | - ss << __SRS_JARRAY_START | ||
| 1052 | - << __SRS_JARRAY_END; | 1158 | + |
| 1159 | + ss << __SRS_JARRAY_START; | ||
| 1160 | + | ||
| 1161 | + std::vector<SrsDvrApiPlan*> plans; | ||
| 1162 | + for (int i = 0; i < (int)dvrs.size(); i++) { | ||
| 1163 | + SrsDvrApiPlan* plan = dvrs.at(i); | ||
| 1164 | + if (!vhost.empty() && plan->req->vhost != vhost) { | ||
| 1165 | + continue; | ||
| 1166 | + } | ||
| 1167 | + plans.push_back(plan); | ||
| 1168 | + } | ||
| 1169 | + | ||
| 1170 | + for (int i = 0; i < (int)plans.size(); i++) { | ||
| 1171 | + SrsDvrApiPlan* plan = plans.at(i); | ||
| 1172 | + | ||
| 1173 | + if ((ret = plan->dumps(ss)) != ERROR_SUCCESS) { | ||
| 1174 | + return ret; | ||
| 1175 | + } | ||
| 1176 | + | ||
| 1177 | + if (i < (int)dvrs.size() - 1) { | ||
| 1178 | + ss << __SRS_JFIELD_CONT; | ||
| 1179 | + } | ||
| 1180 | + } | ||
| 1181 | + | ||
| 1182 | + ss << __SRS_JARRAY_END; | ||
| 1183 | + | ||
| 1053 | return ret; | 1184 | return ret; |
| 1054 | } | 1185 | } |
| 1055 | 1186 | ||
| 1187 | +int SrsApiDvrPool::create(SrsJsonAny* json) | ||
| 1188 | +{ | ||
| 1189 | + int ret = ERROR_SUCCESS; | ||
| 1190 | + | ||
| 1191 | + srs_assert(json); | ||
| 1192 | + if (!json->is_object()) { | ||
| 1193 | + ret = ERROR_HTTP_DVR_CREATE_REQUEST; | ||
| 1194 | + srs_error("dvr: api create dvr request requires json object. ret=%d", ret); | ||
| 1195 | + return ret; | ||
| 1196 | + } | ||
| 1197 | + | ||
| 1198 | + SrsJsonObject* obj = json->to_object(); | ||
| 1199 | + SrsJsonAny* prop = NULL; | ||
| 1200 | + if ((prop = obj->ensure_property_string("vhost")) == NULL) { | ||
| 1201 | + ret = ERROR_HTTP_DVR_CREATE_REQUEST; | ||
| 1202 | + srs_error("dvr: api create dvr request requires vhost. ret=%d", ret); | ||
| 1203 | + return ret; | ||
| 1204 | + } | ||
| 1205 | + | ||
| 1206 | + std::string vhost = prop->to_str(); | ||
| 1207 | + SrsDvrApiPlan* dvr = NULL; | ||
| 1208 | + for (int i = 0; i < (int)dvrs.size(); i++) { | ||
| 1209 | + SrsDvrApiPlan* plan = dvrs.at(i); | ||
| 1210 | + if (!vhost.empty() && plan->req->vhost != vhost) { | ||
| 1211 | + continue; | ||
| 1212 | + } | ||
| 1213 | + dvr = plan; | ||
| 1214 | + break; | ||
| 1215 | + } | ||
| 1216 | + | ||
| 1217 | + if (!dvr) { | ||
| 1218 | + ret = ERROR_HTTP_DVR_CREATE_REQUEST; | ||
| 1219 | + srs_error("dvr: api create dvr request vhost invalid. vhost=%s. ret=%d", vhost.c_str(), ret); | ||
| 1220 | + return ret; | ||
| 1221 | + } | ||
| 1222 | + | ||
| 1223 | + // update optional parameters for plan. | ||
| 1224 | + if ((prop = obj->ensure_property_string("path_tmpl")) != NULL) { | ||
| 1225 | + if ((ret = dvr->set_path_tmpl(prop->to_str())) != ERROR_SUCCESS) { | ||
| 1226 | + return ret; | ||
| 1227 | + } | ||
| 1228 | + } | ||
| 1229 | + if ((prop = obj->ensure_property_boolean("wait_keyframe")) != NULL) { | ||
| 1230 | + if ((ret = dvr->set_wait_keyframe(prop->to_boolean())) != ERROR_SUCCESS) { | ||
| 1231 | + return ret; | ||
| 1232 | + } | ||
| 1233 | + } | ||
| 1234 | + if ((prop = obj->ensure_property_string("callback")) != NULL) { | ||
| 1235 | + if ((ret = dvr->set_callback(prop->to_str())) != ERROR_SUCCESS) { | ||
| 1236 | + return ret; | ||
| 1237 | + } | ||
| 1238 | + } | ||
| 1239 | + | ||
| 1240 | + return dvr->start(); | ||
| 1241 | +} | ||
| 1242 | + | ||
| 1056 | SrsDvr::SrsDvr(SrsSource* s) | 1243 | SrsDvr::SrsDvr(SrsSource* s) |
| 1057 | { | 1244 | { |
| 1058 | source = s; | 1245 | source = s; |
| @@ -43,6 +43,7 @@ class SrsSharedPtrMessage; | @@ -43,6 +43,7 @@ class SrsSharedPtrMessage; | ||
| 43 | class SrsFileWriter; | 43 | class SrsFileWriter; |
| 44 | class SrsFlvEncoder; | 44 | class SrsFlvEncoder; |
| 45 | class SrsDvrPlan; | 45 | class SrsDvrPlan; |
| 46 | +class SrsJsonAny; | ||
| 46 | 47 | ||
| 47 | #include <srs_app_source.hpp> | 48 | #include <srs_app_source.hpp> |
| 48 | #include <srs_app_reload.hpp> | 49 | #include <srs_app_reload.hpp> |
| @@ -149,6 +150,10 @@ public: | @@ -149,6 +150,10 @@ public: | ||
| 149 | * update the flv metadata. | 150 | * update the flv metadata. |
| 150 | */ | 151 | */ |
| 151 | virtual int update_flv_metadata(); | 152 | virtual int update_flv_metadata(); |
| 153 | + /** | ||
| 154 | + * get the current dvr path. | ||
| 155 | + */ | ||
| 156 | + virtual std::string get_path(); | ||
| 152 | private: | 157 | private: |
| 153 | /** | 158 | /** |
| 154 | * generate the flv segment path. | 159 | * generate the flv segment path. |
| @@ -179,9 +184,10 @@ class SrsDvrPlan | @@ -179,9 +184,10 @@ class SrsDvrPlan | ||
| 179 | { | 184 | { |
| 180 | public: | 185 | public: |
| 181 | friend class SrsFlvSegment; | 186 | friend class SrsFlvSegment; |
| 187 | +public: | ||
| 188 | + SrsRequest* req; | ||
| 182 | protected: | 189 | protected: |
| 183 | SrsSource* source; | 190 | SrsSource* source; |
| 184 | - SrsRequest* req; | ||
| 185 | SrsFlvSegment* segment; | 191 | SrsFlvSegment* segment; |
| 186 | bool dvr_enabled; | 192 | bool dvr_enabled; |
| 187 | public: | 193 | public: |
| @@ -204,6 +210,7 @@ public: | @@ -204,6 +210,7 @@ public: | ||
| 204 | */ | 210 | */ |
| 205 | virtual int on_video(SrsSharedPtrMessage* __video); | 211 | virtual int on_video(SrsSharedPtrMessage* __video); |
| 206 | protected: | 212 | protected: |
| 213 | + virtual int on_reap_segment(); | ||
| 207 | virtual int on_dvr_request_sh(); | 214 | virtual int on_dvr_request_sh(); |
| 208 | virtual int on_video_keyframe(); | 215 | virtual int on_video_keyframe(); |
| 209 | virtual int64_t filter_timestamp(int64_t timestamp); | 216 | virtual int64_t filter_timestamp(int64_t timestamp); |
| @@ -229,12 +236,25 @@ public: | @@ -229,12 +236,25 @@ public: | ||
| 229 | */ | 236 | */ |
| 230 | class SrsDvrApiPlan : public SrsDvrPlan | 237 | class SrsDvrApiPlan : public SrsDvrPlan |
| 231 | { | 238 | { |
| 239 | +private: | ||
| 240 | + std::string callback; | ||
| 241 | + bool autostart; | ||
| 242 | + bool started; | ||
| 232 | public: | 243 | public: |
| 233 | SrsDvrApiPlan(); | 244 | SrsDvrApiPlan(); |
| 234 | virtual ~SrsDvrApiPlan(); | 245 | virtual ~SrsDvrApiPlan(); |
| 235 | public: | 246 | public: |
| 247 | + virtual int initialize(SrsSource* s, SrsRequest* r); | ||
| 236 | virtual int on_publish(); | 248 | virtual int on_publish(); |
| 237 | virtual void on_unpublish(); | 249 | virtual void on_unpublish(); |
| 250 | +public: | ||
| 251 | + virtual int set_path_tmpl(std::string path_tmpl); | ||
| 252 | + virtual int set_callback(std::string value); | ||
| 253 | + virtual int set_wait_keyframe(bool wait_keyframe); | ||
| 254 | + virtual int start(); | ||
| 255 | + virtual int dumps(std::stringstream& ss); | ||
| 256 | +protected: | ||
| 257 | + virtual int on_reap_segment(); | ||
| 238 | }; | 258 | }; |
| 239 | 259 | ||
| 240 | /** | 260 | /** |
| @@ -302,6 +322,7 @@ private: | @@ -302,6 +322,7 @@ private: | ||
| 302 | class SrsApiDvrPool | 322 | class SrsApiDvrPool |
| 303 | { | 323 | { |
| 304 | private: | 324 | private: |
| 325 | + std::vector<SrsDvrApiPlan*> dvrs; | ||
| 305 | static SrsApiDvrPool* _instance; | 326 | static SrsApiDvrPool* _instance; |
| 306 | private: | 327 | private: |
| 307 | SrsApiDvrPool(); | 328 | SrsApiDvrPool(); |
| @@ -309,7 +330,10 @@ public: | @@ -309,7 +330,10 @@ public: | ||
| 309 | static SrsApiDvrPool* instance(); | 330 | static SrsApiDvrPool* instance(); |
| 310 | virtual ~SrsApiDvrPool(); | 331 | virtual ~SrsApiDvrPool(); |
| 311 | public: | 332 | public: |
| 312 | - virtual int dumps(std::stringstream& ss); | 333 | + virtual int add_dvr(SrsDvrApiPlan* dvr); |
| 334 | +public: | ||
| 335 | + virtual int dumps(std::string vhost, std::stringstream& ss); | ||
| 336 | + virtual int create(SrsJsonAny* json); | ||
| 313 | }; | 337 | }; |
| 314 | 338 | ||
| 315 | /** | 339 | /** |
| @@ -494,12 +494,25 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | @@ -494,12 +494,25 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | ||
| 494 | SrsApiDvrPool* pool = SrsApiDvrPool::instance(); | 494 | SrsApiDvrPool* pool = SrsApiDvrPool::instance(); |
| 495 | if (r->is_http_get()) { | 495 | if (r->is_http_get()) { |
| 496 | std::stringstream data; | 496 | std::stringstream data; |
| 497 | - int ret = pool->dumps(data); | 497 | + int ret = pool->dumps(r->query_get("vhost"), data); |
| 498 | 498 | ||
| 499 | ss << __SRS_JOBJECT_START | 499 | ss << __SRS_JOBJECT_START |
| 500 | << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT | 500 | << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT |
| 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()) { | ||
| 504 | + char* body = (char*)r->body().c_str(); | ||
| 505 | + SrsJsonAny* json = SrsJsonAny::loads(body); | ||
| 506 | + int ret = ERROR_SUCCESS; | ||
| 507 | + if (!json) { | ||
| 508 | + ret = ERROR_HTTP_JSON_REQUIRED; | ||
| 509 | + } else { | ||
| 510 | + SrsAutoFree(SrsJsonAny, json); | ||
| 511 | + ret = pool->create(json); | ||
| 512 | + } | ||
| 513 | + ss << __SRS_JOBJECT_START | ||
| 514 | + << __SRS_JFIELD_ERROR(ret) | ||
| 515 | + << __SRS_JOBJECT_END; | ||
| 503 | } else { | 516 | } else { |
| 504 | ss << __SRS_JOBJECT_START | 517 | ss << __SRS_JOBJECT_START |
| 505 | << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST) | 518 | << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST) |
| @@ -457,6 +457,21 @@ SrsJsonAny* SrsJsonObject::ensure_property_string(string name) | @@ -457,6 +457,21 @@ SrsJsonAny* SrsJsonObject::ensure_property_string(string name) | ||
| 457 | return prop; | 457 | return prop; |
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | +SrsJsonAny* SrsJsonObject::ensure_property_boolean(string name) | ||
| 461 | +{ | ||
| 462 | + SrsJsonAny* prop = get_property(name); | ||
| 463 | + | ||
| 464 | + if (!prop) { | ||
| 465 | + return NULL; | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + if (!prop->is_boolean()) { | ||
| 469 | + return NULL; | ||
| 470 | + } | ||
| 471 | + | ||
| 472 | + return prop; | ||
| 473 | +} | ||
| 474 | + | ||
| 460 | SrsJsonArray::SrsJsonArray() | 475 | SrsJsonArray::SrsJsonArray() |
| 461 | { | 476 | { |
| 462 | marker = SRS_JSON_Array; | 477 | marker = SRS_JSON_Array; |
| @@ -123,6 +123,7 @@ public: | @@ -123,6 +123,7 @@ public: | ||
| 123 | public: | 123 | public: |
| 124 | /** | 124 | /** |
| 125 | * read json tree from str:char* | 125 | * read json tree from str:char* |
| 126 | + * @return json object. NULL if error. | ||
| 126 | */ | 127 | */ |
| 127 | static SrsJsonAny* loads(char* str); | 128 | static SrsJsonAny* loads(char* str); |
| 128 | }; | 129 | }; |
| @@ -148,6 +149,7 @@ public: | @@ -148,6 +149,7 @@ public: | ||
| 148 | virtual void set(std::string key, SrsJsonAny* value); | 149 | virtual void set(std::string key, SrsJsonAny* value); |
| 149 | virtual SrsJsonAny* get_property(std::string name); | 150 | virtual SrsJsonAny* get_property(std::string name); |
| 150 | virtual SrsJsonAny* ensure_property_string(std::string name); | 151 | virtual SrsJsonAny* ensure_property_string(std::string name); |
| 152 | + virtual SrsJsonAny* ensure_property_boolean(std::string name); | ||
| 151 | }; | 153 | }; |
| 152 | 154 | ||
| 153 | class SrsJsonArray : public SrsJsonAny | 155 | class SrsJsonArray : public SrsJsonAny |
| @@ -214,6 +216,7 @@ that is: | @@ -214,6 +216,7 @@ that is: | ||
| 214 | #define __SRS_JFIELD_NAME(k) "\"" << k << "\":" | 216 | #define __SRS_JFIELD_NAME(k) "\"" << k << "\":" |
| 215 | #define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\"" | 217 | #define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\"" |
| 216 | #define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v | 218 | #define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v |
| 219 | +#define __SRS_JFIELD_BOOL(k, v) __SRS_JFIELD_ORG(k, (v? "true":"false")) | ||
| 217 | #define __SRS_JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret | 220 | #define __SRS_JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret |
| 218 | #define __SRS_JFIELD_CONT "," | 221 | #define __SRS_JFIELD_CONT "," |
| 219 | #define __SRS_JOBJECT_END "}" | 222 | #define __SRS_JOBJECT_END "}" |
| @@ -211,6 +211,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -211,6 +211,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 211 | #define ERROR_HLS_TRY_MP3 3049 | 211 | #define ERROR_HLS_TRY_MP3 3049 |
| 212 | #define ERROR_HTTP_DVR_DISABLED 3050 | 212 | #define ERROR_HTTP_DVR_DISABLED 3050 |
| 213 | #define ERROR_HTTP_DVR_REQUEST 3051 | 213 | #define ERROR_HTTP_DVR_REQUEST 3051 |
| 214 | +#define ERROR_HTTP_JSON_REQUIRED 3052 | ||
| 215 | +#define ERROR_HTTP_DVR_CREATE_REQUEST 3053 | ||
| 214 | 216 | ||
| 215 | /////////////////////////////////////////////////////// | 217 | /////////////////////////////////////////////////////// |
| 216 | // HTTP/StreamCaster protocol error. | 218 | // HTTP/StreamCaster protocol error. |
-
请 注册 或 登录 后发表评论