正在显示
15 个修改的文件
包含
623 行增加
和
108 行删除
| @@ -566,7 +566,9 @@ Supported operating systems and hardware: | @@ -566,7 +566,9 @@ Supported operating systems and hardware: | ||
| 566 | 566 | ||
| 567 | ### SRS 2.0 history | 567 | ### SRS 2.0 history |
| 568 | 568 | ||
| 569 | -* v2.0, 2015-03-30, for [#372](https://github.com/winlinvip/simple-rtmp-server/issues/372), support transform vhost of edge 2.0.155. | 569 | +* v2.0, 2015-04-04, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), rewrite annexb mux for ts, refer to apple sample. 2.0.157. |
| 570 | +* v2.0, 2015-04-03, enhanced avc decode, parse the sps get width+height. 2.0.156. | ||
| 571 | +* v2.0, 2015-04-03, for [#372](https://github.com/winlinvip/simple-rtmp-server/issues/372), support transform vhost of edge 2.0.155. | ||
| 570 | * v2.0, 2015-03-30, for [#366](https://github.com/winlinvip/simple-rtmp-server/issues/366), config hls to disable cleanup of ts. 2.0.154. | 572 | * v2.0, 2015-03-30, for [#366](https://github.com/winlinvip/simple-rtmp-server/issues/366), config hls to disable cleanup of ts. 2.0.154. |
| 571 | * v2.0, 2015-03-31, support server cycle handler. 2.0.153. | 573 | * v2.0, 2015-03-31, support server cycle handler. 2.0.153. |
| 572 | * v2.0, 2015-03-31, support on_hls for http hooks. 2.0.152. | 574 | * v2.0, 2015-03-31, support on_hls for http hooks. 2.0.152. |
| @@ -44,6 +44,11 @@ max_connections 1000; | @@ -44,6 +44,11 @@ max_connections 1000; | ||
| 44 | # @remark: donot support reload. | 44 | # @remark: donot support reload. |
| 45 | # default: on | 45 | # default: on |
| 46 | daemon on; | 46 | daemon on; |
| 47 | +# whether use utc_time to generate the time struct, | ||
| 48 | +# if off, use localtime() to generate it, | ||
| 49 | +# if on, use gmtime() instead, which use UTC time. | ||
| 50 | +# default: off | ||
| 51 | +utc_time off; | ||
| 47 | 52 | ||
| 48 | ############################################################################################# | 53 | ############################################################################################# |
| 49 | # heartbeat/stats sections | 54 | # heartbeat/stats sections |
| @@ -1336,7 +1336,8 @@ int SrsConfig::check_config() | @@ -1336,7 +1336,8 @@ int SrsConfig::check_config() | ||
| 1336 | && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" | 1336 | && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" |
| 1337 | && n != "max_connections" && n != "daemon" && n != "heartbeat" | 1337 | && n != "max_connections" && n != "daemon" && n != "heartbeat" |
| 1338 | && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms" | 1338 | && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms" |
| 1339 | - && n != "http_stream" && n != "http_server" && n != "stream_caster") | 1339 | + && n != "http_stream" && n != "http_server" && n != "stream_caster" |
| 1340 | + && n != "utc_time") | ||
| 1340 | { | 1341 | { |
| 1341 | ret = ERROR_SYSTEM_CONFIG_INVALID; | 1342 | ret = ERROR_SYSTEM_CONFIG_INVALID; |
| 1342 | srs_error("unsupported directive %s, ret=%d", n.c_str(), ret); | 1343 | srs_error("unsupported directive %s, ret=%d", n.c_str(), ret); |
| @@ -1896,6 +1897,16 @@ int SrsConfig::get_pithy_print_ms() | @@ -1896,6 +1897,16 @@ int SrsConfig::get_pithy_print_ms() | ||
| 1896 | return ::atoi(pithy->arg0().c_str()); | 1897 | return ::atoi(pithy->arg0().c_str()); |
| 1897 | } | 1898 | } |
| 1898 | 1899 | ||
| 1900 | +bool SrsConfig::get_utc_time() | ||
| 1901 | +{ | ||
| 1902 | + SrsConfDirective* utc = root->get("utc_time"); | ||
| 1903 | + if (!utc || utc->arg0().empty()) { | ||
| 1904 | + return SRS_CONF_DEFAULT_UTC_TIME; | ||
| 1905 | + } | ||
| 1906 | + | ||
| 1907 | + return utc->arg0() == "on"; | ||
| 1908 | +} | ||
| 1909 | + | ||
| 1899 | vector<SrsConfDirective*> SrsConfig::get_stream_casters() | 1910 | vector<SrsConfDirective*> SrsConfig::get_stream_casters() |
| 1900 | { | 1911 | { |
| 1901 | srs_assert(root); | 1912 | srs_assert(root); |
| @@ -43,6 +43,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -43,6 +43,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 43 | #define SRS_CONF_DEFAULT_LOG_TANK_CONSOLE "console" | 43 | #define SRS_CONF_DEFAULT_LOG_TANK_CONSOLE "console" |
| 44 | #define SRS_CONF_DEFAULT_COFNIG_FILE "conf/srs.conf" | 44 | #define SRS_CONF_DEFAULT_COFNIG_FILE "conf/srs.conf" |
| 45 | #define SRS_CONF_DEFAULT_FF_LOG_DIR "./objs" | 45 | #define SRS_CONF_DEFAULT_FF_LOG_DIR "./objs" |
| 46 | +#define SRS_CONF_DEFAULT_UTC_TIME false | ||
| 46 | 47 | ||
| 47 | #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000 | 48 | #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000 |
| 48 | #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" | 49 | #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" |
| @@ -435,6 +436,10 @@ public: | @@ -435,6 +436,10 @@ public: | ||
| 435 | * every this interval in ms. | 436 | * every this interval in ms. |
| 436 | */ | 437 | */ |
| 437 | virtual int get_pithy_print_ms(); | 438 | virtual int get_pithy_print_ms(); |
| 439 | + /** | ||
| 440 | + * whether use utc-time to format the time. | ||
| 441 | + */ | ||
| 442 | + virtual bool get_utc_time(); | ||
| 438 | // stream_caster section | 443 | // stream_caster section |
| 439 | public: | 444 | public: |
| 440 | /** | 445 | /** |
| @@ -312,12 +312,6 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | @@ -312,12 +312,6 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | ||
| 312 | m3u8 = path + "/" + m3u8_file; | 312 | m3u8 = path + "/" + m3u8_file; |
| 313 | m3u8 = srs_path_build_stream(m3u8, req->vhost, req->app, req->stream); | 313 | m3u8 = srs_path_build_stream(m3u8, req->vhost, req->app, req->stream); |
| 314 | 314 | ||
| 315 | - m3u8_dir = m3u8; | ||
| 316 | - size_t pos = string::npos; | ||
| 317 | - if ((pos = m3u8_dir.rfind("/")) != string::npos) { | ||
| 318 | - m3u8_dir = m3u8_dir.substr(0, pos); | ||
| 319 | - } | ||
| 320 | - | ||
| 321 | // we always keep the target duration increasing. | 315 | // we always keep the target duration increasing. |
| 322 | int max_td = srs_max(target_duration, (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost))); | 316 | int max_td = srs_max(target_duration, (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost))); |
| 323 | srs_info("hls update target duration %d=>%d, aof=%.2f", target_duration, max_td, aof_ratio); | 317 | srs_info("hls update target duration %d=>%d, aof=%.2f", target_duration, max_td, aof_ratio); |
| @@ -336,6 +330,14 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | @@ -336,6 +330,14 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | ||
| 336 | should_write_file = true; | 330 | should_write_file = true; |
| 337 | } | 331 | } |
| 338 | 332 | ||
| 333 | + // create m3u8 dir once. | ||
| 334 | + m3u8_dir = srs_path_dirname(m3u8); | ||
| 335 | + if (should_write_file && (ret = srs_create_dir_recursively(m3u8_dir)) != ERROR_SUCCESS) { | ||
| 336 | + srs_error("create app dir %s failed. ret=%d", m3u8_dir.c_str(), ret); | ||
| 337 | + return ret; | ||
| 338 | + } | ||
| 339 | + srs_info("create m3u8 dir %s ok", m3u8_dir.c_str()); | ||
| 340 | + | ||
| 339 | return ret; | 341 | return ret; |
| 340 | } | 342 | } |
| 341 | 343 | ||
| @@ -434,11 +436,12 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) | @@ -434,11 +436,12 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) | ||
| 434 | current->uri += ts_url; | 436 | current->uri += ts_url; |
| 435 | 437 | ||
| 436 | // create dir recursively for hls. | 438 | // create dir recursively for hls. |
| 437 | - if (should_write_file && (ret = srs_create_dir_recursively(m3u8_dir)) != ERROR_SUCCESS) { | ||
| 438 | - srs_error("create app dir %s failed. ret=%d", m3u8_dir.c_str(), ret); | 439 | + std::string ts_dir = srs_path_dirname(current->full_path); |
| 440 | + if (should_write_file && (ret = srs_create_dir_recursively(ts_dir)) != ERROR_SUCCESS) { | ||
| 441 | + srs_error("create app dir %s failed. ret=%d", ts_dir.c_str(), ret); | ||
| 439 | return ret; | 442 | return ret; |
| 440 | } | 443 | } |
| 441 | - srs_info("create app dir %s ok", m3u8_dir.c_str()); | 444 | + srs_info("create ts dir %s ok", ts_dir.c_str()); |
| 442 | 445 | ||
| 443 | // open temp ts file. | 446 | // open temp ts file. |
| 444 | std::string tmp_file = current->full_path + ".tmp"; | 447 | std::string tmp_file = current->full_path + ".tmp"; |
| @@ -751,7 +754,7 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) | @@ -751,7 +754,7 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) | ||
| 751 | // "#EXTINF:4294967295.208,\n" | 754 | // "#EXTINF:4294967295.208,\n" |
| 752 | ss.precision(3); | 755 | ss.precision(3); |
| 753 | ss.setf(std::ios::fixed, std::ios::floatfield); | 756 | ss.setf(std::ios::fixed, std::ios::floatfield); |
| 754 | - ss << "#EXTINF:" << segment->duration << "," << SRS_CONSTS_LF; | 757 | + ss << "#EXTINF:" << segment->duration << ", no desc" << SRS_CONSTS_LF; |
| 755 | srs_verbose("write m3u8 segment info success."); | 758 | srs_verbose("write m3u8 segment info success."); |
| 756 | 759 | ||
| 757 | // {file name}\n | 760 | // {file name}\n |
| @@ -896,6 +899,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | @@ -896,6 +899,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | ||
| 896 | // we use absolutely overflow of segment to make jwplayer/ffplay happy | 899 | // we use absolutely overflow of segment to make jwplayer/ffplay happy |
| 897 | // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-71155184 | 900 | // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-71155184 |
| 898 | if (cache->audio && muxer->is_segment_absolutely_overflow()) { | 901 | if (cache->audio && muxer->is_segment_absolutely_overflow()) { |
| 902 | + srs_warn("hls: absolute audio reap segment."); | ||
| 899 | if ((ret = reap_segment("audio", muxer, cache->audio->pts)) != ERROR_SUCCESS) { | 903 | if ((ret = reap_segment("audio", muxer, cache->audio->pts)) != ERROR_SUCCESS) { |
| 900 | return ret; | 904 | return ret; |
| 901 | } | 905 | } |
| @@ -914,9 +918,12 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | @@ -914,9 +918,12 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | ||
| 914 | } | 918 | } |
| 915 | 919 | ||
| 916 | // new segment when: | 920 | // new segment when: |
| 917 | - // 1. base on gop. | 921 | + // 1. base on gop(IDR). |
| 918 | // 2. some gops duration overflow. | 922 | // 2. some gops duration overflow. |
| 919 | if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && muxer->is_segment_overflow()) { | 923 | if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && muxer->is_segment_overflow()) { |
| 924 | + if (!sample->has_idr) { | ||
| 925 | + srs_warn("hls: ts starts without IDR, first nalu=%d", sample->first_nalu_type); | ||
| 926 | + } | ||
| 920 | if ((ret = reap_segment("video", muxer, cache->video->dts)) != ERROR_SUCCESS) { | 927 | if ((ret = reap_segment("video", muxer, cache->video->dts)) != ERROR_SUCCESS) { |
| 921 | return ret; | 928 | return ret; |
| 922 | } | 929 | } |
| @@ -936,19 +943,21 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme | @@ -936,19 +943,21 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme | ||
| 936 | { | 943 | { |
| 937 | int ret = ERROR_SUCCESS; | 944 | int ret = ERROR_SUCCESS; |
| 938 | 945 | ||
| 946 | + // TODO: flush audio before or after segment? | ||
| 947 | + // TODO: fresh segment begin with audio or video? | ||
| 948 | + | ||
| 949 | + // close current ts. | ||
| 939 | if ((ret = muxer->segment_close(log_desc)) != ERROR_SUCCESS) { | 950 | if ((ret = muxer->segment_close(log_desc)) != ERROR_SUCCESS) { |
| 940 | srs_error("m3u8 muxer close segment failed. ret=%d", ret); | 951 | srs_error("m3u8 muxer close segment failed. ret=%d", ret); |
| 941 | return ret; | 952 | return ret; |
| 942 | } | 953 | } |
| 943 | 954 | ||
| 955 | + // open new ts. | ||
| 944 | if ((ret = muxer->segment_open(segment_start_dts)) != ERROR_SUCCESS) { | 956 | if ((ret = muxer->segment_open(segment_start_dts)) != ERROR_SUCCESS) { |
| 945 | srs_error("m3u8 muxer open segment failed. ret=%d", ret); | 957 | srs_error("m3u8 muxer open segment failed. ret=%d", ret); |
| 946 | return ret; | 958 | return ret; |
| 947 | } | 959 | } |
| 948 | 960 | ||
| 949 | - // TODO: flush audio before or after segment? | ||
| 950 | - // TODO: fresh segment begin with audio or video? | ||
| 951 | - | ||
| 952 | // segment open, flush video first. | 961 | // segment open, flush video first. |
| 953 | if ((ret = muxer->flush_video(cache)) != ERROR_SUCCESS) { | 962 | if ((ret = muxer->flush_video(cache)) != ERROR_SUCCESS) { |
| 954 | srs_error("m3u8 muxer flush video failed. ret=%d", ret); | 963 | srs_error("m3u8 muxer flush video failed. ret=%d", ret); |
| @@ -274,9 +274,15 @@ bool SrsFastLog::generate_header(bool error, const char* tag, int context_id, co | @@ -274,9 +274,15 @@ bool SrsFastLog::generate_header(bool error, const char* tag, int context_id, co | ||
| 274 | 274 | ||
| 275 | // to calendar time | 275 | // to calendar time |
| 276 | struct tm* tm; | 276 | struct tm* tm; |
| 277 | + if (_srs_config->get_utc_time()) { | ||
| 278 | + if ((tm = gmtime(&tv.tv_sec)) == NULL) { | ||
| 279 | + return false; | ||
| 280 | + } | ||
| 281 | + } else { | ||
| 277 | if ((tm = localtime(&tv.tv_sec)) == NULL) { | 282 | if ((tm = localtime(&tv.tv_sec)) == NULL) { |
| 278 | return false; | 283 | return false; |
| 279 | } | 284 | } |
| 285 | + } | ||
| 280 | 286 | ||
| 281 | // write log header | 287 | // write log header |
| 282 | int log_header_size = -1; | 288 | int log_header_size = -1; |
| @@ -140,9 +140,15 @@ string srs_path_build_timestamp(string template_path) | @@ -140,9 +140,15 @@ string srs_path_build_timestamp(string template_path) | ||
| 140 | 140 | ||
| 141 | // to calendar time | 141 | // to calendar time |
| 142 | struct tm* tm; | 142 | struct tm* tm; |
| 143 | + if (_srs_config->get_utc_time()) { | ||
| 144 | + if ((tm = gmtime(&tv.tv_sec)) == NULL) { | ||
| 145 | + return path; | ||
| 146 | + } | ||
| 147 | + } else { | ||
| 143 | if ((tm = localtime(&tv.tv_sec)) == NULL) { | 148 | if ((tm = localtime(&tv.tv_sec)) == NULL) { |
| 144 | return path; | 149 | return path; |
| 145 | } | 150 | } |
| 151 | + } | ||
| 146 | 152 | ||
| 147 | // the buffer to format the date and time. | 153 | // the buffer to format the date and time. |
| 148 | char buf[64]; | 154 | char buf[64]; |
| @@ -154,32 +160,32 @@ string srs_path_build_timestamp(string template_path) | @@ -154,32 +160,32 @@ string srs_path_build_timestamp(string template_path) | ||
| 154 | } | 160 | } |
| 155 | // [2006], replace with current year. | 161 | // [2006], replace with current year. |
| 156 | if (true) { | 162 | if (true) { |
| 157 | - snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year); | 163 | + snprintf(buf, sizeof(buf), "%04d", 1900 + tm->tm_year); |
| 158 | path = srs_string_replace(path, "[2006]", buf); | 164 | path = srs_string_replace(path, "[2006]", buf); |
| 159 | } | 165 | } |
| 160 | // [01], replace this const to current month. | 166 | // [01], replace this const to current month. |
| 161 | if (true) { | 167 | if (true) { |
| 162 | - snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon); | 168 | + snprintf(buf, sizeof(buf), "%02d", 1 + tm->tm_mon); |
| 163 | path = srs_string_replace(path, "[01]", buf); | 169 | path = srs_string_replace(path, "[01]", buf); |
| 164 | } | 170 | } |
| 165 | // [02], replace this const to current date. | 171 | // [02], replace this const to current date. |
| 166 | if (true) { | 172 | if (true) { |
| 167 | - snprintf(buf, sizeof(buf), "%d", tm->tm_mday); | 173 | + snprintf(buf, sizeof(buf), "%02d", tm->tm_mday); |
| 168 | path = srs_string_replace(path, "[02]", buf); | 174 | path = srs_string_replace(path, "[02]", buf); |
| 169 | } | 175 | } |
| 170 | // [15], replace this const to current hour. | 176 | // [15], replace this const to current hour. |
| 171 | if (true) { | 177 | if (true) { |
| 172 | - snprintf(buf, sizeof(buf), "%d", tm->tm_hour); | 178 | + snprintf(buf, sizeof(buf), "%02d", tm->tm_hour); |
| 173 | path = srs_string_replace(path, "[15]", buf); | 179 | path = srs_string_replace(path, "[15]", buf); |
| 174 | } | 180 | } |
| 175 | // [04], repleace this const to current minute. | 181 | // [04], repleace this const to current minute. |
| 176 | if (true) { | 182 | if (true) { |
| 177 | - snprintf(buf, sizeof(buf), "%d", tm->tm_min); | 183 | + snprintf(buf, sizeof(buf), "%02d", tm->tm_min); |
| 178 | path = srs_string_replace(path, "[04]", buf); | 184 | path = srs_string_replace(path, "[04]", buf); |
| 179 | } | 185 | } |
| 180 | // [05], repleace this const to current second. | 186 | // [05], repleace this const to current second. |
| 181 | if (true) { | 187 | if (true) { |
| 182 | - snprintf(buf, sizeof(buf), "%d", tm->tm_sec); | 188 | + snprintf(buf, sizeof(buf), "%02d", tm->tm_sec); |
| 183 | path = srs_string_replace(path, "[05]", buf); | 189 | path = srs_string_replace(path, "[05]", buf); |
| 184 | } | 190 | } |
| 185 | // [999], repleace this const to current millisecond. | 191 | // [999], repleace this const to current millisecond. |
| @@ -31,6 +31,7 @@ using namespace std; | @@ -31,6 +31,7 @@ using namespace std; | ||
| 31 | #include <srs_kernel_log.hpp> | 31 | #include <srs_kernel_log.hpp> |
| 32 | #include <srs_kernel_stream.hpp> | 32 | #include <srs_kernel_stream.hpp> |
| 33 | #include <srs_kernel_utility.hpp> | 33 | #include <srs_kernel_utility.hpp> |
| 34 | +#include <srs_core_autofree.hpp> | ||
| 34 | 35 | ||
| 35 | string srs_codec_video2str(SrsCodecVideo codec) | 36 | string srs_codec_video2str(SrsCodecVideo codec) |
| 36 | { | 37 | { |
| @@ -265,6 +266,30 @@ bool SrsFlvCodec::audio_is_aac(char* data, int size) | @@ -265,6 +266,30 @@ bool SrsFlvCodec::audio_is_aac(char* data, int size) | ||
| 265 | return sound_format == SrsCodecAudioAAC; | 266 | return sound_format == SrsCodecAudioAAC; |
| 266 | } | 267 | } |
| 267 | 268 | ||
| 269 | +string srs_codec_avc_nalu2str(SrsAvcNaluType nalu_type) | ||
| 270 | +{ | ||
| 271 | + switch (nalu_type) { | ||
| 272 | + case SrsAvcNaluTypeNonIDR: return "NonIDR"; | ||
| 273 | + case SrsAvcNaluTypeDataPartitionA: return "DataPartitionA"; | ||
| 274 | + case SrsAvcNaluTypeDataPartitionB: return "DataPartitionB"; | ||
| 275 | + case SrsAvcNaluTypeDataPartitionC: return "DataPartitionC"; | ||
| 276 | + case SrsAvcNaluTypeIDR: return "IDR"; | ||
| 277 | + case SrsAvcNaluTypeSEI: return "SEI"; | ||
| 278 | + case SrsAvcNaluTypeSPS: return "SPS"; | ||
| 279 | + case SrsAvcNaluTypePPS: return "PPS"; | ||
| 280 | + case SrsAvcNaluTypeAccessUnitDelimiter: return "AccessUnitDelimiter"; | ||
| 281 | + case SrsAvcNaluTypeEOSequence: return "EOSequence"; | ||
| 282 | + case SrsAvcNaluTypeEOStream: return "EOStream"; | ||
| 283 | + case SrsAvcNaluTypeFilterData: return "FilterData"; | ||
| 284 | + case SrsAvcNaluTypeSPSExt: return "SPSExt"; | ||
| 285 | + case SrsAvcNaluTypePrefixNALU: return "PrefixNALU"; | ||
| 286 | + case SrsAvcNaluTypeSubsetSPS: return "SubsetSPS"; | ||
| 287 | + case SrsAvcNaluTypeLayerWithoutPartition: return "LayerWithoutPartition"; | ||
| 288 | + case SrsAvcNaluTypeCodedSliceExt: return "CodedSliceExt"; | ||
| 289 | + case SrsAvcNaluTypeReserved: default: return "Other"; | ||
| 290 | + } | ||
| 291 | +} | ||
| 292 | + | ||
| 268 | SrsCodecSampleUnit::SrsCodecSampleUnit() | 293 | SrsCodecSampleUnit::SrsCodecSampleUnit() |
| 269 | { | 294 | { |
| 270 | size = 0; | 295 | size = 0; |
| @@ -292,6 +317,8 @@ void SrsCodecSample::clear() | @@ -292,6 +317,8 @@ void SrsCodecSample::clear() | ||
| 292 | cts = 0; | 317 | cts = 0; |
| 293 | frame_type = SrsCodecVideoAVCFrameReserved; | 318 | frame_type = SrsCodecVideoAVCFrameReserved; |
| 294 | avc_packet_type = SrsCodecVideoAVCTypeReserved; | 319 | avc_packet_type = SrsCodecVideoAVCTypeReserved; |
| 320 | + has_idr = false; | ||
| 321 | + first_nalu_type = SrsAvcNaluTypeReserved; | ||
| 295 | 322 | ||
| 296 | acodec = SrsCodecAudioReserved1; | 323 | acodec = SrsCodecAudioReserved1; |
| 297 | sound_rate = SrsCodecAudioSampleRateReserved; | 324 | sound_rate = SrsCodecAudioSampleRateReserved; |
| @@ -315,6 +342,19 @@ int SrsCodecSample::add_sample_unit(char* bytes, int size) | @@ -315,6 +342,19 @@ int SrsCodecSample::add_sample_unit(char* bytes, int size) | ||
| 315 | sample_unit->bytes = bytes; | 342 | sample_unit->bytes = bytes; |
| 316 | sample_unit->size = size; | 343 | sample_unit->size = size; |
| 317 | 344 | ||
| 345 | + // for video, parse the nalu type, set the IDR flag. | ||
| 346 | + if (is_video) { | ||
| 347 | + SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(bytes[0] & 0x1f); | ||
| 348 | + | ||
| 349 | + if (nal_unit_type == SrsAvcNaluTypeIDR) { | ||
| 350 | + has_idr = true; | ||
| 351 | + } | ||
| 352 | + | ||
| 353 | + if (first_nalu_type == SrsAvcNaluTypeReserved) { | ||
| 354 | + first_nalu_type = nal_unit_type; | ||
| 355 | + } | ||
| 356 | + } | ||
| 357 | + | ||
| 318 | return ret; | 358 | return ret; |
| 319 | } | 359 | } |
| 320 | 360 | ||
| @@ -713,7 +753,8 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream) | @@ -713,7 +753,8 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream) | ||
| 713 | return ret; | 753 | return ret; |
| 714 | } | 754 | } |
| 715 | 755 | ||
| 716 | - // 1 sps | 756 | + // 1 sps, 7.3.2.1 Sequence parameter set RBSP syntax |
| 757 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 45. | ||
| 717 | if (!stream->require(1)) { | 758 | if (!stream->require(1)) { |
| 718 | ret = ERROR_HLS_DECODE_ERROR; | 759 | ret = ERROR_HLS_DECODE_ERROR; |
| 719 | srs_error("avc decode sequenc header sps failed. ret=%d", ret); | 760 | srs_error("avc decode sequenc header sps failed. ret=%d", ret); |
| @@ -740,8 +781,7 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream) | @@ -740,8 +781,7 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream) | ||
| 740 | if (sequenceParameterSetLength > 0) { | 781 | if (sequenceParameterSetLength > 0) { |
| 741 | srs_freep(sequenceParameterSetNALUnit); | 782 | srs_freep(sequenceParameterSetNALUnit); |
| 742 | sequenceParameterSetNALUnit = new char[sequenceParameterSetLength]; | 783 | sequenceParameterSetNALUnit = new char[sequenceParameterSetLength]; |
| 743 | - memcpy(sequenceParameterSetNALUnit, stream->data() + stream->pos(), sequenceParameterSetLength); | ||
| 744 | - stream->skip(sequenceParameterSetLength); | 784 | + stream->read_bytes(sequenceParameterSetNALUnit, sequenceParameterSetLength); |
| 745 | } | 785 | } |
| 746 | // 1 pps | 786 | // 1 pps |
| 747 | if (!stream->require(1)) { | 787 | if (!stream->require(1)) { |
| @@ -770,10 +810,242 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream) | @@ -770,10 +810,242 @@ int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream) | ||
| 770 | if (pictureParameterSetLength > 0) { | 810 | if (pictureParameterSetLength > 0) { |
| 771 | srs_freep(pictureParameterSetNALUnit); | 811 | srs_freep(pictureParameterSetNALUnit); |
| 772 | pictureParameterSetNALUnit = new char[pictureParameterSetLength]; | 812 | pictureParameterSetNALUnit = new char[pictureParameterSetLength]; |
| 773 | - memcpy(pictureParameterSetNALUnit, stream->data() + stream->pos(), pictureParameterSetLength); | ||
| 774 | - stream->skip(pictureParameterSetLength); | 813 | + stream->read_bytes(pictureParameterSetNALUnit, pictureParameterSetLength); |
| 814 | + } | ||
| 815 | + | ||
| 816 | + return avc_demux_sps(); | ||
| 817 | +} | ||
| 818 | + | ||
| 819 | +int SrsAvcAacCodec::avc_demux_sps() | ||
| 820 | +{ | ||
| 821 | + int ret = ERROR_SUCCESS; | ||
| 822 | + | ||
| 823 | + if (!sequenceParameterSetLength) { | ||
| 824 | + return ret; | ||
| 825 | + } | ||
| 826 | + | ||
| 827 | + SrsStream stream; | ||
| 828 | + if ((ret = stream.initialize(sequenceParameterSetNALUnit, sequenceParameterSetLength)) != ERROR_SUCCESS) { | ||
| 829 | + return ret; | ||
| 830 | + } | ||
| 831 | + | ||
| 832 | + // for NALU, 7.3.1 NAL unit syntax | ||
| 833 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 61. | ||
| 834 | + if (!stream.require(1)) { | ||
| 835 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 836 | + srs_error("avc decode sps failed. ret=%d", ret); | ||
| 837 | + return ret; | ||
| 838 | + } | ||
| 839 | + int8_t nutv = stream.read_1bytes(); | ||
| 840 | + | ||
| 841 | + // forbidden_zero_bit shall be equal to 0. | ||
| 842 | + int8_t forbidden_zero_bit = (nutv >> 7) & 0x01; | ||
| 843 | + if (forbidden_zero_bit) { | ||
| 844 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 845 | + srs_error("forbidden_zero_bit shall be equal to 0. ret=%d", ret); | ||
| 846 | + return ret; | ||
| 847 | + } | ||
| 848 | + | ||
| 849 | + // nal_ref_idc not equal to 0 specifies that the content of the NAL unit contains a sequence parameter set or a picture | ||
| 850 | + // parameter set or a slice of a reference picture or a slice data partition of a reference picture. | ||
| 851 | + int8_t nal_ref_idc = (nutv >> 5) & 0x03; | ||
| 852 | + if (!nal_ref_idc) { | ||
| 853 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 854 | + srs_error("for sps, nal_ref_idc shall be not be equal to 0. ret=%d", ret); | ||
| 855 | + return ret; | ||
| 856 | + } | ||
| 857 | + | ||
| 858 | + // 7.4.1 NAL unit semantics | ||
| 859 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 61. | ||
| 860 | + // nal_unit_type specifies the type of RBSP data structure contained in the NAL unit as specified in Table 7-1. | ||
| 861 | + SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(nutv & 0x1f); | ||
| 862 | + if (nal_unit_type != 7) { | ||
| 863 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 864 | + srs_error("for sps, nal_unit_type shall be equal to 7. ret=%d", ret); | ||
| 865 | + return ret; | ||
| 866 | + } | ||
| 867 | + | ||
| 868 | + // decode the rbsp from sps. | ||
| 869 | + // rbsp[ i ] a raw byte sequence payload is specified as an ordered sequence of bytes. | ||
| 870 | + int8_t* rbsp = new int8_t[sequenceParameterSetLength]; | ||
| 871 | + SrsAutoFree(int8_t, rbsp); | ||
| 872 | + | ||
| 873 | + int nb_rbsp = 0; | ||
| 874 | + while (!stream.empty()) { | ||
| 875 | + rbsp[nb_rbsp] = stream.read_1bytes(); | ||
| 876 | + | ||
| 877 | + // XX 00 00 03 XX, the 03 byte should be drop. | ||
| 878 | + if (nb_rbsp > 2 && rbsp[nb_rbsp - 2] == 0 && rbsp[nb_rbsp - 1] == 0 && rbsp[nb_rbsp] == 3) { | ||
| 879 | + continue; | ||
| 880 | + } | ||
| 881 | + | ||
| 882 | + nb_rbsp++; | ||
| 883 | + } | ||
| 884 | + | ||
| 885 | + return avc_demux_sps_rbsp((char*)rbsp, nb_rbsp); | ||
| 886 | +} | ||
| 887 | + | ||
| 888 | + | ||
| 889 | +int SrsAvcAacCodec::avc_demux_sps_rbsp(char* rbsp, int nb_rbsp) | ||
| 890 | +{ | ||
| 891 | + int ret = ERROR_SUCCESS; | ||
| 892 | + | ||
| 893 | + // reparse the rbsp. | ||
| 894 | + SrsStream stream; | ||
| 895 | + if ((ret = stream.initialize(rbsp, nb_rbsp)) != ERROR_SUCCESS) { | ||
| 896 | + return ret; | ||
| 897 | + } | ||
| 898 | + | ||
| 899 | + // for SPS, 7.3.2.1.1 Sequence parameter set data syntax | ||
| 900 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62. | ||
| 901 | + if (!stream.require(3)) { | ||
| 902 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 903 | + srs_error("sps shall atleast 3bytes. ret=%d", ret); | ||
| 904 | + return ret; | ||
| 905 | + } | ||
| 906 | + u_int8_t profile_idc = stream.read_1bytes(); | ||
| 907 | + if (!profile_idc) { | ||
| 908 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 909 | + srs_error("sps the profile_idc invalid. ret=%d", ret); | ||
| 910 | + return ret; | ||
| 911 | + } | ||
| 912 | + | ||
| 913 | + int8_t flags = stream.read_1bytes(); | ||
| 914 | + if (flags & 0x03) { | ||
| 915 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 916 | + srs_error("sps the flags invalid. ret=%d", ret); | ||
| 917 | + return ret; | ||
| 918 | + } | ||
| 919 | + | ||
| 920 | + u_int8_t level_idc = stream.read_1bytes(); | ||
| 921 | + if (!level_idc) { | ||
| 922 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 923 | + srs_error("sps the level_idc invalid. ret=%d", ret); | ||
| 924 | + return ret; | ||
| 775 | } | 925 | } |
| 776 | 926 | ||
| 927 | + SrsBitStream bs; | ||
| 928 | + if ((ret = bs.initialize(&stream)) != ERROR_SUCCESS) { | ||
| 929 | + return ret; | ||
| 930 | + } | ||
| 931 | + | ||
| 932 | + int64_t seq_parameter_set_id = -1; | ||
| 933 | + if ((ret = srs_avc_nalu_read_uev(&bs, seq_parameter_set_id)) != ERROR_SUCCESS) { | ||
| 934 | + return ret; | ||
| 935 | + } | ||
| 936 | + if (seq_parameter_set_id < 0) { | ||
| 937 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 938 | + srs_error("sps the seq_parameter_set_id invalid. ret=%d", ret); | ||
| 939 | + return ret; | ||
| 940 | + } | ||
| 941 | + srs_info("sps parse profile=%d, level=%d, sps_id=%d", profile_idc, level_idc, seq_parameter_set_id); | ||
| 942 | + | ||
| 943 | + if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 | ||
| 944 | + || profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc == 118 | ||
| 945 | + || profile_idc == 128 | ||
| 946 | + ) { | ||
| 947 | + int64_t chroma_format_idc = -1; | ||
| 948 | + if ((ret = srs_avc_nalu_read_uev(&bs, chroma_format_idc)) != ERROR_SUCCESS) { | ||
| 949 | + return ret; | ||
| 950 | + } | ||
| 951 | + if (chroma_format_idc == 3) { | ||
| 952 | + int8_t separate_colour_plane_flag = -1; | ||
| 953 | + if ((ret = srs_avc_nalu_read_bit(&bs, separate_colour_plane_flag)) != ERROR_SUCCESS) { | ||
| 954 | + return ret; | ||
| 955 | + } | ||
| 956 | + } | ||
| 957 | + | ||
| 958 | + int64_t bit_depth_luma_minus8 = -1; | ||
| 959 | + if ((ret = srs_avc_nalu_read_uev(&bs, bit_depth_luma_minus8)) != ERROR_SUCCESS) { | ||
| 960 | + return ret; | ||
| 961 | + } | ||
| 962 | + | ||
| 963 | + int64_t bit_depth_chroma_minus8 = -1; | ||
| 964 | + if ((ret = srs_avc_nalu_read_uev(&bs, bit_depth_chroma_minus8)) != ERROR_SUCCESS) { | ||
| 965 | + return ret; | ||
| 966 | + } | ||
| 967 | + | ||
| 968 | + int8_t qpprime_y_zero_transform_bypass_flag = -1; | ||
| 969 | + if ((ret = srs_avc_nalu_read_bit(&bs, qpprime_y_zero_transform_bypass_flag)) != ERROR_SUCCESS) { | ||
| 970 | + return ret; | ||
| 971 | + } | ||
| 972 | + | ||
| 973 | + int8_t seq_scaling_matrix_present_flag = -1; | ||
| 974 | + if ((ret = srs_avc_nalu_read_bit(&bs, seq_scaling_matrix_present_flag)) != ERROR_SUCCESS) { | ||
| 975 | + return ret; | ||
| 976 | + } | ||
| 977 | + if (seq_scaling_matrix_present_flag) { | ||
| 978 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 979 | + srs_error("sps the seq_scaling_matrix_present_flag invalid. ret=%d", ret); | ||
| 980 | + return ret; | ||
| 981 | + } | ||
| 982 | + } | ||
| 983 | + | ||
| 984 | + int64_t log2_max_frame_num_minus4 = -1; | ||
| 985 | + if ((ret = srs_avc_nalu_read_uev(&bs, log2_max_frame_num_minus4)) != ERROR_SUCCESS) { | ||
| 986 | + return ret; | ||
| 987 | + } | ||
| 988 | + | ||
| 989 | + int64_t pic_order_cnt_type = -1; | ||
| 990 | + if ((ret = srs_avc_nalu_read_uev(&bs, pic_order_cnt_type)) != ERROR_SUCCESS) { | ||
| 991 | + return ret; | ||
| 992 | + } | ||
| 993 | + | ||
| 994 | + if (pic_order_cnt_type == 0) { | ||
| 995 | + int64_t log2_max_pic_order_cnt_lsb_minus4 = -1; | ||
| 996 | + if ((ret = srs_avc_nalu_read_uev(&bs, log2_max_pic_order_cnt_lsb_minus4)) != ERROR_SUCCESS) { | ||
| 997 | + return ret; | ||
| 998 | + } | ||
| 999 | + } else if (pic_order_cnt_type == 1) { | ||
| 1000 | + int8_t delta_pic_order_always_zero_flag = -1; | ||
| 1001 | + if ((ret = srs_avc_nalu_read_bit(&bs, delta_pic_order_always_zero_flag)) != ERROR_SUCCESS) { | ||
| 1002 | + return ret; | ||
| 1003 | + } | ||
| 1004 | + | ||
| 1005 | + int64_t offset_for_non_ref_pic = -1; | ||
| 1006 | + if ((ret = srs_avc_nalu_read_uev(&bs, offset_for_non_ref_pic)) != ERROR_SUCCESS) { | ||
| 1007 | + return ret; | ||
| 1008 | + } | ||
| 1009 | + | ||
| 1010 | + int64_t offset_for_top_to_bottom_field = -1; | ||
| 1011 | + if ((ret = srs_avc_nalu_read_uev(&bs, offset_for_top_to_bottom_field)) != ERROR_SUCCESS) { | ||
| 1012 | + return ret; | ||
| 1013 | + } | ||
| 1014 | + | ||
| 1015 | + int64_t num_ref_frames_in_pic_order_cnt_cycle = -1; | ||
| 1016 | + if ((ret = srs_avc_nalu_read_uev(&bs, num_ref_frames_in_pic_order_cnt_cycle)) != ERROR_SUCCESS) { | ||
| 1017 | + return ret; | ||
| 1018 | + } | ||
| 1019 | + if (num_ref_frames_in_pic_order_cnt_cycle) { | ||
| 1020 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 1021 | + srs_error("sps the num_ref_frames_in_pic_order_cnt_cycle invalid. ret=%d", ret); | ||
| 1022 | + return ret; | ||
| 1023 | + } | ||
| 1024 | + } | ||
| 1025 | + | ||
| 1026 | + int64_t max_num_ref_frames = -1; | ||
| 1027 | + if ((ret = srs_avc_nalu_read_uev(&bs, max_num_ref_frames)) != ERROR_SUCCESS) { | ||
| 1028 | + return ret; | ||
| 1029 | + } | ||
| 1030 | + | ||
| 1031 | + int8_t gaps_in_frame_num_value_allowed_flag = -1; | ||
| 1032 | + if ((ret = srs_avc_nalu_read_bit(&bs, gaps_in_frame_num_value_allowed_flag)) != ERROR_SUCCESS) { | ||
| 1033 | + return ret; | ||
| 1034 | + } | ||
| 1035 | + | ||
| 1036 | + int64_t pic_width_in_mbs_minus1 = -1; | ||
| 1037 | + if ((ret = srs_avc_nalu_read_uev(&bs, pic_width_in_mbs_minus1)) != ERROR_SUCCESS) { | ||
| 1038 | + return ret; | ||
| 1039 | + } | ||
| 1040 | + | ||
| 1041 | + int64_t pic_height_in_map_units_minus1 = -1; | ||
| 1042 | + if ((ret = srs_avc_nalu_read_uev(&bs, pic_height_in_map_units_minus1)) != ERROR_SUCCESS) { | ||
| 1043 | + return ret; | ||
| 1044 | + } | ||
| 1045 | + | ||
| 1046 | + width = (int)(pic_width_in_mbs_minus1 + 1) * 16; | ||
| 1047 | + height = (int)(pic_height_in_map_units_minus1 + 1) * 16; | ||
| 1048 | + | ||
| 777 | return ret; | 1049 | return ret; |
| 778 | } | 1050 | } |
| 779 | 1051 |
| @@ -276,6 +276,52 @@ enum SrsCodecAudioSoundType | @@ -276,6 +276,52 @@ enum SrsCodecAudioSoundType | ||
| 276 | }; | 276 | }; |
| 277 | 277 | ||
| 278 | /** | 278 | /** |
| 279 | + * Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes | ||
| 280 | + * H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83. | ||
| 281 | + */ | ||
| 282 | +enum SrsAvcNaluType | ||
| 283 | +{ | ||
| 284 | + // Unspecified | ||
| 285 | + SrsAvcNaluTypeReserved = 0, | ||
| 286 | + | ||
| 287 | + // Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp( ) | ||
| 288 | + SrsAvcNaluTypeNonIDR = 1, | ||
| 289 | + // Coded slice data partition A slice_data_partition_a_layer_rbsp( ) | ||
| 290 | + SrsAvcNaluTypeDataPartitionA = 2, | ||
| 291 | + // Coded slice data partition B slice_data_partition_b_layer_rbsp( ) | ||
| 292 | + SrsAvcNaluTypeDataPartitionB = 3, | ||
| 293 | + // Coded slice data partition C slice_data_partition_c_layer_rbsp( ) | ||
| 294 | + SrsAvcNaluTypeDataPartitionC = 4, | ||
| 295 | + // Coded slice of an IDR picture slice_layer_without_partitioning_rbsp( ) | ||
| 296 | + SrsAvcNaluTypeIDR = 5, | ||
| 297 | + // Supplemental enhancement information (SEI) sei_rbsp( ) | ||
| 298 | + SrsAvcNaluTypeSEI = 6, | ||
| 299 | + // Sequence parameter set seq_parameter_set_rbsp( ) | ||
| 300 | + SrsAvcNaluTypeSPS = 7, | ||
| 301 | + // Picture parameter set pic_parameter_set_rbsp( ) | ||
| 302 | + SrsAvcNaluTypePPS = 8, | ||
| 303 | + // Access unit delimiter access_unit_delimiter_rbsp( ) | ||
| 304 | + SrsAvcNaluTypeAccessUnitDelimiter = 9, | ||
| 305 | + // End of sequence end_of_seq_rbsp( ) | ||
| 306 | + SrsAvcNaluTypeEOSequence = 10, | ||
| 307 | + // End of stream end_of_stream_rbsp( ) | ||
| 308 | + SrsAvcNaluTypeEOStream = 11, | ||
| 309 | + // Filler data filler_data_rbsp( ) | ||
| 310 | + SrsAvcNaluTypeFilterData = 12, | ||
| 311 | + // Sequence parameter set extension seq_parameter_set_extension_rbsp( ) | ||
| 312 | + SrsAvcNaluTypeSPSExt = 13, | ||
| 313 | + // Prefix NAL unit prefix_nal_unit_rbsp( ) | ||
| 314 | + SrsAvcNaluTypePrefixNALU = 14, | ||
| 315 | + // Subset sequence parameter set subset_seq_parameter_set_rbsp( ) | ||
| 316 | + SrsAvcNaluTypeSubsetSPS = 15, | ||
| 317 | + // Coded slice of an auxiliary coded picture without partitioning slice_layer_without_partitioning_rbsp( ) | ||
| 318 | + SrsAvcNaluTypeLayerWithoutPartition = 19, | ||
| 319 | + // Coded slice extension slice_layer_extension_rbsp( ) | ||
| 320 | + SrsAvcNaluTypeCodedSliceExt = 20, | ||
| 321 | +}; | ||
| 322 | +std::string srs_codec_avc_nalu2str(SrsAvcNaluType nalu_type); | ||
| 323 | + | ||
| 324 | +/** | ||
| 279 | * the codec sample unit. | 325 | * the codec sample unit. |
| 280 | * for h.264 video packet, a NALU is a sample unit. | 326 | * for h.264 video packet, a NALU is a sample unit. |
| 281 | * for aac raw audio packet, a NALU is the entire aac raw data. | 327 | * for aac raw audio packet, a NALU is the entire aac raw data. |
| @@ -334,6 +380,9 @@ public: | @@ -334,6 +380,9 @@ public: | ||
| 334 | // video specified | 380 | // video specified |
| 335 | SrsCodecVideoAVCFrame frame_type; | 381 | SrsCodecVideoAVCFrame frame_type; |
| 336 | SrsCodecVideoAVCType avc_packet_type; | 382 | SrsCodecVideoAVCType avc_packet_type; |
| 383 | + // whether sample_units contains IDR frame. | ||
| 384 | + bool has_idr; | ||
| 385 | + SrsAvcNaluType first_nalu_type; | ||
| 337 | public: | 386 | public: |
| 338 | // audio specified | 387 | // audio specified |
| 339 | SrsCodecAudio acodec; | 388 | SrsCodecAudio acodec; |
| @@ -581,6 +630,11 @@ private: | @@ -581,6 +630,11 @@ private: | ||
| 581 | */ | 630 | */ |
| 582 | virtual int avc_demux_sps_pps(SrsStream* stream); | 631 | virtual int avc_demux_sps_pps(SrsStream* stream); |
| 583 | /** | 632 | /** |
| 633 | + * decode the sps rbsp stream. | ||
| 634 | + */ | ||
| 635 | + virtual int avc_demux_sps(); | ||
| 636 | + virtual int avc_demux_sps_rbsp(char* rbsp, int nb_rbsp); | ||
| 637 | + /** | ||
| 584 | * demux the avc NALU in "AnnexB" | 638 | * demux the avc NALU in "AnnexB" |
| 585 | * from H.264-AVC-ISO_IEC_14496-10.pdf, page 211. | 639 | * from H.264-AVC-ISO_IEC_14496-10.pdf, page 211. |
| 586 | */ | 640 | */ |
| @@ -215,7 +215,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -215,7 +215,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 215 | #define ERROR_HTTP_DVR_CREATE_REQUEST 3053 | 215 | #define ERROR_HTTP_DVR_CREATE_REQUEST 3053 |
| 216 | #define ERROR_HTTP_DVR_NO_TAEGET 3054 | 216 | #define ERROR_HTTP_DVR_NO_TAEGET 3054 |
| 217 | #define ERROR_ADTS_ID_NOT_AAC 3055 | 217 | #define ERROR_ADTS_ID_NOT_AAC 3055 |
| 218 | - | ||
| 219 | // HDS error code | 218 | // HDS error code |
| 220 | #define ERROR_HDS_OPEN_F4M_FAILED 3056 | 219 | #define ERROR_HDS_OPEN_F4M_FAILED 3056 |
| 221 | #define ERROR_HDS_WRITE_F4M_FAILED 3057 | 220 | #define ERROR_HDS_WRITE_F4M_FAILED 3057 |
| @@ -254,6 +253,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -254,6 +253,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 254 | #define ERROR_STREAM_CASTER_FLV_TAG 4024 | 253 | #define ERROR_STREAM_CASTER_FLV_TAG 4024 |
| 255 | #define ERROR_HTTP_RESPONSE_EOF 4025 | 254 | #define ERROR_HTTP_RESPONSE_EOF 4025 |
| 256 | #define ERROR_HTTP_INVALID_CHUNK_HEADER 4026 | 255 | #define ERROR_HTTP_INVALID_CHUNK_HEADER 4026 |
| 256 | +#define ERROR_AVC_NALU_UEV 4027 | ||
| 257 | 257 | ||
| 258 | /////////////////////////////////////////////////////// | 258 | /////////////////////////////////////////////////////// |
| 259 | // user-define error. | 259 | // user-define error. |
| @@ -252,4 +252,38 @@ void SrsStream::write_bytes(char* data, int size) | @@ -252,4 +252,38 @@ void SrsStream::write_bytes(char* data, int size) | ||
| 252 | p += size; | 252 | p += size; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | +SrsBitStream::SrsBitStream() | ||
| 256 | +{ | ||
| 257 | + cb = 0; | ||
| 258 | + cb_left = 0; | ||
| 259 | + stream = NULL; | ||
| 260 | +} | ||
| 261 | + | ||
| 262 | +SrsBitStream::~SrsBitStream() | ||
| 263 | +{ | ||
| 264 | +} | ||
| 265 | + | ||
| 266 | +int SrsBitStream::initialize(SrsStream* s) { | ||
| 267 | + stream = s; | ||
| 268 | + return ERROR_SUCCESS; | ||
| 269 | +} | ||
| 270 | + | ||
| 271 | +bool SrsBitStream::empty() { | ||
| 272 | + if (cb_left) { | ||
| 273 | + return false; | ||
| 274 | + } | ||
| 275 | + return stream->empty(); | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | +int8_t SrsBitStream::read_bit() { | ||
| 279 | + if (!cb_left) { | ||
| 280 | + srs_assert(!stream->empty()); | ||
| 281 | + cb = stream->read_1bytes(); | ||
| 282 | + cb_left = 8; | ||
| 283 | + } | ||
| 284 | + | ||
| 285 | + int8_t v = (cb >> (cb_left - 1)) & 0x01; | ||
| 286 | + cb_left--; | ||
| 287 | + return v; | ||
| 288 | +} | ||
| 255 | 289 |
| @@ -154,4 +154,22 @@ public: | @@ -154,4 +154,22 @@ public: | ||
| 154 | virtual void write_bytes(char* data, int size); | 154 | virtual void write_bytes(char* data, int size); |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | +/** | ||
| 158 | + * the bit stream. | ||
| 159 | + */ | ||
| 160 | +class SrsBitStream | ||
| 161 | +{ | ||
| 162 | +private: | ||
| 163 | + int8_t cb; | ||
| 164 | + u_int8_t cb_left; | ||
| 165 | + SrsStream* stream; | ||
| 166 | +public: | ||
| 167 | + SrsBitStream(); | ||
| 168 | + virtual ~SrsBitStream(); | ||
| 169 | +public: | ||
| 170 | + virtual int initialize(SrsStream* s); | ||
| 171 | + virtual bool empty(); | ||
| 172 | + virtual int8_t read_bit(); | ||
| 173 | +}; | ||
| 174 | + | ||
| 157 | #endif | 175 | #endif |
| @@ -2835,106 +2835,130 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample) | @@ -2835,106 +2835,130 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample) | ||
| 2835 | { | 2835 | { |
| 2836 | int ret = ERROR_SUCCESS; | 2836 | int ret = ERROR_SUCCESS; |
| 2837 | 2837 | ||
| 2838 | - // for type1/5/6, insert aud packet. | ||
| 2839 | - u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; | ||
| 2840 | - | ||
| 2841 | - bool sps_pps_sent = false; | ||
| 2842 | - bool aud_sent = false; | 2838 | + // mux the samples in annexb format, |
| 2839 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 324. | ||
| 2843 | /** | 2840 | /** |
| 2844 | - * a ts sample is format as: | ||
| 2845 | * 00 00 00 01 // header | 2841 | * 00 00 00 01 // header |
| 2846 | * xxxxxxx // data bytes | 2842 | * xxxxxxx // data bytes |
| 2847 | * 00 00 01 // continue header | 2843 | * 00 00 01 // continue header |
| 2848 | * xxxxxxx // data bytes. | 2844 | * xxxxxxx // data bytes. |
| 2849 | - * so, for each sample, we append header in aud_nal, then appends the bytes in sample. | 2845 | + * |
| 2846 | + * nal_unit_type specifies the type of RBSP data structure contained in the NAL unit as specified in Table 7-1. | ||
| 2847 | + * Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes | ||
| 2848 | + * H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83. | ||
| 2849 | + * 1, Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp( ) | ||
| 2850 | + * 2, Coded slice data partition A slice_data_partition_a_layer_rbsp( ) | ||
| 2851 | + * 3, Coded slice data partition B slice_data_partition_b_layer_rbsp( ) | ||
| 2852 | + * 4, Coded slice data partition C slice_data_partition_c_layer_rbsp( ) | ||
| 2853 | + * 5, Coded slice of an IDR picture slice_layer_without_partitioning_rbsp( ) | ||
| 2854 | + * 6, Supplemental enhancement information (SEI) sei_rbsp( ) | ||
| 2855 | + * 7, Sequence parameter set seq_parameter_set_rbsp( ) | ||
| 2856 | + * 8, Picture parameter set pic_parameter_set_rbsp( ) | ||
| 2857 | + * 9, Access unit delimiter access_unit_delimiter_rbsp( ) | ||
| 2858 | + * 10, End of sequence end_of_seq_rbsp( ) | ||
| 2859 | + * 11, End of stream end_of_stream_rbsp( ) | ||
| 2860 | + * 12, Filler data filler_data_rbsp( ) | ||
| 2861 | + * 13, Sequence parameter set extension seq_parameter_set_extension_rbsp( ) | ||
| 2862 | + * 14, Prefix NAL unit prefix_nal_unit_rbsp( ) | ||
| 2863 | + * 15, Subset sequence parameter set subset_seq_parameter_set_rbsp( ) | ||
| 2864 | + * 19, Coded slice of an auxiliary coded picture without partitioning slice_layer_without_partitioning_rbsp( ) | ||
| 2865 | + * 20, Coded slice extension slice_layer_extension_rbsp( ) | ||
| 2866 | + * the first ts message of apple sample: | ||
| 2867 | + * annexb 4B header, 2B aud(nal_unit_type:6)(0x09 0xf0) | ||
| 2868 | + * annexb 4B header, 19B sps(nal_unit_type:7) | ||
| 2869 | + * annexb 3B header, 4B pps(nal_unit_type:8) | ||
| 2870 | + * annexb 3B header, 12B nalu(nal_unit_type:6) | ||
| 2871 | + * annexb 3B header, 21B nalu(nal_unit_type:6) | ||
| 2872 | + * annexb 3B header, 2762B nalu(nal_unit_type:5) | ||
| 2873 | + * annexb 3B header, 3535B nalu(nal_unit_type:5) | ||
| 2874 | + * the second ts message of apple ts sample: | ||
| 2875 | + * annexb 4B header, 2B aud(nal_unit_type:6)(0x09 0xf0) | ||
| 2876 | + * annexb 3B header, 21B nalu(nal_unit_type:6) | ||
| 2877 | + * annexb 3B header, 379B nalu(nal_unit_type:1) | ||
| 2878 | + * annexb 3B header, 406B nalu(nal_unit_type:1) | ||
| 2850 | */ | 2879 | */ |
| 2851 | - for (int i = 0; i < sample->nb_sample_units; i++) { | ||
| 2852 | - SrsCodecSampleUnit* sample_unit = &sample->sample_units[i]; | ||
| 2853 | - int32_t size = sample_unit->size; | ||
| 2854 | - | ||
| 2855 | - if (!sample_unit->bytes || size <= 0) { | ||
| 2856 | - ret = ERROR_HLS_AVC_SAMPLE_SIZE; | ||
| 2857 | - srs_error("invalid avc sample length=%d, ret=%d", size, ret); | ||
| 2858 | - return ret; | ||
| 2859 | - } | ||
| 2860 | - | ||
| 2861 | - /** | ||
| 2862 | - * step 1: | ||
| 2863 | - * first, before each "real" sample, | ||
| 2864 | - * we add some packets according to the nal_unit_type, | ||
| 2865 | - * for example, when got nal_unit_type=5, insert SPS/PPS before sample. | ||
| 2866 | - */ | ||
| 2867 | - | ||
| 2868 | - // 5bits, 7.3.1 NAL unit syntax, | ||
| 2869 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 2870 | - u_int8_t nal_unit_type; | ||
| 2871 | - nal_unit_type = *sample_unit->bytes; | ||
| 2872 | - nal_unit_type &= 0x1f; | ||
| 2873 | - | ||
| 2874 | - // @see: ngx_rtmp_hls_video | ||
| 2875 | - // Table 7-1 NAL unit type codes, page 61 | ||
| 2876 | - // 1: Coded slice | ||
| 2877 | - if (nal_unit_type == 1) { | ||
| 2878 | - sps_pps_sent = false; | ||
| 2879 | - } | ||
| 2880 | - | ||
| 2881 | - // 6: Supplemental enhancement information (SEI) sei_rbsp( ), page 61 | ||
| 2882 | - // @see: ngx_rtmp_hls_append_aud | ||
| 2883 | - if (!aud_sent) { | ||
| 2884 | - // @remark, when got type 9, we donot send aud_nal, but it will make | ||
| 2885 | - // ios unhappy, so we remove it. | ||
| 2886 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/281 | ||
| 2887 | - /*if (nal_unit_type == 9) { | ||
| 2888 | - aud_sent = true; | ||
| 2889 | - }*/ | ||
| 2890 | - | ||
| 2891 | - if (nal_unit_type == 1 || nal_unit_type == 5 || nal_unit_type == 6) { | ||
| 2892 | - // for type 6, append a aud with type 9. | ||
| 2893 | - video->payload->append((const char*)aud_nal, sizeof(aud_nal)); | ||
| 2894 | - aud_sent = true; | ||
| 2895 | - } | ||
| 2896 | - } | ||
| 2897 | - | ||
| 2898 | - // 5: Coded slice of an IDR picture. | ||
| 2899 | - // insert sps/pps before IDR or key frame is ok. | ||
| 2900 | - if (nal_unit_type == 5 && !sps_pps_sent) { | ||
| 2901 | - sps_pps_sent = true; | ||
| 2902 | - | ||
| 2903 | - // @see: ngx_rtmp_hls_append_sps_pps | 2880 | + static u_int8_t fresh_nalu_header[] = { 0x00, 0x00, 0x00, 0x01 }; |
| 2881 | + static u_int8_t cont_nalu_header[] = { 0x00, 0x00, 0x01 }; | ||
| 2882 | + | ||
| 2883 | + // the aud(access unit delimiter) before each frame. | ||
| 2884 | + // 7.3.2.4 Access unit delimiter RBSP syntax | ||
| 2885 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 66. | ||
| 2886 | + // | ||
| 2887 | + // primary_pic_type u(3), the first 3bits, primary_pic_type indicates that the slice_type values | ||
| 2888 | + // for all slices of the primary coded picture are members of the set listed in Table 7-5 for | ||
| 2889 | + // the given value of primary_pic_type. | ||
| 2890 | + // 0, slice_type 2, 7 | ||
| 2891 | + // 1, slice_type 0, 2, 5, 7 | ||
| 2892 | + // 2, slice_type 0, 1, 2, 5, 6, 7 | ||
| 2893 | + // 3, slice_type 4, 9 | ||
| 2894 | + // 4, slice_type 3, 4, 8, 9 | ||
| 2895 | + // 5, slice_type 2, 4, 7, 9 | ||
| 2896 | + // 6, slice_type 0, 2, 3, 4, 5, 7, 8, 9 | ||
| 2897 | + // 7, slice_type 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 | ||
| 2898 | + // 7.4.2.4 Access unit delimiter RBSP semantics | ||
| 2899 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 102. | ||
| 2900 | + // | ||
| 2901 | + // slice_type specifies the coding type of the slice according to Table 7-6. | ||
| 2902 | + // 0, P (P slice) | ||
| 2903 | + // 1, B (B slice) | ||
| 2904 | + // 2, I (I slice) | ||
| 2905 | + // 3, SP (SP slice) | ||
| 2906 | + // 4, SI (SI slice) | ||
| 2907 | + // 5, P (P slice) | ||
| 2908 | + // 6, B (B slice) | ||
| 2909 | + // 7, I (I slice) | ||
| 2910 | + // 8, SP (SP slice) | ||
| 2911 | + // 9, SI (SI slice) | ||
| 2912 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 105. | ||
| 2913 | + static u_int8_t aud_nalu_7[] = { 0x09, 0xf0}; | ||
| 2914 | + video->payload->append((const char*)fresh_nalu_header, 4); | ||
| 2915 | + video->payload->append((const char*)aud_nalu_7, 2); | ||
| 2916 | + | ||
| 2917 | + // when ts message(samples) contains IDR, insert sps+pps. | ||
| 2918 | + if (sample->has_idr) { | ||
| 2919 | + // fresh nalu header before sps. | ||
| 2904 | if (codec->sequenceParameterSetLength > 0) { | 2920 | if (codec->sequenceParameterSetLength > 0) { |
| 2905 | // AnnexB prefix, for sps always 4 bytes header | 2921 | // AnnexB prefix, for sps always 4 bytes header |
| 2906 | - video->payload->append((const char*)aud_nal, 4); | 2922 | + video->payload->append((const char*)fresh_nalu_header, 4); |
| 2907 | // sps | 2923 | // sps |
| 2908 | video->payload->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength); | 2924 | video->payload->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength); |
| 2909 | } | 2925 | } |
| 2926 | + // cont nalu header before pps. | ||
| 2910 | if (codec->pictureParameterSetLength > 0) { | 2927 | if (codec->pictureParameterSetLength > 0) { |
| 2911 | - // AnnexB prefix, for pps always 4 bytes header | ||
| 2912 | - video->payload->append((const char*)aud_nal, 4); | 2928 | + // AnnexB prefix, for pps always 3 bytes header |
| 2929 | + video->payload->append((const char*)cont_nalu_header, 3); | ||
| 2913 | // pps | 2930 | // pps |
| 2914 | video->payload->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength); | 2931 | video->payload->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength); |
| 2915 | } | 2932 | } |
| 2916 | } | 2933 | } |
| 2917 | 2934 | ||
| 2918 | - // 7-9, ignore, @see: ngx_rtmp_hls_video | ||
| 2919 | - if (nal_unit_type >= 7 && nal_unit_type <= 9) { | ||
| 2920 | - continue; | ||
| 2921 | - } | ||
| 2922 | - | ||
| 2923 | - /** | ||
| 2924 | - * step 2: | ||
| 2925 | - * output the "real" sample, in buf. | ||
| 2926 | - * when we output some special assist packets according to nal_unit_type | ||
| 2927 | - */ | 2935 | + // all sample use cont nalu header, except the sps-pps before IDR frame. |
| 2936 | + for (int i = 0; i < sample->nb_sample_units; i++) { | ||
| 2937 | + SrsCodecSampleUnit* sample_unit = &sample->sample_units[i]; | ||
| 2938 | + int32_t size = sample_unit->size; | ||
| 2928 | 2939 | ||
| 2929 | - // sample start prefix, '00 00 00 01' or '00 00 01' | ||
| 2930 | - u_int8_t* p = aud_nal + 1; | ||
| 2931 | - u_int8_t* end = p + 3; | 2940 | + if (!sample_unit->bytes || size <= 0) { |
| 2941 | + ret = ERROR_HLS_AVC_SAMPLE_SIZE; | ||
| 2942 | + srs_error("invalid avc sample length=%d, ret=%d", size, ret); | ||
| 2943 | + return ret; | ||
| 2944 | + } | ||
| 2932 | 2945 | ||
| 2933 | - // first AnnexB prefix is long (4 bytes) | ||
| 2934 | - if (video->payload->length() == 0) { | ||
| 2935 | - p = aud_nal; | 2946 | + // 5bits, 7.3.1 NAL unit syntax, |
| 2947 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83. | ||
| 2948 | + SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(sample_unit->bytes[0] & 0x1f); | ||
| 2949 | + | ||
| 2950 | + // ignore SPS/PPS/AUD | ||
| 2951 | + switch (nal_unit_type) { | ||
| 2952 | + case SrsAvcNaluTypeSPS: | ||
| 2953 | + case SrsAvcNaluTypePPS: | ||
| 2954 | + case SrsAvcNaluTypeAccessUnitDelimiter: | ||
| 2955 | + continue; | ||
| 2956 | + default: | ||
| 2957 | + break; | ||
| 2936 | } | 2958 | } |
| 2937 | - video->payload->append((const char*)p, end - p); | 2959 | + |
| 2960 | + // insert cont nalu header before frame. | ||
| 2961 | + video->payload->append((const char*)cont_nalu_header, 3); | ||
| 2938 | 2962 | ||
| 2939 | // sample data | 2963 | // sample data |
| 2940 | video->payload->append(sample_unit->bytes, sample_unit->size); | 2964 | video->payload->append(sample_unit->bytes, sample_unit->size); |
| @@ -46,6 +46,53 @@ using namespace std; | @@ -46,6 +46,53 @@ using namespace std; | ||
| 46 | // @see SRS_SYS_TIME_RESOLUTION_MS_TIMES | 46 | // @see SRS_SYS_TIME_RESOLUTION_MS_TIMES |
| 47 | #define SYS_TIME_RESOLUTION_US 300*1000 | 47 | #define SYS_TIME_RESOLUTION_US 300*1000 |
| 48 | 48 | ||
| 49 | +int srs_avc_nalu_read_uev(SrsBitStream* stream, int64_t& v) | ||
| 50 | +{ | ||
| 51 | + int ret = ERROR_SUCCESS; | ||
| 52 | + | ||
| 53 | + if (stream->empty()) { | ||
| 54 | + return ERROR_AVC_NALU_UEV; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + // ue(v) in 9.1 Parsing process for Exp-Golomb codes | ||
| 58 | + // H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 227. | ||
| 59 | + // Syntax elements coded as ue(v), me(v), or se(v) are Exp-Golomb-coded. | ||
| 60 | + // leadingZeroBits = -1; | ||
| 61 | + // for( b = 0; !b; leadingZeroBits++ ) | ||
| 62 | + // b = read_bits( 1 ) | ||
| 63 | + // The variable codeNum is then assigned as follows: | ||
| 64 | + // codeNum = (2<<leadingZeroBits) – 1 + read_bits( leadingZeroBits ) | ||
| 65 | + int leadingZeroBits = -1; | ||
| 66 | + for (int8_t b = 0; !b && !stream->empty(); leadingZeroBits++) { | ||
| 67 | + b = stream->read_bit(); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + if (leadingZeroBits >= 64) { | ||
| 71 | + return ERROR_AVC_NALU_UEV; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + v = (1 << leadingZeroBits) - 1; | ||
| 75 | + for (int i = 0; i < leadingZeroBits; i++) { | ||
| 76 | + int64_t b = stream->read_bit(); | ||
| 77 | + v += b << (leadingZeroBits - 1); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + return ret; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +int srs_avc_nalu_read_bit(SrsBitStream* stream, int8_t& v) | ||
| 84 | +{ | ||
| 85 | + int ret = ERROR_SUCCESS; | ||
| 86 | + | ||
| 87 | + if (stream->empty()) { | ||
| 88 | + return ERROR_AVC_NALU_UEV; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + v = stream->read_bit(); | ||
| 92 | + | ||
| 93 | + return ret; | ||
| 94 | +} | ||
| 95 | + | ||
| 49 | static int64_t _srs_system_time_us_cache = 0; | 96 | static int64_t _srs_system_time_us_cache = 0; |
| 50 | static int64_t _srs_system_time_startup_time = 0; | 97 | static int64_t _srs_system_time_startup_time = 0; |
| 51 | 98 | ||
| @@ -294,6 +341,21 @@ bool srs_path_exists(std::string path) | @@ -294,6 +341,21 @@ bool srs_path_exists(std::string path) | ||
| 294 | return false; | 341 | return false; |
| 295 | } | 342 | } |
| 296 | 343 | ||
| 344 | +string srs_path_dirname(string path) | ||
| 345 | +{ | ||
| 346 | + std::string dirname = path; | ||
| 347 | + size_t pos = string::npos; | ||
| 348 | + | ||
| 349 | + if ((pos = dirname.rfind("/")) != string::npos) { | ||
| 350 | + if (pos == 0) { | ||
| 351 | + return "/"; | ||
| 352 | + } | ||
| 353 | + dirname = dirname.substr(0, pos); | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + return dirname; | ||
| 357 | +} | ||
| 358 | + | ||
| 297 | bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code) | 359 | bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code) |
| 298 | { | 360 | { |
| 299 | char* bytes = stream->data() + stream->pos(); | 361 | char* bytes = stream->data() + stream->pos(); |
| @@ -33,11 +33,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -33,11 +33,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 33 | #include <string> | 33 | #include <string> |
| 34 | 34 | ||
| 35 | class SrsStream; | 35 | class SrsStream; |
| 36 | +class SrsBitStream; | ||
| 36 | 37 | ||
| 37 | // compare | 38 | // compare |
| 38 | #define srs_min(a, b) (((a) < (b))? (a) : (b)) | 39 | #define srs_min(a, b) (((a) < (b))? (a) : (b)) |
| 39 | #define srs_max(a, b) (((a) < (b))? (b) : (a)) | 40 | #define srs_max(a, b) (((a) < (b))? (b) : (a)) |
| 40 | 41 | ||
| 42 | +// read nalu uev. | ||
| 43 | +extern int srs_avc_nalu_read_uev(SrsBitStream* stream, int64_t& v); | ||
| 44 | +extern int srs_avc_nalu_read_bit(SrsBitStream* stream, int8_t& v); | ||
| 45 | + | ||
| 41 | // get current system time in ms, use cache to avoid performance problem | 46 | // get current system time in ms, use cache to avoid performance problem |
| 42 | extern int64_t srs_get_system_time_ms(); | 47 | extern int64_t srs_get_system_time_ms(); |
| 43 | extern int64_t srs_get_system_startup_time_ms(); | 48 | extern int64_t srs_get_system_startup_time_ms(); |
| @@ -68,6 +73,8 @@ extern int srs_create_dir_recursively(std::string dir); | @@ -68,6 +73,8 @@ extern int srs_create_dir_recursively(std::string dir); | ||
| 68 | 73 | ||
| 69 | // whether path exists. | 74 | // whether path exists. |
| 70 | extern bool srs_path_exists(std::string path); | 75 | extern bool srs_path_exists(std::string path); |
| 76 | +// get the dirname of path | ||
| 77 | +extern std::string srs_path_dirname(std::string path); | ||
| 71 | 78 | ||
| 72 | /** | 79 | /** |
| 73 | * whether stream starts with the avc NALU in "AnnexB" | 80 | * whether stream starts with the avc NALU in "AnnexB" |
-
请 注册 或 登录 后发表评论