winlin

merge from 2.0release

@@ -566,6 +566,7 @@ Supported operating systems and hardware: @@ -566,6 +566,7 @@ Supported operating systems and hardware:
566 566
567 ### SRS 2.0 history 567 ### SRS 2.0 history
568 568
  569 +* v2.0, 2015-04-15, for [#383](https://github.com/winlinvip/simple-rtmp-server/issues/383), support mix_correct algorithm. 2.0.161.
569 * v2.0, 2015-04-13, for [#381](https://github.com/winlinvip/simple-rtmp-server/issues/381), support reap hls/ts by gop or not. 2.0.160. 570 * v2.0, 2015-04-13, for [#381](https://github.com/winlinvip/simple-rtmp-server/issues/381), support reap hls/ts by gop or not. 2.0.160.
570 * v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts. 571 * v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts.
571 * v2.0, 2015-04-10, refine the hls deviation for floor algorithm. 572 * v2.0, 2015-04-10, refine the hls deviation for floor algorithm.
@@ -75,7 +75,7 @@ heartbeat { @@ -75,7 +75,7 @@ heartbeat {
75 # the id of devide. 75 # the id of devide.
76 device_id "my-srs-device"; 76 device_id "my-srs-device";
77 # whether report with summaries 77 # whether report with summaries
78 - # if true, put /api/v1/summaries to the request data: 78 + # if on, put /api/v1/summaries to the request data:
79 # { 79 # {
80 # "summaries": summaries object. 80 # "summaries": summaries object.
81 # } 81 # }
@@ -1329,7 +1329,7 @@ vhost jitter.srs.com { @@ -1329,7 +1329,7 @@ vhost jitter.srs.com {
1329 # about the stream monotonically increasing: 1329 # about the stream monotonically increasing:
1330 # 1. video timestamp is monotonically increasing, 1330 # 1. video timestamp is monotonically increasing,
1331 # 2. audio timestamp is monotonically increasing, 1331 # 2. audio timestamp is monotonically increasing,
1332 - # 3. video and audio timestamp is interleaved monotonically increasing. 1332 + # 3. video and audio timestamp is interleaved/mixed monotonically increasing.
1333 # it's specified by RTMP specification, @see 3. Byte Order, Alignment, and Time Format 1333 # it's specified by RTMP specification, @see 3. Byte Order, Alignment, and Time Format
1334 # however, some encoder cannot provides this feature, please set this to off to ignore time jitter. 1334 # however, some encoder cannot provides this feature, please set this to off to ignore time jitter.
1335 # the time jitter algorithm: 1335 # the time jitter algorithm:
@@ -1338,6 +1338,11 @@ vhost jitter.srs.com { @@ -1338,6 +1338,11 @@ vhost jitter.srs.com {
1338 # 3. off, disable the time jitter algorithm, like atc. 1338 # 3. off, disable the time jitter algorithm, like atc.
1339 # default: full 1339 # default: full
1340 time_jitter full; 1340 time_jitter full;
  1341 + # whether use the interleaved/mixed algorithm to correct the timestamp.
  1342 + # if on, always ensure the timestamp of audio+video is interleaved/mixed monotonically increase.
  1343 + # if off, use time_jitter to correct the timestamp if required.
  1344 + # default: off
  1345 + mix_correct off;
1341 } 1346 }
1342 1347
1343 # vhost for atc. 1348 # vhost for atc.
@@ -171,7 +171,7 @@ int do_proxy(srs_flv_t flv, srs_rtmp_t ortmp, int64_t re, int32_t* pstarttime, u @@ -171,7 +171,7 @@ int do_proxy(srs_flv_t flv, srs_rtmp_t ortmp, int64_t re, int32_t* pstarttime, u
171 return ret; 171 return ret;
172 } 172 }
173 173
174 - if (*pstarttime < 0) { 174 + if (*pstarttime < 0 && srs_utils_flv_tag_is_av(type)) {
175 *pstarttime = *ptimestamp; 175 *pstarttime = *ptimestamp;
176 } 176 }
177 177
@@ -807,6 +807,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) @@ -807,6 +807,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
807 } 807 }
808 srs_trace("vhost %s reload time_jitter success.", vhost.c_str()); 808 srs_trace("vhost %s reload time_jitter success.", vhost.c_str());
809 } 809 }
  810 + // mix_correct, only one per vhost
  811 + if (!srs_directive_equals(new_vhost->get("mix_correct"), old_vhost->get("mix_correct"))) {
  812 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  813 + ISrsReloadHandler* subscribe = *it;
  814 + if ((ret = subscribe->on_reload_vhost_mix_correct(vhost)) != ERROR_SUCCESS) {
  815 + srs_error("vhost %s notify subscribes mix_correct failed. ret=%d", vhost.c_str(), ret);
  816 + return ret;
  817 + }
  818 + }
  819 + srs_trace("vhost %s reload mix_correct success.", vhost.c_str());
  820 + }
810 // forward, only one per vhost 821 // forward, only one per vhost
811 if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) { 822 if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) {
812 for (it = subscribes.begin(); it != subscribes.end(); ++it) { 823 for (it = subscribes.begin(); it != subscribes.end(); ++it) {
@@ -1419,7 +1430,7 @@ int SrsConfig::check_config() @@ -1419,7 +1430,7 @@ int SrsConfig::check_config()
1419 && n != "gop_cache" && n != "queue_length" 1430 && n != "gop_cache" && n != "queue_length"
1420 && n != "refer" && n != "refer_publish" && n != "refer_play" 1431 && n != "refer" && n != "refer_publish" && n != "refer_play"
1421 && n != "forward" && n != "transcode" && n != "bandcheck" 1432 && n != "forward" && n != "transcode" && n != "bandcheck"
1422 - && n != "time_jitter" 1433 + && n != "time_jitter" && n != "mix_correct"
1423 && n != "atc" && n != "atc_auto" 1434 && n != "atc" && n != "atc_auto"
1424 && n != "debug_srs_upnode" 1435 && n != "debug_srs_upnode"
1425 && n != "mr" && n != "mw_latency" && n != "min_latency" 1436 && n != "mr" && n != "mw_latency" && n != "min_latency"
@@ -2118,12 +2129,12 @@ bool SrsConfig::get_atc_auto(string vhost) @@ -2118,12 +2129,12 @@ bool SrsConfig::get_atc_auto(string vhost)
2118 SrsConfDirective* conf = get_vhost(vhost); 2129 SrsConfDirective* conf = get_vhost(vhost);
2119 2130
2120 if (!conf) { 2131 if (!conf) {
2121 - return true; 2132 + return SRS_CONF_DEFAULT_ATC_AUTO;
2122 } 2133 }
2123 2134
2124 conf = conf->get("atc_auto"); 2135 conf = conf->get("atc_auto");
2125 if (!conf || conf->arg0().empty()) { 2136 if (!conf || conf->arg0().empty()) {
2126 - return true; 2137 + return SRS_CONF_DEFAULT_ATC_AUTO;
2127 } 2138 }
2128 2139
2129 return SRS_CONF_PERFER_TRUE(conf->arg0()); 2140 return SRS_CONF_PERFER_TRUE(conf->arg0());
@@ -2131,14 +2142,14 @@ bool SrsConfig::get_atc_auto(string vhost) @@ -2131,14 +2142,14 @@ bool SrsConfig::get_atc_auto(string vhost)
2131 2142
2132 int SrsConfig::get_time_jitter(string vhost) 2143 int SrsConfig::get_time_jitter(string vhost)
2133 { 2144 {
2134 - SrsConfDirective* dvr = get_vhost(vhost); 2145 + SrsConfDirective* conf = get_vhost(vhost);
2135 2146
2136 std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER; 2147 std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER;
2137 2148
2138 - if (dvr) {  
2139 - SrsConfDirective* conf = dvr->get("time_jitter");  
2140 -  
2141 if (conf) { 2149 if (conf) {
  2150 + conf = conf->get("time_jitter");
  2151 +
  2152 + if (conf && !conf->arg0().empty()) {
2142 time_jitter = conf->arg0(); 2153 time_jitter = conf->arg0();
2143 } 2154 }
2144 } 2155 }
@@ -2146,6 +2157,22 @@ int SrsConfig::get_time_jitter(string vhost) @@ -2146,6 +2157,22 @@ int SrsConfig::get_time_jitter(string vhost)
2146 return _srs_time_jitter_string2int(time_jitter); 2157 return _srs_time_jitter_string2int(time_jitter);
2147 } 2158 }
2148 2159
  2160 +bool SrsConfig::get_mix_correct(string vhost)
  2161 +{
  2162 + SrsConfDirective* conf = get_vhost(vhost);
  2163 +
  2164 + if (!conf) {
  2165 + return SRS_CONF_DEFAULT_MIX_CORRECT;
  2166 + }
  2167 +
  2168 + conf = conf->get("mix_correct");
  2169 + if (!conf || conf->arg0().empty()) {
  2170 + return SRS_CONF_DEFAULT_MIX_CORRECT;
  2171 + }
  2172 +
  2173 + return SRS_CONF_PERFER_FALSE(conf->arg0());
  2174 +}
  2175 +
2149 double SrsConfig::get_queue_length(string vhost) 2176 double SrsConfig::get_queue_length(string vhost)
2150 { 2177 {
2151 SrsConfDirective* conf = get_vhost(vhost); 2178 SrsConfDirective* conf = get_vhost(vhost);
@@ -72,6 +72,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -72,6 +72,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
72 #define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION 72 #define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION
73 #define SRS_CONF_DEFAULT_DVR_DURATION 30 73 #define SRS_CONF_DEFAULT_DVR_DURATION 30
74 #define SRS_CONF_DEFAULT_TIME_JITTER "full" 74 #define SRS_CONF_DEFAULT_TIME_JITTER "full"
  75 +#define SRS_CONF_DEFAULT_ATC_AUTO true
  76 +#define SRS_CONF_DEFAULT_MIX_CORRECT false
75 // in seconds, the paused queue length. 77 // in seconds, the paused queue length.
76 #define SRS_CONF_DEFAULT_PAUSED_LENGTH 10 78 #define SRS_CONF_DEFAULT_PAUSED_LENGTH 10
77 // the interval in seconds for bandwidth check 79 // the interval in seconds for bandwidth check
@@ -532,6 +534,11 @@ public: @@ -532,6 +534,11 @@ public:
532 */ 534 */
533 virtual int get_time_jitter(std::string vhost); 535 virtual int get_time_jitter(std::string vhost);
534 /** 536 /**
  537 + * whether use mix correct algorithm to ensure the timestamp
  538 + * monotonically increase.
  539 + */
  540 + virtual bool get_mix_correct(std::string vhost);
  541 + /**
535 * get the cache queue length, in seconds. 542 * get the cache queue length, in seconds.
536 * when exceed the queue length, drop packet util I frame. 543 * when exceed the queue length, drop packet util I frame.
537 * @remark, default 10. 544 * @remark, default 10.
@@ -358,8 +358,18 @@ int SrsHttpHooks::on_hls_notify(std::string url, SrsRequest* req, std::string ts @@ -358,8 +358,18 @@ int SrsHttpHooks::on_hls_notify(std::string url, SrsRequest* req, std::string ts
358 return ret; 358 return ret;
359 } 359 }
360 360
  361 + std::string path = uri.get_query();
  362 + if (path.empty()) {
  363 + path = uri.get_path();
  364 + } else {
  365 + path = uri.get_path();
  366 + path += "?";
  367 + path += uri.get_query();
  368 + }
  369 + srs_warn("GET %s", path.c_str());
  370 +
361 SrsHttpMessage* msg = NULL; 371 SrsHttpMessage* msg = NULL;
362 - if ((ret = http.get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) { 372 + if ((ret = http.get(path.c_str(), "", &msg)) != ERROR_SUCCESS) {
363 return ret; 373 return ret;
364 } 374 }
365 SrsAutoFree(SrsHttpMessage, msg); 375 SrsAutoFree(SrsHttpMessage, msg);
@@ -130,6 +130,11 @@ int ISrsReloadHandler::on_reload_vhost_time_jitter(string /*vhost*/) @@ -130,6 +130,11 @@ int ISrsReloadHandler::on_reload_vhost_time_jitter(string /*vhost*/)
130 return ERROR_SUCCESS; 130 return ERROR_SUCCESS;
131 } 131 }
132 132
  133 +int ISrsReloadHandler::on_reload_vhost_mix_correct(string /*vhost*/)
  134 +{
  135 + return ERROR_SUCCESS;
  136 +}
  137 +
133 int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/) 138 int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/)
134 { 139 {
135 return ERROR_SUCCESS; 140 return ERROR_SUCCESS;
@@ -63,6 +63,7 @@ public: @@ -63,6 +63,7 @@ public:
63 virtual int on_reload_vhost_gop_cache(std::string vhost); 63 virtual int on_reload_vhost_gop_cache(std::string vhost);
64 virtual int on_reload_vhost_queue_length(std::string vhost); 64 virtual int on_reload_vhost_queue_length(std::string vhost);
65 virtual int on_reload_vhost_time_jitter(std::string vhost); 65 virtual int on_reload_vhost_time_jitter(std::string vhost);
  66 + virtual int on_reload_vhost_mix_correct(std::string vhost);
66 virtual int on_reload_vhost_forward(std::string vhost); 67 virtual int on_reload_vhost_forward(std::string vhost);
67 virtual int on_reload_vhost_hls(std::string vhost); 68 virtual int on_reload_vhost_hls(std::string vhost);
68 virtual int on_reload_vhost_hds(std::string vhost); 69 virtual int on_reload_vhost_hds(std::string vhost);
@@ -44,6 +44,7 @@ using namespace std; @@ -44,6 +44,7 @@ using namespace std;
44 #include <srs_rtmp_msg_array.hpp> 44 #include <srs_rtmp_msg_array.hpp>
45 #include <srs_app_hds.hpp> 45 #include <srs_app_hds.hpp>
46 #include <srs_app_statistic.hpp> 46 #include <srs_app_statistic.hpp>
  47 +#include <srs_core_autofree.hpp>
47 48
48 #define CONST_MAX_JITTER_MS 500 49 #define CONST_MAX_JITTER_MS 500
49 #define DEFAULT_FRAME_TIME_MS 40 50 #define DEFAULT_FRAME_TIME_MS 40
@@ -768,10 +769,62 @@ void SrsSource::destroy() @@ -768,10 +769,62 @@ void SrsSource::destroy()
768 pool.clear(); 769 pool.clear();
769 } 770 }
770 771
  772 +SrsMixQueue::SrsMixQueue()
  773 +{
  774 + nb_videos = 0;
  775 +}
  776 +
  777 +SrsMixQueue::~SrsMixQueue()
  778 +{
  779 + clear();
  780 +}
  781 +
  782 +void SrsMixQueue::clear()
  783 +{
  784 + std::multimap<int64_t, SrsSharedPtrMessage*>::iterator it;
  785 + for (it = msgs.begin(); it != msgs.end(); ++it) {
  786 + SrsSharedPtrMessage* msg = it->second;
  787 + srs_freep(msg);
  788 + }
  789 + msgs.clear();
  790 +
  791 + nb_videos = 0;
  792 +}
  793 +
  794 +void SrsMixQueue::push(SrsSharedPtrMessage* msg)
  795 +{
  796 + msgs.insert(std::make_pair(msg->timestamp, msg));
  797 +
  798 + if (msg->is_video()) {
  799 + nb_videos++;
  800 + }
  801 +}
  802 +
  803 +SrsSharedPtrMessage* SrsMixQueue::pop()
  804 +{
  805 + // always keep 2+ videos
  806 + if (nb_videos < 2) {
  807 + return NULL;
  808 + }
  809 +
  810 + // pop the first msg.
  811 + std::multimap<int64_t, SrsSharedPtrMessage*>::iterator it = msgs.begin();
  812 + SrsSharedPtrMessage* msg = it->second;
  813 + msgs.erase(it);
  814 +
  815 + if (msg->is_video()) {
  816 + nb_videos--;
  817 + }
  818 +
  819 + return msg;
  820 +}
  821 +
771 SrsSource::SrsSource() 822 SrsSource::SrsSource()
772 { 823 {
773 _req = NULL; 824 _req = NULL;
774 jitter_algorithm = SrsRtmpJitterAlgorithmOFF; 825 jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
  826 + mix_correct = false;
  827 + mix_queue = new SrsMixQueue();
775 828
776 #ifdef SRS_AUTO_HLS 829 #ifdef SRS_AUTO_HLS
777 hls = new SrsHls(); 830 hls = new SrsHls();
@@ -818,6 +871,7 @@ SrsSource::~SrsSource() @@ -818,6 +871,7 @@ SrsSource::~SrsSource()
818 forwarders.clear(); 871 forwarders.clear();
819 } 872 }
820 873
  874 + srs_freep(mix_queue);
821 srs_freep(cache_metadata); 875 srs_freep(cache_metadata);
822 srs_freep(cache_sh_video); 876 srs_freep(cache_sh_video);
823 srs_freep(cache_sh_audio); 877 srs_freep(cache_sh_audio);
@@ -878,6 +932,7 @@ int SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* h @@ -878,6 +932,7 @@ int SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* h
878 publish_edge->set_queue_size(queue_size); 932 publish_edge->set_queue_size(queue_size);
879 933
880 jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost); 934 jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
  935 + mix_correct = _srs_config->get_mix_correct(_req->vhost);
881 936
882 return ret; 937 return ret;
883 } 938 }
@@ -973,6 +1028,25 @@ int SrsSource::on_reload_vhost_time_jitter(string vhost) @@ -973,6 +1028,25 @@ int SrsSource::on_reload_vhost_time_jitter(string vhost)
973 return ret; 1028 return ret;
974 } 1029 }
975 1030
  1031 +int SrsSource::on_reload_vhost_mix_correct(string vhost)
  1032 +{
  1033 + int ret = ERROR_SUCCESS;
  1034 +
  1035 + if (_req->vhost != vhost) {
  1036 + return ret;
  1037 + }
  1038 +
  1039 + bool v = _srs_config->get_mix_correct(_req->vhost);
  1040 +
  1041 + // when changed, clear the mix queue.
  1042 + if (v != mix_correct) {
  1043 + mix_queue->clear();
  1044 + }
  1045 + mix_correct = v;
  1046 +
  1047 + return ret;
  1048 +}
  1049 +
976 int SrsSource::on_reload_vhost_forward(string vhost) 1050 int SrsSource::on_reload_vhost_forward(string vhost)
977 { 1051 {
978 int ret = ERROR_SUCCESS; 1052 int ret = ERROR_SUCCESS;
@@ -1330,10 +1404,23 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1330,10 +1404,23 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1330 srs_error("initialize the audio failed. ret=%d", ret); 1404 srs_error("initialize the audio failed. ret=%d", ret);
1331 return ret; 1405 return ret;
1332 } 1406 }
1333 - srs_verbose("initialize shared ptr audio success."); 1407 + srs_info("Audio dts=%"PRId64", size=%d", msg.timestamp, msg.size);
  1408 +
  1409 + if (!mix_correct) {
  1410 + return on_audio_imp(&msg);
  1411 + }
  1412 +
  1413 + return do_mix_correct(&msg);
  1414 +}
  1415 +
  1416 +int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg)
  1417 +{
  1418 + int ret = ERROR_SUCCESS;
  1419 +
  1420 + srs_info("Audio dts=%"PRId64", size=%d", msg->timestamp, msg->size);
1334 1421
1335 #ifdef SRS_AUTO_HLS 1422 #ifdef SRS_AUTO_HLS
1336 - if ((ret = hls->on_audio(&msg)) != ERROR_SUCCESS) { 1423 + if ((ret = hls->on_audio(msg)) != ERROR_SUCCESS) {
1337 // apply the error strategy for hls. 1424 // apply the error strategy for hls.
1338 // @see https://github.com/winlinvip/simple-rtmp-server/issues/264 1425 // @see https://github.com/winlinvip/simple-rtmp-server/issues/264
1339 std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost); 1426 std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost);
@@ -1347,7 +1434,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1347,7 +1434,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1347 ret = ERROR_SUCCESS; 1434 ret = ERROR_SUCCESS;
1348 } else if (hls_error_strategy == SRS_CONF_DEFAULT_HLS_ON_ERROR_CONTINUE) { 1435 } else if (hls_error_strategy == SRS_CONF_DEFAULT_HLS_ON_ERROR_CONTINUE) {
1349 // compare the sequence header with audio, continue when it's actually an sequence header. 1436 // compare the sequence header with audio, continue when it's actually an sequence header.
1350 - if (ret == ERROR_HLS_DECODE_ERROR && cache_sh_audio && cache_sh_audio->size == msg.size) { 1437 + if (ret == ERROR_HLS_DECODE_ERROR && cache_sh_audio && cache_sh_audio->size == msg->size) {
1351 srs_warn("the audio is actually a sequence header, ignore this packet."); 1438 srs_warn("the audio is actually a sequence header, ignore this packet.");
1352 ret = ERROR_SUCCESS; 1439 ret = ERROR_SUCCESS;
1353 } else { 1440 } else {
@@ -1362,7 +1449,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1362,7 +1449,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1362 #endif 1449 #endif
1363 1450
1364 #ifdef SRS_AUTO_DVR 1451 #ifdef SRS_AUTO_DVR
1365 - if ((ret = dvr->on_audio(&msg)) != ERROR_SUCCESS) { 1452 + if ((ret = dvr->on_audio(msg)) != ERROR_SUCCESS) {
1366 srs_warn("dvr process audio message failed, ignore and disable dvr. ret=%d", ret); 1453 srs_warn("dvr process audio message failed, ignore and disable dvr. ret=%d", ret);
1367 1454
1368 // unpublish, ignore ret. 1455 // unpublish, ignore ret.
@@ -1374,7 +1461,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1374,7 +1461,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1374 #endif 1461 #endif
1375 1462
1376 #ifdef SRS_AUTO_HDS 1463 #ifdef SRS_AUTO_HDS
1377 - if ((ret = hds->on_audio(&msg)) != ERROR_SUCCESS) { 1464 + if ((ret = hds->on_audio(msg)) != ERROR_SUCCESS) {
1378 srs_warn("hds process audio message failed, ignore and disable dvr. ret=%d", ret); 1465 srs_warn("hds process audio message failed, ignore and disable dvr. ret=%d", ret);
1379 1466
1380 // unpublish, ignore ret. 1467 // unpublish, ignore ret.
@@ -1390,7 +1477,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1390,7 +1477,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1390 SrsConsumer** pconsumer = consumers.data(); 1477 SrsConsumer** pconsumer = consumers.data();
1391 for (int i = 0; i < nb_consumers; i++) { 1478 for (int i = 0; i < nb_consumers; i++) {
1392 SrsConsumer* consumer = pconsumer[i]; 1479 SrsConsumer* consumer = pconsumer[i];
1393 - if ((ret = consumer->enqueue(&msg, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) { 1480 + if ((ret = consumer->enqueue(msg, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
1394 srs_error("dispatch the audio failed. ret=%d", ret); 1481 srs_error("dispatch the audio failed. ret=%d", ret);
1395 return ret; 1482 return ret;
1396 } 1483 }
@@ -1403,7 +1490,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1403,7 +1490,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1403 std::vector<SrsForwarder*>::iterator it; 1490 std::vector<SrsForwarder*>::iterator it;
1404 for (it = forwarders.begin(); it != forwarders.end(); ++it) { 1491 for (it = forwarders.begin(); it != forwarders.end(); ++it) {
1405 SrsForwarder* forwarder = *it; 1492 SrsForwarder* forwarder = *it;
1406 - if ((ret = forwarder->on_audio(&msg)) != ERROR_SUCCESS) { 1493 + if ((ret = forwarder->on_audio(msg)) != ERROR_SUCCESS) {
1407 srs_error("forwarder process audio message failed. ret=%d", ret); 1494 srs_error("forwarder process audio message failed. ret=%d", ret);
1408 return ret; 1495 return ret;
1409 } 1496 }
@@ -1413,10 +1500,10 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1413,10 +1500,10 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1413 // cache the sequence header of aac, or first packet of mp3. 1500 // cache the sequence header of aac, or first packet of mp3.
1414 // for example, the mp3 is used for hls to write the "right" audio codec. 1501 // for example, the mp3 is used for hls to write the "right" audio codec.
1415 // TODO: FIXME: to refine the stream info system. 1502 // TODO: FIXME: to refine the stream info system.
1416 - bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg.payload, msg.size); 1503 + bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size);
1417 if (is_aac_sequence_header || !cache_sh_audio) { 1504 if (is_aac_sequence_header || !cache_sh_audio) {
1418 srs_freep(cache_sh_audio); 1505 srs_freep(cache_sh_audio);
1419 - cache_sh_audio = msg.copy(); 1506 + cache_sh_audio = msg->copy();
1420 } 1507 }
1421 1508
1422 // cache the sequence header if aac 1509 // cache the sequence header if aac
@@ -1425,7 +1512,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1425,7 +1512,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1425 // parse detail audio codec 1512 // parse detail audio codec
1426 SrsAvcAacCodec codec; 1513 SrsAvcAacCodec codec;
1427 SrsCodecSample sample; 1514 SrsCodecSample sample;
1428 - if ((ret = codec.audio_aac_demux(msg.payload, msg.size, &sample)) != ERROR_SUCCESS) { 1515 + if ((ret = codec.audio_aac_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) {
1429 srs_error("source codec demux audio failed. ret=%d", ret); 1516 srs_error("source codec demux audio failed. ret=%d", ret);
1430 return ret; 1517 return ret;
1431 } 1518 }
@@ -1442,7 +1529,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1442,7 +1529,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1442 srs_trace("%dB audio sh, " 1529 srs_trace("%dB audio sh, "
1443 "codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), " 1530 "codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), "
1444 "flv(%dbits, %dchannels, %dHZ)", 1531 "flv(%dbits, %dchannels, %dHZ)",
1445 - msg.size, codec.audio_codec_id, 1532 + msg->size, codec.audio_codec_id,
1446 srs_codec_aac_object2str(codec.aac_object).c_str(), codec.aac_channels, 1533 srs_codec_aac_object2str(codec.aac_object).c_str(), codec.aac_channels,
1447 codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate], 1534 codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate],
1448 flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type], 1535 flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type],
@@ -1451,7 +1538,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1451,7 +1538,7 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1451 } 1538 }
1452 1539
1453 // cache the last gop packets 1540 // cache the last gop packets
1454 - if ((ret = gop_cache->cache(&msg)) != ERROR_SUCCESS) { 1541 + if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) {
1455 srs_error("shrink gop cache failed. ret=%d", ret); 1542 srs_error("shrink gop cache failed. ret=%d", ret);
1456 return ret; 1543 return ret;
1457 } 1544 }
@@ -1460,10 +1547,10 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio) @@ -1460,10 +1547,10 @@ int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1460 // if atc, update the sequence header to abs time. 1547 // if atc, update the sequence header to abs time.
1461 if (atc) { 1548 if (atc) {
1462 if (cache_sh_audio) { 1549 if (cache_sh_audio) {
1463 - cache_sh_audio->timestamp = msg.timestamp; 1550 + cache_sh_audio->timestamp = msg->timestamp;
1464 } 1551 }
1465 if (cache_metadata) { 1552 if (cache_metadata) {
1466 - cache_metadata->timestamp = msg.timestamp; 1553 + cache_metadata->timestamp = msg->timestamp;
1467 } 1554 }
1468 } 1555 }
1469 1556
@@ -1481,10 +1568,23 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1481,10 +1568,23 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1481 srs_error("initialize the video failed. ret=%d", ret); 1568 srs_error("initialize the video failed. ret=%d", ret);
1482 return ret; 1569 return ret;
1483 } 1570 }
1484 - srs_verbose("initialize shared ptr video success."); 1571 + srs_info("Video dts=%"PRId64", size=%d", msg.timestamp, msg.size);
  1572 +
  1573 + if (!mix_correct) {
  1574 + return on_video_imp(&msg);
  1575 + }
  1576 +
  1577 + return do_mix_correct(&msg);
  1578 +}
  1579 +
  1580 +int SrsSource::on_video_imp(SrsSharedPtrMessage* msg)
  1581 +{
  1582 + int ret = ERROR_SUCCESS;
  1583 +
  1584 + srs_info("Video dts=%"PRId64", size=%d", msg->timestamp, msg->size);
1485 1585
1486 #ifdef SRS_AUTO_HLS 1586 #ifdef SRS_AUTO_HLS
1487 - if ((ret = hls->on_video(&msg)) != ERROR_SUCCESS) { 1587 + if ((ret = hls->on_video(msg)) != ERROR_SUCCESS) {
1488 // apply the error strategy for hls. 1588 // apply the error strategy for hls.
1489 // @see https://github.com/winlinvip/simple-rtmp-server/issues/264 1589 // @see https://github.com/winlinvip/simple-rtmp-server/issues/264
1490 std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost); 1590 std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost);
@@ -1498,7 +1598,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1498,7 +1598,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1498 ret = ERROR_SUCCESS; 1598 ret = ERROR_SUCCESS;
1499 } else if (hls_error_strategy == SRS_CONF_DEFAULT_HLS_ON_ERROR_CONTINUE) { 1599 } else if (hls_error_strategy == SRS_CONF_DEFAULT_HLS_ON_ERROR_CONTINUE) {
1500 // compare the sequence header with video, continue when it's actually an sequence header. 1600 // compare the sequence header with video, continue when it's actually an sequence header.
1501 - if (ret == ERROR_HLS_DECODE_ERROR && cache_sh_video && cache_sh_video->size == msg.size) { 1601 + if (ret == ERROR_HLS_DECODE_ERROR && cache_sh_video && cache_sh_video->size == msg->size) {
1502 srs_warn("the video is actually a sequence header, ignore this packet."); 1602 srs_warn("the video is actually a sequence header, ignore this packet.");
1503 ret = ERROR_SUCCESS; 1603 ret = ERROR_SUCCESS;
1504 } else { 1604 } else {
@@ -1513,7 +1613,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1513,7 +1613,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1513 #endif 1613 #endif
1514 1614
1515 #ifdef SRS_AUTO_DVR 1615 #ifdef SRS_AUTO_DVR
1516 - if ((ret = dvr->on_video(&msg)) != ERROR_SUCCESS) { 1616 + if ((ret = dvr->on_video(msg)) != ERROR_SUCCESS) {
1517 srs_warn("dvr process video message failed, ignore and disable dvr. ret=%d", ret); 1617 srs_warn("dvr process video message failed, ignore and disable dvr. ret=%d", ret);
1518 1618
1519 // unpublish, ignore ret. 1619 // unpublish, ignore ret.
@@ -1525,7 +1625,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1525,7 +1625,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1525 #endif 1625 #endif
1526 1626
1527 #ifdef SRS_AUTO_HDS 1627 #ifdef SRS_AUTO_HDS
1528 - if ((ret = hds->on_video(&msg)) != ERROR_SUCCESS) { 1628 + if ((ret = hds->on_video(msg)) != ERROR_SUCCESS) {
1529 srs_warn("hds process video message failed, ignore and disable dvr. ret=%d", ret); 1629 srs_warn("hds process video message failed, ignore and disable dvr. ret=%d", ret);
1530 1630
1531 // unpublish, ignore ret. 1631 // unpublish, ignore ret.
@@ -1539,7 +1639,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1539,7 +1639,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1539 if (true) { 1639 if (true) {
1540 for (int i = 0; i < (int)consumers.size(); i++) { 1640 for (int i = 0; i < (int)consumers.size(); i++) {
1541 SrsConsumer* consumer = consumers.at(i); 1641 SrsConsumer* consumer = consumers.at(i);
1542 - if ((ret = consumer->enqueue(&msg, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) { 1642 + if ((ret = consumer->enqueue(msg, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
1543 srs_error("dispatch the video failed. ret=%d", ret); 1643 srs_error("dispatch the video failed. ret=%d", ret);
1544 return ret; 1644 return ret;
1545 } 1645 }
@@ -1552,7 +1652,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1552,7 +1652,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1552 std::vector<SrsForwarder*>::iterator it; 1652 std::vector<SrsForwarder*>::iterator it;
1553 for (it = forwarders.begin(); it != forwarders.end(); ++it) { 1653 for (it = forwarders.begin(); it != forwarders.end(); ++it) {
1554 SrsForwarder* forwarder = *it; 1654 SrsForwarder* forwarder = *it;
1555 - if ((ret = forwarder->on_video(&msg)) != ERROR_SUCCESS) { 1655 + if ((ret = forwarder->on_video(msg)) != ERROR_SUCCESS) {
1556 srs_error("forwarder process video message failed. ret=%d", ret); 1656 srs_error("forwarder process video message failed. ret=%d", ret);
1557 return ret; 1657 return ret;
1558 } 1658 }
@@ -1561,14 +1661,14 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1561,14 +1661,14 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1561 1661
1562 // cache the sequence header if h264 1662 // cache the sequence header if h264
1563 // donot cache the sequence header to gop_cache, return here. 1663 // donot cache the sequence header to gop_cache, return here.
1564 - if (SrsFlvCodec::video_is_sequence_header(msg.payload, msg.size)) { 1664 + if (SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size)) {
1565 srs_freep(cache_sh_video); 1665 srs_freep(cache_sh_video);
1566 - cache_sh_video = msg.copy(); 1666 + cache_sh_video = msg->copy();
1567 1667
1568 // parse detail audio codec 1668 // parse detail audio codec
1569 SrsAvcAacCodec codec; 1669 SrsAvcAacCodec codec;
1570 SrsCodecSample sample; 1670 SrsCodecSample sample;
1571 - if ((ret = codec.video_avc_demux(msg.payload, msg.size, &sample)) != ERROR_SUCCESS) { 1671 + if ((ret = codec.video_avc_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) {
1572 srs_error("source codec demux video failed. ret=%d", ret); 1672 srs_error("source codec demux video failed. ret=%d", ret);
1573 return ret; 1673 return ret;
1574 } 1674 }
@@ -1581,7 +1681,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1581,7 +1681,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1581 1681
1582 srs_trace("%dB video sh, " 1682 srs_trace("%dB video sh, "
1583 "codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %dfps, %ds)", 1683 "codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %dfps, %ds)",
1584 - msg.size, codec.video_codec_id, 1684 + msg->size, codec.video_codec_id,
1585 srs_codec_avc_profile2str(codec.avc_profile).c_str(), 1685 srs_codec_avc_profile2str(codec.avc_profile).c_str(),
1586 srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height, 1686 srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height,
1587 codec.video_data_rate / 1000, codec.frame_rate, codec.duration); 1687 codec.video_data_rate / 1000, codec.frame_rate, codec.duration);
@@ -1589,7 +1689,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1589,7 +1689,7 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1589 } 1689 }
1590 1690
1591 // cache the last gop packets 1691 // cache the last gop packets
1592 - if ((ret = gop_cache->cache(&msg)) != ERROR_SUCCESS) { 1692 + if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) {
1593 srs_error("gop cache msg failed. ret=%d", ret); 1693 srs_error("gop cache msg failed. ret=%d", ret);
1594 return ret; 1694 return ret;
1595 } 1695 }
@@ -1598,16 +1698,39 @@ int SrsSource::on_video(SrsCommonMessage* shared_video) @@ -1598,16 +1698,39 @@ int SrsSource::on_video(SrsCommonMessage* shared_video)
1598 // if atc, update the sequence header to abs time. 1698 // if atc, update the sequence header to abs time.
1599 if (atc) { 1699 if (atc) {
1600 if (cache_sh_video) { 1700 if (cache_sh_video) {
1601 - cache_sh_video->timestamp = msg.timestamp; 1701 + cache_sh_video->timestamp = msg->timestamp;
1602 } 1702 }
1603 if (cache_metadata) { 1703 if (cache_metadata) {
1604 - cache_metadata->timestamp = msg.timestamp; 1704 + cache_metadata->timestamp = msg->timestamp;
1605 } 1705 }
1606 } 1706 }
1607 1707
1608 return ret; 1708 return ret;
1609 } 1709 }
1610 1710
  1711 +int SrsSource::do_mix_correct(SrsSharedPtrMessage* msg)
  1712 +{
  1713 + int ret = ERROR_SUCCESS;
  1714 +
  1715 + // insert msg to the queue.
  1716 + mix_queue->push(msg->copy());
  1717 +
  1718 + // fetch someone from mix queue.
  1719 + SrsSharedPtrMessage* m = mix_queue->pop();
  1720 + if (!m) {
  1721 + return ret;
  1722 + }
  1723 + SrsAutoFree(SrsSharedPtrMessage, m);
  1724 +
  1725 + // consume the monotonically increase message.
  1726 + if (m->is_audio()) {
  1727 + return on_audio_imp(m);
  1728 + }
  1729 +
  1730 + srs_assert(m->is_video());
  1731 + return on_video_imp(m);
  1732 +}
  1733 +
1611 int SrsSource::on_aggregate(SrsCommonMessage* msg) 1734 int SrsSource::on_aggregate(SrsCommonMessage* msg)
1612 { 1735 {
1613 int ret = ERROR_SUCCESS; 1736 int ret = ERROR_SUCCESS;
@@ -1748,6 +1871,9 @@ int SrsSource::on_publish() @@ -1748,6 +1871,9 @@ int SrsSource::on_publish()
1748 // save its id to srouce id. 1871 // save its id to srouce id.
1749 on_source_id_changed(_srs_context->get_id()); 1872 on_source_id_changed(_srs_context->get_id());
1750 1873
  1874 + // reset the mix queue.
  1875 + mix_queue->clear();
  1876 +
1751 // create forwarders 1877 // create forwarders
1752 if ((ret = create_forwarders()) != ERROR_SUCCESS) { 1878 if ((ret = create_forwarders()) != ERROR_SUCCESS) {
1753 srs_error("create forwarders failed. ret=%d", ret); 1879 srs_error("create forwarders failed. ret=%d", ret);
@@ -369,6 +369,23 @@ public: @@ -369,6 +369,23 @@ public:
369 }; 369 };
370 370
371 /** 371 /**
  372 + * the mix queue to correct the timestamp for mix_correct algorithm.
  373 + */
  374 +class SrsMixQueue
  375 +{
  376 +private:
  377 + u_int32_t nb_videos;
  378 + std::multimap<int64_t, SrsSharedPtrMessage*> msgs;
  379 +public:
  380 + SrsMixQueue();
  381 + virtual ~SrsMixQueue();
  382 +public:
  383 + virtual void clear();
  384 + virtual void push(SrsSharedPtrMessage* msg);
  385 + virtual SrsSharedPtrMessage* pop();
  386 +};
  387 +
  388 +/**
372 * live streaming source. 389 * live streaming source.
373 */ 390 */
374 class SrsSource : public ISrsReloadHandler 391 class SrsSource : public ISrsReloadHandler
@@ -407,6 +424,9 @@ private: @@ -407,6 +424,9 @@ private:
407 std::vector<SrsConsumer*> consumers; 424 std::vector<SrsConsumer*> consumers;
408 // the time jitter algorithm for vhost. 425 // the time jitter algorithm for vhost.
409 SrsRtmpJitterAlgorithm jitter_algorithm; 426 SrsRtmpJitterAlgorithm jitter_algorithm;
  427 + // whether use interlaced/mixed algorithm to correct timestamp.
  428 + bool mix_correct;
  429 + SrsMixQueue* mix_queue;
410 // hls handler. 430 // hls handler.
411 #ifdef SRS_AUTO_HLS 431 #ifdef SRS_AUTO_HLS
412 SrsHls* hls; 432 SrsHls* hls;
@@ -474,6 +494,7 @@ public: @@ -474,6 +494,7 @@ public:
474 virtual int on_reload_vhost_gop_cache(std::string vhost); 494 virtual int on_reload_vhost_gop_cache(std::string vhost);
475 virtual int on_reload_vhost_queue_length(std::string vhost); 495 virtual int on_reload_vhost_queue_length(std::string vhost);
476 virtual int on_reload_vhost_time_jitter(std::string vhost); 496 virtual int on_reload_vhost_time_jitter(std::string vhost);
  497 + virtual int on_reload_vhost_mix_correct(std::string vhost);
477 virtual int on_reload_vhost_forward(std::string vhost); 498 virtual int on_reload_vhost_forward(std::string vhost);
478 virtual int on_reload_vhost_hls(std::string vhost); 499 virtual int on_reload_vhost_hls(std::string vhost);
479 virtual int on_reload_vhost_hds(std::string vhost); 500 virtual int on_reload_vhost_hds(std::string vhost);
@@ -495,8 +516,17 @@ public: @@ -495,8 +516,17 @@ public:
495 public: 516 public:
496 virtual bool can_publish(); 517 virtual bool can_publish();
497 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); 518 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
  519 +public:
498 virtual int on_audio(SrsCommonMessage* audio); 520 virtual int on_audio(SrsCommonMessage* audio);
  521 +private:
  522 + virtual int on_audio_imp(SrsSharedPtrMessage* audio);
  523 +public:
499 virtual int on_video(SrsCommonMessage* video); 524 virtual int on_video(SrsCommonMessage* video);
  525 +private:
  526 + virtual int on_video_imp(SrsSharedPtrMessage* video);
  527 +private:
  528 + virtual int do_mix_correct(SrsSharedPtrMessage* msg);
  529 +public:
500 virtual int on_aggregate(SrsCommonMessage* msg); 530 virtual int on_aggregate(SrsCommonMessage* msg);
501 /** 531 /**
502 * the pre-publish is we are very sure we are 532 * the pre-publish is we are very sure we are
@@ -1979,6 +1979,21 @@ srs_bool srs_utils_flv_tag_is_ok(char type) @@ -1979,6 +1979,21 @@ srs_bool srs_utils_flv_tag_is_ok(char type)
1979 return type == SRS_RTMP_TYPE_AUDIO || type == SRS_RTMP_TYPE_VIDEO || type == SRS_RTMP_TYPE_SCRIPT; 1979 return type == SRS_RTMP_TYPE_AUDIO || type == SRS_RTMP_TYPE_VIDEO || type == SRS_RTMP_TYPE_SCRIPT;
1980 } 1980 }
1981 1981
  1982 +srs_bool srs_utils_flv_tag_is_audio(char type)
  1983 +{
  1984 + return type == SRS_RTMP_TYPE_AUDIO;
  1985 +}
  1986 +
  1987 +srs_bool srs_utils_flv_tag_is_video(char type)
  1988 +{
  1989 + return type == SRS_RTMP_TYPE_VIDEO;
  1990 +}
  1991 +
  1992 +srs_bool srs_utils_flv_tag_is_av(char type)
  1993 +{
  1994 + return type == SRS_RTMP_TYPE_AUDIO || type == SRS_RTMP_TYPE_VIDEO;
  1995 +}
  1996 +
1982 char srs_utils_flv_video_codec_id(char* data, int size) 1997 char srs_utils_flv_video_codec_id(char* data, int size)
1983 { 1998 {
1984 if (size < 1) { 1999 if (size < 1) {
@@ -661,6 +661,9 @@ extern int srs_utils_parse_timestamp( @@ -661,6 +661,9 @@ extern int srs_utils_parse_timestamp(
661 * @return true when tag is video/audio/script-data; otherwise, false. 661 * @return true when tag is video/audio/script-data; otherwise, false.
662 */ 662 */
663 extern srs_bool srs_utils_flv_tag_is_ok(char type); 663 extern srs_bool srs_utils_flv_tag_is_ok(char type);
  664 +extern srs_bool srs_utils_flv_tag_is_audio(char type);
  665 +extern srs_bool srs_utils_flv_tag_is_video(char type);
  666 +extern srs_bool srs_utils_flv_tag_is_av(char type);
664 667
665 /** 668 /**
666 * get the CodecID of video tag. 669 * get the CodecID of video tag.