正在显示
10 个修改的文件
包含
622 行增加
和
484 行删除
| @@ -366,7 +366,7 @@ ModuleLibIncs=(${SRS_OBJS_DIR}) | @@ -366,7 +366,7 @@ ModuleLibIncs=(${SRS_OBJS_DIR}) | ||
| 366 | MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_stream" | 366 | MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_stream" |
| 367 | "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_codec" "srs_kernel_file" | 367 | "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_codec" "srs_kernel_file" |
| 368 | "srs_kernel_consts" "srs_kernel_aac" "srs_kernel_mp3" "srs_kernel_ts" | 368 | "srs_kernel_consts" "srs_kernel_aac" "srs_kernel_mp3" "srs_kernel_ts" |
| 369 | - "srs_kernel_avc") | 369 | + "srs_kernel_avc" "srs_kernel_buffer") |
| 370 | KERNEL_INCS="src/kernel"; MODULE_DIR=${KERNEL_INCS} . auto/modules.sh | 370 | KERNEL_INCS="src/kernel"; MODULE_DIR=${KERNEL_INCS} . auto/modules.sh |
| 371 | KERNEL_OBJS="${MODULE_OBJS[@]}" | 371 | KERNEL_OBJS="${MODULE_OBJS[@]}" |
| 372 | # | 372 | # |
| @@ -22,6 +22,8 @@ file | @@ -22,6 +22,8 @@ file | ||
| 22 | ../../src/kernel/srs_kernel_aac.cpp, | 22 | ../../src/kernel/srs_kernel_aac.cpp, |
| 23 | ../../src/kernel/srs_kernel_avc.hpp, | 23 | ../../src/kernel/srs_kernel_avc.hpp, |
| 24 | ../../src/kernel/srs_kernel_avc.cpp, | 24 | ../../src/kernel/srs_kernel_avc.cpp, |
| 25 | + ../../src/kernel/srs_kernel_buffer.hpp, | ||
| 26 | + ../../src/kernel/srs_kernel_buffer.cpp, | ||
| 25 | ../../src/kernel/srs_kernel_codec.hpp, | 27 | ../../src/kernel/srs_kernel_codec.hpp, |
| 26 | ../../src/kernel/srs_kernel_codec.cpp, | 28 | ../../src/kernel/srs_kernel_codec.cpp, |
| 27 | ../../src/kernel/srs_kernel_consts.hpp, | 29 | ../../src/kernel/srs_kernel_consts.hpp, |
| @@ -24,25 +24,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -24,25 +24,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 24 | #include <srs_app_hls.hpp> | 24 | #include <srs_app_hls.hpp> |
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | -* the public data, event HLS disable, others can use it. | ||
| 28 | -*/ | ||
| 29 | -// 0 = 5.5 kHz = 5512 Hz | ||
| 30 | -// 1 = 11 kHz = 11025 Hz | ||
| 31 | -// 2 = 22 kHz = 22050 Hz | ||
| 32 | -// 3 = 44 kHz = 44100 Hz | ||
| 33 | -int flv_sample_rates[] = {5512, 11025, 22050, 44100}; | ||
| 34 | - | ||
| 35 | -// the sample rates in the codec, | ||
| 36 | -// in the sequence header. | ||
| 37 | -int aac_sample_rates[] = | ||
| 38 | -{ | ||
| 39 | - 96000, 88200, 64000, 48000, | ||
| 40 | - 44100, 32000, 24000, 22050, | ||
| 41 | - 16000, 12000, 11025, 8000, | ||
| 42 | - 7350, 0, 0, 0 | ||
| 43 | -}; | ||
| 44 | - | ||
| 45 | -/** | ||
| 46 | * the HLS section, only available when HLS enabled. | 27 | * the HLS section, only available when HLS enabled. |
| 47 | */ | 28 | */ |
| 48 | #ifdef SRS_AUTO_HLS | 29 | #ifdef SRS_AUTO_HLS |
| @@ -80,25 +61,6 @@ using namespace std; | @@ -80,25 +61,6 @@ using namespace std; | ||
| 80 | // 63000: 700ms, ts_tbn=90000 | 61 | // 63000: 700ms, ts_tbn=90000 |
| 81 | #define SRS_AUTO_HLS_DELAY 63000 | 62 | #define SRS_AUTO_HLS_DELAY 63000 |
| 82 | 63 | ||
| 83 | -// the mpegts header specifed the video/audio pid. | ||
| 84 | -#define TS_VIDEO_PID 256 | ||
| 85 | -#define TS_AUDIO_PID 257 | ||
| 86 | - | ||
| 87 | -// ts aac stream id. | ||
| 88 | -#define TS_AUDIO_AAC 0xc0 | ||
| 89 | -// ts avc stream id. | ||
| 90 | -#define TS_VIDEO_AVC 0xe0 | ||
| 91 | - | ||
| 92 | -// @see: ngx_rtmp_hls_audio | ||
| 93 | -/* We assume here AAC frame size is 1024 | ||
| 94 | - * Need to handle AAC frames with frame size of 960 */ | ||
| 95 | -#define _SRS_AAC_SAMPLE_SIZE 1024 | ||
| 96 | - | ||
| 97 | -// in ms, for HLS aac sync time. | ||
| 98 | -#define SRS_CONF_DEFAULT_AAC_SYNC 100 | ||
| 99 | -// in ms, for HLS aac flush the audio | ||
| 100 | -#define SRS_CONF_DEFAULT_AAC_DELAY 100 | ||
| 101 | - | ||
| 102 | // @see: ngx_rtmp_mpegts_header | 64 | // @see: ngx_rtmp_mpegts_header |
| 103 | u_int8_t mpegts_header[] = { | 65 | u_int8_t mpegts_header[] = { |
| 104 | /* TS */ | 66 | /* TS */ |
| @@ -162,25 +124,6 @@ u_int8_t mpegts_header[] = { | @@ -162,25 +124,6 @@ u_int8_t mpegts_header[] = { | ||
| 162 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | 124 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff |
| 163 | }; | 125 | }; |
| 164 | 126 | ||
| 165 | -// @see: ngx_rtmp_SrsMpegtsFrame_t | ||
| 166 | -class SrsMpegtsFrame | ||
| 167 | -{ | ||
| 168 | -public: | ||
| 169 | - int64_t pts; | ||
| 170 | - int64_t dts; | ||
| 171 | - int pid; | ||
| 172 | - int sid; | ||
| 173 | - int cc; | ||
| 174 | - bool key; | ||
| 175 | - | ||
| 176 | - SrsMpegtsFrame() | ||
| 177 | - { | ||
| 178 | - pts = dts = 0; | ||
| 179 | - pid = sid = cc = 0; | ||
| 180 | - key = false; | ||
| 181 | - } | ||
| 182 | -}; | ||
| 183 | - | ||
| 184 | // @see: ngx_rtmp_mpegts.c | 127 | // @see: ngx_rtmp_mpegts.c |
| 185 | // TODO: support full mpegts feature in future. | 128 | // TODO: support full mpegts feature in future. |
| 186 | class SrsMpegtsWriter | 129 | class SrsMpegtsWriter |
| @@ -401,69 +344,6 @@ private: | @@ -401,69 +344,6 @@ private: | ||
| 401 | } | 344 | } |
| 402 | }; | 345 | }; |
| 403 | 346 | ||
| 404 | -SrsHlsAacJitter::SrsHlsAacJitter() | ||
| 405 | -{ | ||
| 406 | - base_pts = 0; | ||
| 407 | - nb_samples = 0; | ||
| 408 | - | ||
| 409 | - // TODO: config it, 0 means no adjust | ||
| 410 | - sync_ms = SRS_CONF_DEFAULT_AAC_SYNC; | ||
| 411 | -} | ||
| 412 | - | ||
| 413 | -SrsHlsAacJitter::~SrsHlsAacJitter() | ||
| 414 | -{ | ||
| 415 | -} | ||
| 416 | - | ||
| 417 | -int64_t SrsHlsAacJitter::on_buffer_start(int64_t flv_pts, int sample_rate, int aac_sample_rate) | ||
| 418 | -{ | ||
| 419 | - // use sample rate in flv/RTMP. | ||
| 420 | - int flv_sample_rate = flv_sample_rates[sample_rate & 0x03]; | ||
| 421 | - | ||
| 422 | - // override the sample rate by sequence header | ||
| 423 | - if (aac_sample_rate != __SRS_AAC_SAMPLE_RATE_UNSET) { | ||
| 424 | - flv_sample_rate = aac_sample_rates[aac_sample_rate]; | ||
| 425 | - } | ||
| 426 | - | ||
| 427 | - // sync time set to 0, donot adjust the aac timestamp. | ||
| 428 | - if (!sync_ms) { | ||
| 429 | - return flv_pts; | ||
| 430 | - } | ||
| 431 | - | ||
| 432 | - // @see: ngx_rtmp_hls_audio | ||
| 433 | - // drop the rtmp audio packet timestamp, re-calc it by sample rate. | ||
| 434 | - // | ||
| 435 | - // resample for the tbn of ts is 90000, flv is 1000, | ||
| 436 | - // we will lost timestamp if use audio packet timestamp, | ||
| 437 | - // so we must resample. or audio will corupt in IOS. | ||
| 438 | - int64_t est_pts = base_pts + nb_samples * 90000LL * _SRS_AAC_SAMPLE_SIZE / flv_sample_rate; | ||
| 439 | - int64_t dpts = (int64_t) (est_pts - flv_pts); | ||
| 440 | - | ||
| 441 | - if (dpts <= (int64_t) sync_ms * 90 && dpts >= (int64_t) sync_ms * -90) { | ||
| 442 | - srs_info("HLS correct aac pts " | ||
| 443 | - "from %"PRId64" to %"PRId64", base=%"PRId64", nb_samples=%d, sample_rate=%d", | ||
| 444 | - flv_pts, est_pts, nb_samples, flv_sample_rate, base_pts); | ||
| 445 | - | ||
| 446 | - nb_samples++; | ||
| 447 | - | ||
| 448 | - return est_pts; | ||
| 449 | - } | ||
| 450 | - | ||
| 451 | - // resync | ||
| 452 | - srs_trace("HLS aac resync, dpts=%"PRId64", pts=%"PRId64 | ||
| 453 | - ", base=%"PRId64", nb_samples=%"PRId64", sample_rate=%d", | ||
| 454 | - dpts, flv_pts, base_pts, nb_samples, flv_sample_rate); | ||
| 455 | - | ||
| 456 | - base_pts = flv_pts; | ||
| 457 | - nb_samples = 1; | ||
| 458 | - | ||
| 459 | - return flv_pts; | ||
| 460 | -} | ||
| 461 | - | ||
| 462 | -void SrsHlsAacJitter::on_buffer_continue() | ||
| 463 | -{ | ||
| 464 | - nb_samples++; | ||
| 465 | -} | ||
| 466 | - | ||
| 467 | SrsTSMuxer::SrsTSMuxer() | 347 | SrsTSMuxer::SrsTSMuxer() |
| 468 | { | 348 | { |
| 469 | writer = new SrsFileWriter(); | 349 | writer = new SrsFileWriter(); |
| @@ -963,27 +843,12 @@ int SrsHlsMuxer::create_dir() | @@ -963,27 +843,12 @@ int SrsHlsMuxer::create_dir() | ||
| 963 | 843 | ||
| 964 | SrsHlsCache::SrsHlsCache() | 844 | SrsHlsCache::SrsHlsCache() |
| 965 | { | 845 | { |
| 966 | - aac_jitter = new SrsHlsAacJitter(); | ||
| 967 | - | ||
| 968 | - ab = new SrsSimpleBuffer(); | ||
| 969 | - vb = new SrsSimpleBuffer(); | ||
| 970 | - | ||
| 971 | - af = new SrsMpegtsFrame(); | ||
| 972 | - vf = new SrsMpegtsFrame(); | 846 | + cache = new SrsTsCache(); |
| 973 | } | 847 | } |
| 974 | 848 | ||
| 975 | SrsHlsCache::~SrsHlsCache() | 849 | SrsHlsCache::~SrsHlsCache() |
| 976 | { | 850 | { |
| 977 | - srs_freep(aac_jitter); | ||
| 978 | - | ||
| 979 | - ab->erase(ab->length()); | ||
| 980 | - vb->erase(vb->length()); | ||
| 981 | - | ||
| 982 | - srs_freep(ab); | ||
| 983 | - srs_freep(vb); | ||
| 984 | - | ||
| 985 | - srs_freep(af); | ||
| 986 | - srs_freep(vf); | 851 | + srs_freep(cache); |
| 987 | } | 852 | } |
| 988 | 853 | ||
| 989 | int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment_start_dts) | 854 | int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment_start_dts) |
| @@ -1021,7 +886,7 @@ int SrsHlsCache::on_unpublish(SrsHlsMuxer* muxer) | @@ -1021,7 +886,7 @@ int SrsHlsCache::on_unpublish(SrsHlsMuxer* muxer) | ||
| 1021 | { | 886 | { |
| 1022 | int ret = ERROR_SUCCESS; | 887 | int ret = ERROR_SUCCESS; |
| 1023 | 888 | ||
| 1024 | - if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { | 889 | + if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) { |
| 1025 | srs_error("m3u8 muxer flush audio failed. ret=%d", ret); | 890 | srs_error("m3u8 muxer flush audio failed. ret=%d", ret); |
| 1026 | return ret; | 891 | return ret; |
| 1027 | } | 892 | } |
| @@ -1047,26 +912,17 @@ int SrsHlsCache::on_sequence_header(SrsHlsMuxer* muxer) | @@ -1047,26 +912,17 @@ int SrsHlsCache::on_sequence_header(SrsHlsMuxer* muxer) | ||
| 1047 | int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample) | 912 | int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample) |
| 1048 | { | 913 | { |
| 1049 | int ret = ERROR_SUCCESS; | 914 | int ret = ERROR_SUCCESS; |
| 1050 | - | ||
| 1051 | - // start buffer, set the af | ||
| 1052 | - if (ab->length() == 0) { | ||
| 1053 | - pts = aac_jitter->on_buffer_start(pts, sample->sound_rate, codec->aac_sample_rate); | ||
| 1054 | - | ||
| 1055 | - af->dts = af->pts = audio_buffer_start_pts = pts; | ||
| 1056 | - af->pid = TS_AUDIO_PID; | ||
| 1057 | - af->sid = TS_AUDIO_AAC; | ||
| 1058 | - } else { | ||
| 1059 | - aac_jitter->on_buffer_continue(); | ||
| 1060 | - } | 915 | + |
| 916 | + audio_buffer_start_pts = pts; | ||
| 1061 | 917 | ||
| 1062 | // write audio to cache. | 918 | // write audio to cache. |
| 1063 | - if ((ret = cache_audio(codec, sample)) != ERROR_SUCCESS) { | 919 | + if ((ret = cache->cache_audio(codec, pts, sample)) != ERROR_SUCCESS) { |
| 1064 | return ret; | 920 | return ret; |
| 1065 | } | 921 | } |
| 1066 | 922 | ||
| 1067 | // flush if buffer exceed max size. | 923 | // flush if buffer exceed max size. |
| 1068 | - if (ab->length() > SRS_AUTO_HLS_AUDIO_CACHE_SIZE) { | ||
| 1069 | - if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { | 924 | + if (cache->ab->length() > SRS_AUTO_HLS_AUDIO_CACHE_SIZE) { |
| 925 | + if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) { | ||
| 1070 | return ret; | 926 | return ret; |
| 1071 | } | 927 | } |
| 1072 | } | 928 | } |
| @@ -1075,7 +931,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | @@ -1075,7 +931,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | ||
| 1075 | int64_t audio_delay = SRS_CONF_DEFAULT_AAC_DELAY; | 931 | int64_t audio_delay = SRS_CONF_DEFAULT_AAC_DELAY; |
| 1076 | // flush if audio delay exceed | 932 | // flush if audio delay exceed |
| 1077 | if (pts - audio_buffer_start_pts > audio_delay * 90) { | 933 | if (pts - audio_buffer_start_pts > audio_delay * 90) { |
| 1078 | - if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { | 934 | + if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) { |
| 1079 | return ret; | 935 | return ret; |
| 1080 | } | 936 | } |
| 1081 | } | 937 | } |
| @@ -1087,7 +943,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | @@ -1087,7 +943,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | ||
| 1087 | // so we reap event when the audio incoming when segment overflow. | 943 | // so we reap event when the audio incoming when segment overflow. |
| 1088 | // @see https://github.com/winlinvip/simple-rtmp-server/issues/151 | 944 | // @see https://github.com/winlinvip/simple-rtmp-server/issues/151 |
| 1089 | if (muxer->is_segment_overflow()) { | 945 | if (muxer->is_segment_overflow()) { |
| 1090 | - if ((ret = reap_segment("audio", muxer, af->pts)) != ERROR_SUCCESS) { | 946 | + if ((ret = reap_segment("audio", muxer, cache->af->pts)) != ERROR_SUCCESS) { |
| 1091 | return ret; | 947 | return ret; |
| 1092 | } | 948 | } |
| 1093 | } | 949 | } |
| @@ -1095,33 +951,26 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | @@ -1095,33 +951,26 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | ||
| 1095 | return ret; | 951 | return ret; |
| 1096 | } | 952 | } |
| 1097 | 953 | ||
| 1098 | -int SrsHlsCache::write_video( | ||
| 1099 | - SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample) | 954 | +int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample) |
| 1100 | { | 955 | { |
| 1101 | int ret = ERROR_SUCCESS; | 956 | int ret = ERROR_SUCCESS; |
| 1102 | 957 | ||
| 1103 | // write video to cache. | 958 | // write video to cache. |
| 1104 | - if ((ret = cache_video(codec, sample)) != ERROR_SUCCESS) { | 959 | + if ((ret = cache->cache_video(codec, dts, sample)) != ERROR_SUCCESS) { |
| 1105 | return ret; | 960 | return ret; |
| 1106 | } | 961 | } |
| 1107 | 962 | ||
| 1108 | - vf->dts = dts; | ||
| 1109 | - vf->pts = vf->dts + sample->cts * 90; | ||
| 1110 | - vf->pid = TS_VIDEO_PID; | ||
| 1111 | - vf->sid = TS_VIDEO_AVC; | ||
| 1112 | - vf->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; | ||
| 1113 | - | ||
| 1114 | // new segment when: | 963 | // new segment when: |
| 1115 | // 1. base on gop. | 964 | // 1. base on gop. |
| 1116 | // 2. some gops duration overflow. | 965 | // 2. some gops duration overflow. |
| 1117 | - if (vf->key && muxer->is_segment_overflow()) { | ||
| 1118 | - if ((ret = reap_segment("video", muxer, vf->dts)) != ERROR_SUCCESS) { | 966 | + if (cache->vf->key && muxer->is_segment_overflow()) { |
| 967 | + if ((ret = reap_segment("video", muxer, cache->vf->dts)) != ERROR_SUCCESS) { | ||
| 1119 | return ret; | 968 | return ret; |
| 1120 | } | 969 | } |
| 1121 | } | 970 | } |
| 1122 | 971 | ||
| 1123 | // flush video when got one | 972 | // flush video when got one |
| 1124 | - if ((ret = muxer->flush_video(af, ab, vf, vb)) != ERROR_SUCCESS) { | 973 | + if ((ret = muxer->flush_video(cache->af, cache->ab, cache->vf, cache->vb)) != ERROR_SUCCESS) { |
| 1125 | srs_error("m3u8 muxer flush video failed. ret=%d", ret); | 974 | srs_error("m3u8 muxer flush video failed. ret=%d", ret); |
| 1126 | return ret; | 975 | return ret; |
| 1127 | } | 976 | } |
| @@ -1147,7 +996,7 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme | @@ -1147,7 +996,7 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme | ||
| 1147 | // segment open, flush the audio. | 996 | // segment open, flush the audio. |
| 1148 | // @see: ngx_rtmp_hls_open_fragment | 997 | // @see: ngx_rtmp_hls_open_fragment |
| 1149 | /* start fragment with audio to make iPhone happy */ | 998 | /* start fragment with audio to make iPhone happy */ |
| 1150 | - if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { | 999 | + if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) { |
| 1151 | srs_error("m3u8 muxer flush audio failed. ret=%d", ret); | 1000 | srs_error("m3u8 muxer flush audio failed. ret=%d", ret); |
| 1152 | return ret; | 1001 | return ret; |
| 1153 | } | 1002 | } |
| @@ -1155,185 +1004,6 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme | @@ -1155,185 +1004,6 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme | ||
| 1155 | return ret; | 1004 | return ret; |
| 1156 | } | 1005 | } |
| 1157 | 1006 | ||
| 1158 | -int SrsHlsCache::cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample) | ||
| 1159 | -{ | ||
| 1160 | - int ret = ERROR_SUCCESS; | ||
| 1161 | - | ||
| 1162 | - for (int i = 0; i < sample->nb_sample_units; i++) { | ||
| 1163 | - SrsCodecSampleUnit* sample_unit = &sample->sample_units[i]; | ||
| 1164 | - int32_t size = sample_unit->size; | ||
| 1165 | - | ||
| 1166 | - if (!sample_unit->bytes || size <= 0 || size > 0x1fff) { | ||
| 1167 | - ret = ERROR_HLS_AAC_FRAME_LENGTH; | ||
| 1168 | - srs_error("invalid aac frame length=%d, ret=%d", size, ret); | ||
| 1169 | - return ret; | ||
| 1170 | - } | ||
| 1171 | - | ||
| 1172 | - // the frame length is the AAC raw data plus the adts header size. | ||
| 1173 | - int32_t frame_length = size + 7; | ||
| 1174 | - | ||
| 1175 | - // AAC-ADTS | ||
| 1176 | - // 6.2 Audio Data Transport Stream, ADTS | ||
| 1177 | - // in aac-iso-13818-7.pdf, page 26. | ||
| 1178 | - // fixed 7bytes header | ||
| 1179 | - static u_int8_t adts_header[7] = {0xff, 0xf1, 0x00, 0x00, 0x00, 0x0f, 0xfc}; | ||
| 1180 | - /* | ||
| 1181 | - // adts_fixed_header | ||
| 1182 | - // 2B, 16bits | ||
| 1183 | - int16_t syncword; //12bits, '1111 1111 1111' | ||
| 1184 | - int8_t ID; //1bit, '0' | ||
| 1185 | - int8_t layer; //2bits, '00' | ||
| 1186 | - int8_t protection_absent; //1bit, can be '1' | ||
| 1187 | - // 12bits | ||
| 1188 | - int8_t profile; //2bit, 7.1 Profiles, page 40 | ||
| 1189 | - TSAacSampleFrequency sampling_frequency_index; //4bits, Table 35, page 46 | ||
| 1190 | - int8_t private_bit; //1bit, can be '0' | ||
| 1191 | - int8_t channel_configuration; //3bits, Table 8 | ||
| 1192 | - int8_t original_or_copy; //1bit, can be '0' | ||
| 1193 | - int8_t home; //1bit, can be '0' | ||
| 1194 | - | ||
| 1195 | - // adts_variable_header | ||
| 1196 | - // 28bits | ||
| 1197 | - int8_t copyright_identification_bit; //1bit, can be '0' | ||
| 1198 | - int8_t copyright_identification_start; //1bit, can be '0' | ||
| 1199 | - int16_t frame_length; //13bits | ||
| 1200 | - int16_t adts_buffer_fullness; //11bits, 7FF signals that the bitstream is a variable rate bitstream. | ||
| 1201 | - int8_t number_of_raw_data_blocks_in_frame; //2bits, 0 indicating 1 raw_data_block() | ||
| 1202 | - */ | ||
| 1203 | - // profile, 2bits | ||
| 1204 | - adts_header[2] = (codec->aac_profile << 6) & 0xc0; | ||
| 1205 | - // sampling_frequency_index 4bits | ||
| 1206 | - adts_header[2] |= (codec->aac_sample_rate << 2) & 0x3c; | ||
| 1207 | - // channel_configuration 3bits | ||
| 1208 | - adts_header[2] |= (codec->aac_channels >> 2) & 0x01; | ||
| 1209 | - adts_header[3] = (codec->aac_channels << 6) & 0xc0; | ||
| 1210 | - // frame_length 13bits | ||
| 1211 | - adts_header[3] |= (frame_length >> 11) & 0x03; | ||
| 1212 | - adts_header[4] = (frame_length >> 3) & 0xff; | ||
| 1213 | - adts_header[5] = ((frame_length << 5) & 0xe0); | ||
| 1214 | - // adts_buffer_fullness; //11bits | ||
| 1215 | - adts_header[5] |= 0x1f; | ||
| 1216 | - | ||
| 1217 | - // copy to audio buffer | ||
| 1218 | - ab->append((const char*)adts_header, sizeof(adts_header)); | ||
| 1219 | - ab->append(sample_unit->bytes, sample_unit->size); | ||
| 1220 | - } | ||
| 1221 | - | ||
| 1222 | - return ret; | ||
| 1223 | -} | ||
| 1224 | - | ||
| 1225 | -int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample) | ||
| 1226 | -{ | ||
| 1227 | - int ret = ERROR_SUCCESS; | ||
| 1228 | - | ||
| 1229 | - // for type1/5/6, insert aud packet. | ||
| 1230 | - static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; | ||
| 1231 | - | ||
| 1232 | - bool sps_pps_sent = false; | ||
| 1233 | - bool aud_sent = false; | ||
| 1234 | - /** | ||
| 1235 | - * a ts sample is format as: | ||
| 1236 | - * 00 00 00 01 // header | ||
| 1237 | - * xxxxxxx // data bytes | ||
| 1238 | - * 00 00 01 // continue header | ||
| 1239 | - * xxxxxxx // data bytes. | ||
| 1240 | - * so, for each sample, we append header in aud_nal, then appends the bytes in sample. | ||
| 1241 | - */ | ||
| 1242 | - for (int i = 0; i < sample->nb_sample_units; i++) { | ||
| 1243 | - SrsCodecSampleUnit* sample_unit = &sample->sample_units[i]; | ||
| 1244 | - int32_t size = sample_unit->size; | ||
| 1245 | - | ||
| 1246 | - if (!sample_unit->bytes || size <= 0) { | ||
| 1247 | - ret = ERROR_HLS_AVC_SAMPLE_SIZE; | ||
| 1248 | - srs_error("invalid avc sample length=%d, ret=%d", size, ret); | ||
| 1249 | - return ret; | ||
| 1250 | - } | ||
| 1251 | - | ||
| 1252 | - /** | ||
| 1253 | - * step 1: | ||
| 1254 | - * first, before each "real" sample, | ||
| 1255 | - * we add some packets according to the nal_unit_type, | ||
| 1256 | - * for example, when got nal_unit_type=5, insert SPS/PPS before sample. | ||
| 1257 | - */ | ||
| 1258 | - | ||
| 1259 | - // 5bits, 7.3.1 NAL unit syntax, | ||
| 1260 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1261 | - u_int8_t nal_unit_type; | ||
| 1262 | - nal_unit_type = *sample_unit->bytes; | ||
| 1263 | - nal_unit_type &= 0x1f; | ||
| 1264 | - | ||
| 1265 | - // @see: ngx_rtmp_hls_video | ||
| 1266 | - // Table 7-1 – NAL unit type codes, page 61 | ||
| 1267 | - // 1: Coded slice | ||
| 1268 | - if (nal_unit_type == 1) { | ||
| 1269 | - sps_pps_sent = false; | ||
| 1270 | - } | ||
| 1271 | - | ||
| 1272 | - // 6: Supplemental enhancement information (SEI) sei_rbsp( ), page 61 | ||
| 1273 | - // @see: ngx_rtmp_hls_append_aud | ||
| 1274 | - if (!aud_sent) { | ||
| 1275 | - // @remark, when got type 9, we donot send aud_nal, but it will make | ||
| 1276 | - // ios unhappy, so we remove it. | ||
| 1277 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/281 | ||
| 1278 | - /*if (nal_unit_type == 9) { | ||
| 1279 | - aud_sent = true; | ||
| 1280 | - }*/ | ||
| 1281 | - | ||
| 1282 | - if (nal_unit_type == 1 || nal_unit_type == 5 || nal_unit_type == 6) { | ||
| 1283 | - // for type 6, append a aud with type 9. | ||
| 1284 | - vb->append((const char*)aud_nal, sizeof(aud_nal)); | ||
| 1285 | - aud_sent = true; | ||
| 1286 | - } | ||
| 1287 | - } | ||
| 1288 | - | ||
| 1289 | - // 5: Coded slice of an IDR picture. | ||
| 1290 | - // insert sps/pps before IDR or key frame is ok. | ||
| 1291 | - if (nal_unit_type == 5 && !sps_pps_sent) { | ||
| 1292 | - sps_pps_sent = true; | ||
| 1293 | - | ||
| 1294 | - // @see: ngx_rtmp_hls_append_sps_pps | ||
| 1295 | - if (codec->sequenceParameterSetLength > 0) { | ||
| 1296 | - // AnnexB prefix, for sps always 4 bytes header | ||
| 1297 | - vb->append((const char*)aud_nal, 4); | ||
| 1298 | - // sps | ||
| 1299 | - vb->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength); | ||
| 1300 | - } | ||
| 1301 | - if (codec->pictureParameterSetLength > 0) { | ||
| 1302 | - // AnnexB prefix, for pps always 4 bytes header | ||
| 1303 | - vb->append((const char*)aud_nal, 4); | ||
| 1304 | - // pps | ||
| 1305 | - vb->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength); | ||
| 1306 | - } | ||
| 1307 | - } | ||
| 1308 | - | ||
| 1309 | - // 7-9, ignore, @see: ngx_rtmp_hls_video | ||
| 1310 | - if (nal_unit_type >= 7 && nal_unit_type <= 9) { | ||
| 1311 | - continue; | ||
| 1312 | - } | ||
| 1313 | - | ||
| 1314 | - /** | ||
| 1315 | - * step 2: | ||
| 1316 | - * output the "real" sample, in buf. | ||
| 1317 | - * when we output some special assist packets according to nal_unit_type | ||
| 1318 | - */ | ||
| 1319 | - | ||
| 1320 | - // sample start prefix, '00 00 00 01' or '00 00 01' | ||
| 1321 | - u_int8_t* p = aud_nal + 1; | ||
| 1322 | - u_int8_t* end = p + 3; | ||
| 1323 | - | ||
| 1324 | - // first AnnexB prefix is long (4 bytes) | ||
| 1325 | - if (vb->length() == 0) { | ||
| 1326 | - p = aud_nal; | ||
| 1327 | - } | ||
| 1328 | - vb->append((const char*)p, end - p); | ||
| 1329 | - | ||
| 1330 | - // sample data | ||
| 1331 | - vb->append(sample_unit->bytes, sample_unit->size); | ||
| 1332 | - } | ||
| 1333 | - | ||
| 1334 | - return ret; | ||
| 1335 | -} | ||
| 1336 | - | ||
| 1337 | SrsHls::SrsHls(SrsSource* _source) | 1007 | SrsHls::SrsHls(SrsSource* _source) |
| 1338 | { | 1008 | { |
| 1339 | hls_enabled = false; | 1009 | hls_enabled = false; |
| @@ -30,19 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -30,19 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 30 | #include <srs_core.hpp> | 30 | #include <srs_core.hpp> |
| 31 | 31 | ||
| 32 | /** | 32 | /** |
| 33 | -* the public data, event HLS disable, others can use it. | ||
| 34 | -*/ | ||
| 35 | -/** | ||
| 36 | -* the flv sample rate map | ||
| 37 | -*/ | ||
| 38 | -extern int flv_sample_rates[]; | ||
| 39 | - | ||
| 40 | -/** | ||
| 41 | -* the aac sample rate map | ||
| 42 | -*/ | ||
| 43 | -extern int aac_sample_rates[]; | ||
| 44 | - | ||
| 45 | -/** | ||
| 46 | * the HLS section, only available when HLS enabled. | 33 | * the HLS section, only available when HLS enabled. |
| 47 | */ | 34 | */ |
| 48 | #ifdef SRS_AUTO_HLS | 35 | #ifdef SRS_AUTO_HLS |
| @@ -62,38 +49,8 @@ class SrsPithyPrint; | @@ -62,38 +49,8 @@ class SrsPithyPrint; | ||
| 62 | class SrsSource; | 49 | class SrsSource; |
| 63 | class SrsFileWriter; | 50 | class SrsFileWriter; |
| 64 | class SrsSimpleBuffer; | 51 | class SrsSimpleBuffer; |
| 65 | - | ||
| 66 | -/** | ||
| 67 | -* jitter correct for audio, | ||
| 68 | -* the sample rate 44100/32000 will lost precise, | ||
| 69 | -* when mp4/ts(tbn=90000) covert to flv/rtmp(1000), | ||
| 70 | -* so the Hls on ipad or iphone will corrupt, | ||
| 71 | -* @see nginx-rtmp: est_pts | ||
| 72 | -*/ | ||
| 73 | -class SrsHlsAacJitter | ||
| 74 | -{ | ||
| 75 | -private: | ||
| 76 | - int64_t base_pts; | ||
| 77 | - int64_t nb_samples; | ||
| 78 | - int sync_ms; | ||
| 79 | -public: | ||
| 80 | - SrsHlsAacJitter(); | ||
| 81 | - virtual ~SrsHlsAacJitter(); | ||
| 82 | - /** | ||
| 83 | - * when buffer start, calc the "correct" pts for ts, | ||
| 84 | - * @param flv_pts, the flv pts calc from flv header timestamp, | ||
| 85 | - * @param sample_rate, the sample rate in format(flv/RTMP packet header). | ||
| 86 | - * @param aac_sample_rate, the sample rate in codec(sequence header). | ||
| 87 | - * @return the calc correct pts. | ||
| 88 | - */ | ||
| 89 | - virtual int64_t on_buffer_start(int64_t flv_pts, int sample_rate, int aac_sample_rate); | ||
| 90 | - /** | ||
| 91 | - * when buffer continue, muxer donot write to file, | ||
| 92 | - * the audio buffer continue grow and donot need a pts, | ||
| 93 | - * for the ts audio PES packet only has one pts at the first time. | ||
| 94 | - */ | ||
| 95 | - virtual void on_buffer_continue(); | ||
| 96 | -}; | 52 | +class SrsTsAacJitter; |
| 53 | +class SrsTsCache; | ||
| 97 | 54 | ||
| 98 | /** | 55 | /** |
| 99 | * write data from frame(header info) and buffer(data) to ts file. | 56 | * write data from frame(header info) and buffer(data) to ts file. |
| @@ -223,22 +180,15 @@ private: | @@ -223,22 +180,15 @@ private: | ||
| 223 | * about the flv tbn problem: | 180 | * about the flv tbn problem: |
| 224 | * flv tbn is 1/1000, ts tbn is 1/90000, | 181 | * flv tbn is 1/1000, ts tbn is 1/90000, |
| 225 | * when timestamp convert to flv tbn, it will loose precise, | 182 | * when timestamp convert to flv tbn, it will loose precise, |
| 226 | -* so we must gather audio frame together, and recalc the timestamp @see SrsHlsAacJitter, | 183 | +* so we must gather audio frame together, and recalc the timestamp @see SrsTsAacJitter, |
| 227 | * we use a aac jitter to correct the audio pts. | 184 | * we use a aac jitter to correct the audio pts. |
| 228 | */ | 185 | */ |
| 229 | class SrsHlsCache | 186 | class SrsHlsCache |
| 230 | { | 187 | { |
| 231 | private: | 188 | private: |
| 232 | - // current frame and buffer | ||
| 233 | - SrsMpegtsFrame* af; | ||
| 234 | - SrsSimpleBuffer* ab; | ||
| 235 | - SrsMpegtsFrame* vf; | ||
| 236 | - SrsSimpleBuffer* vb; | ||
| 237 | -private: | ||
| 238 | // the audio cache buffer start pts, to flush audio if full. | 189 | // the audio cache buffer start pts, to flush audio if full. |
| 239 | int64_t audio_buffer_start_pts; | 190 | int64_t audio_buffer_start_pts; |
| 240 | - // time jitter for aac | ||
| 241 | - SrsHlsAacJitter* aac_jitter; | 191 | + SrsTsCache* cache; |
| 242 | public: | 192 | public: |
| 243 | SrsHlsCache(); | 193 | SrsHlsCache(); |
| 244 | virtual ~SrsHlsCache(); | 194 | virtual ~SrsHlsCache(); |
| @@ -271,8 +221,6 @@ private: | @@ -271,8 +221,6 @@ private: | ||
| 271 | * so, user must reap_segment then flush_video to hls muxer. | 221 | * so, user must reap_segment then flush_video to hls muxer. |
| 272 | */ | 222 | */ |
| 273 | virtual int reap_segment(std::string log_desc, SrsHlsMuxer* muxer, int64_t segment_start_dts); | 223 | virtual int reap_segment(std::string log_desc, SrsHlsMuxer* muxer, int64_t segment_start_dts); |
| 274 | - virtual int cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample); | ||
| 275 | - virtual int cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample); | ||
| 276 | }; | 224 | }; |
| 277 | 225 | ||
| 278 | /** | 226 | /** |
| @@ -27,6 +27,358 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -27,6 +27,358 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 27 | #include <srs_kernel_log.hpp> | 27 | #include <srs_kernel_log.hpp> |
| 28 | #include <srs_kernel_stream.hpp> | 28 | #include <srs_kernel_stream.hpp> |
| 29 | #include <srs_kernel_utility.hpp> | 29 | #include <srs_kernel_utility.hpp> |
| 30 | +#include <srs_kernel_buffer.hpp> | ||
| 31 | + | ||
| 32 | +// in ms, for HLS aac sync time. | ||
| 33 | +#define SRS_CONF_DEFAULT_AAC_SYNC 100 | ||
| 34 | + | ||
| 35 | +// @see: ngx_rtmp_hls_audio | ||
| 36 | +/* We assume here AAC frame size is 1024 | ||
| 37 | + * Need to handle AAC frames with frame size of 960 */ | ||
| 38 | +#define _SRS_AAC_SAMPLE_SIZE 1024 | ||
| 39 | + | ||
| 40 | +// the mpegts header specifed the video/audio pid. | ||
| 41 | +#define TS_VIDEO_PID 256 | ||
| 42 | +#define TS_AUDIO_PID 257 | ||
| 43 | + | ||
| 44 | +// ts aac stream id. | ||
| 45 | +#define TS_AUDIO_AAC 0xc0 | ||
| 46 | +// ts avc stream id. | ||
| 47 | +#define TS_VIDEO_AVC 0xe0 | ||
| 48 | + | ||
| 49 | +/** | ||
| 50 | +* the public data, event HLS disable, others can use it. | ||
| 51 | +*/ | ||
| 52 | +// 0 = 5.5 kHz = 5512 Hz | ||
| 53 | +// 1 = 11 kHz = 11025 Hz | ||
| 54 | +// 2 = 22 kHz = 22050 Hz | ||
| 55 | +// 3 = 44 kHz = 44100 Hz | ||
| 56 | +int flv_sample_rates[] = {5512, 11025, 22050, 44100}; | ||
| 57 | + | ||
| 58 | +// the sample rates in the codec, | ||
| 59 | +// in the sequence header. | ||
| 60 | +int aac_sample_rates[] = | ||
| 61 | +{ | ||
| 62 | + 96000, 88200, 64000, 48000, | ||
| 63 | + 44100, 32000, 24000, 22050, | ||
| 64 | + 16000, 12000, 11025, 8000, | ||
| 65 | + 7350, 0, 0, 0 | ||
| 66 | +}; | ||
| 67 | + | ||
| 68 | +SrsMpegtsFrame::SrsMpegtsFrame() | ||
| 69 | +{ | ||
| 70 | + pts = dts = 0; | ||
| 71 | + pid = sid = cc = 0; | ||
| 72 | + key = false; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +SrsTsAacJitter::SrsTsAacJitter() | ||
| 76 | +{ | ||
| 77 | + base_pts = 0; | ||
| 78 | + nb_samples = 0; | ||
| 79 | + | ||
| 80 | + // TODO: config it, 0 means no adjust | ||
| 81 | + sync_ms = SRS_CONF_DEFAULT_AAC_SYNC; | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +SrsTsAacJitter::~SrsTsAacJitter() | ||
| 85 | +{ | ||
| 86 | +} | ||
| 87 | + | ||
| 88 | +int64_t SrsTsAacJitter::on_buffer_start(int64_t flv_pts, int sample_rate, int aac_sample_rate) | ||
| 89 | +{ | ||
| 90 | + // use sample rate in flv/RTMP. | ||
| 91 | + int flv_sample_rate = flv_sample_rates[sample_rate & 0x03]; | ||
| 92 | + | ||
| 93 | + // override the sample rate by sequence header | ||
| 94 | + if (aac_sample_rate != __SRS_AAC_SAMPLE_RATE_UNSET) { | ||
| 95 | + flv_sample_rate = aac_sample_rates[aac_sample_rate]; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + // sync time set to 0, donot adjust the aac timestamp. | ||
| 99 | + if (!sync_ms) { | ||
| 100 | + return flv_pts; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + // @see: ngx_rtmp_hls_audio | ||
| 104 | + // drop the rtmp audio packet timestamp, re-calc it by sample rate. | ||
| 105 | + // | ||
| 106 | + // resample for the tbn of ts is 90000, flv is 1000, | ||
| 107 | + // we will lost timestamp if use audio packet timestamp, | ||
| 108 | + // so we must resample. or audio will corupt in IOS. | ||
| 109 | + int64_t est_pts = base_pts + nb_samples * 90000LL * _SRS_AAC_SAMPLE_SIZE / flv_sample_rate; | ||
| 110 | + int64_t dpts = (int64_t) (est_pts - flv_pts); | ||
| 111 | + | ||
| 112 | + if (dpts <= (int64_t) sync_ms * 90 && dpts >= (int64_t) sync_ms * -90) { | ||
| 113 | + srs_info("HLS correct aac pts " | ||
| 114 | + "from %"PRId64" to %"PRId64", base=%"PRId64", nb_samples=%d, sample_rate=%d", | ||
| 115 | + flv_pts, est_pts, nb_samples, flv_sample_rate, base_pts); | ||
| 116 | + | ||
| 117 | + nb_samples++; | ||
| 118 | + | ||
| 119 | + return est_pts; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + // resync | ||
| 123 | + srs_trace("HLS aac resync, dpts=%"PRId64", pts=%"PRId64 | ||
| 124 | + ", base=%"PRId64", nb_samples=%"PRId64", sample_rate=%d", | ||
| 125 | + dpts, flv_pts, base_pts, nb_samples, flv_sample_rate); | ||
| 126 | + | ||
| 127 | + base_pts = flv_pts; | ||
| 128 | + nb_samples = 1; | ||
| 129 | + | ||
| 130 | + return flv_pts; | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +void SrsTsAacJitter::on_buffer_continue() | ||
| 134 | +{ | ||
| 135 | + nb_samples++; | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +SrsTsCache::SrsTsCache() | ||
| 139 | +{ | ||
| 140 | + aac_jitter = new SrsTsAacJitter(); | ||
| 141 | + | ||
| 142 | + ab = new SrsSimpleBuffer(); | ||
| 143 | + vb = new SrsSimpleBuffer(); | ||
| 144 | + | ||
| 145 | + af = new SrsMpegtsFrame(); | ||
| 146 | + vf = new SrsMpegtsFrame(); | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +SrsTsCache::~SrsTsCache() | ||
| 150 | +{ | ||
| 151 | + srs_freep(aac_jitter); | ||
| 152 | + | ||
| 153 | + ab->erase(ab->length()); | ||
| 154 | + vb->erase(vb->length()); | ||
| 155 | + | ||
| 156 | + srs_freep(ab); | ||
| 157 | + srs_freep(vb); | ||
| 158 | + | ||
| 159 | + srs_freep(af); | ||
| 160 | + srs_freep(vf); | ||
| 161 | +} | ||
| 162 | + | ||
| 163 | +int SrsTsCache::cache_audio(SrsAvcAacCodec* codec, int64_t pts, SrsCodecSample* sample) | ||
| 164 | +{ | ||
| 165 | + int ret = ERROR_SUCCESS; | ||
| 166 | + | ||
| 167 | + // start buffer, set the af | ||
| 168 | + if (ab->length() == 0) { | ||
| 169 | + pts = aac_jitter->on_buffer_start(pts, sample->sound_rate, codec->aac_sample_rate); | ||
| 170 | + | ||
| 171 | + af->dts = af->pts = pts; | ||
| 172 | + af->pid = TS_AUDIO_PID; | ||
| 173 | + af->sid = TS_AUDIO_AAC; | ||
| 174 | + } else { | ||
| 175 | + aac_jitter->on_buffer_continue(); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + // write audio to cache. | ||
| 179 | + if ((ret = do_cache_audio(codec, sample)) != ERROR_SUCCESS) { | ||
| 180 | + return ret; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + return ret; | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +int SrsTsCache::cache_video(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample) | ||
| 187 | +{ | ||
| 188 | + int ret = ERROR_SUCCESS; | ||
| 189 | + | ||
| 190 | + // write video to cache. | ||
| 191 | + if ((ret = do_cache_video(codec, sample)) != ERROR_SUCCESS) { | ||
| 192 | + return ret; | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + vf->dts = dts; | ||
| 196 | + vf->pts = vf->dts + sample->cts * 90; | ||
| 197 | + vf->pid = TS_VIDEO_PID; | ||
| 198 | + vf->sid = TS_VIDEO_AVC; | ||
| 199 | + vf->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; | ||
| 200 | + | ||
| 201 | + return ret; | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +int SrsTsCache::do_cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample) | ||
| 205 | +{ | ||
| 206 | + int ret = ERROR_SUCCESS; | ||
| 207 | + | ||
| 208 | + for (int i = 0; i < sample->nb_sample_units; i++) { | ||
| 209 | + SrsCodecSampleUnit* sample_unit = &sample->sample_units[i]; | ||
| 210 | + int32_t size = sample_unit->size; | ||
| 211 | + | ||
| 212 | + if (!sample_unit->bytes || size <= 0 || size > 0x1fff) { | ||
| 213 | + ret = ERROR_HLS_AAC_FRAME_LENGTH; | ||
| 214 | + srs_error("invalid aac frame length=%d, ret=%d", size, ret); | ||
| 215 | + return ret; | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + // the frame length is the AAC raw data plus the adts header size. | ||
| 219 | + int32_t frame_length = size + 7; | ||
| 220 | + | ||
| 221 | + // AAC-ADTS | ||
| 222 | + // 6.2 Audio Data Transport Stream, ADTS | ||
| 223 | + // in aac-iso-13818-7.pdf, page 26. | ||
| 224 | + // fixed 7bytes header | ||
| 225 | + static u_int8_t adts_header[7] = {0xff, 0xf1, 0x00, 0x00, 0x00, 0x0f, 0xfc}; | ||
| 226 | + /* | ||
| 227 | + // adts_fixed_header | ||
| 228 | + // 2B, 16bits | ||
| 229 | + int16_t syncword; //12bits, '1111 1111 1111' | ||
| 230 | + int8_t ID; //1bit, '0' | ||
| 231 | + int8_t layer; //2bits, '00' | ||
| 232 | + int8_t protection_absent; //1bit, can be '1' | ||
| 233 | + // 12bits | ||
| 234 | + int8_t profile; //2bit, 7.1 Profiles, page 40 | ||
| 235 | + TSAacSampleFrequency sampling_frequency_index; //4bits, Table 35, page 46 | ||
| 236 | + int8_t private_bit; //1bit, can be '0' | ||
| 237 | + int8_t channel_configuration; //3bits, Table 8 | ||
| 238 | + int8_t original_or_copy; //1bit, can be '0' | ||
| 239 | + int8_t home; //1bit, can be '0' | ||
| 240 | + | ||
| 241 | + // adts_variable_header | ||
| 242 | + // 28bits | ||
| 243 | + int8_t copyright_identification_bit; //1bit, can be '0' | ||
| 244 | + int8_t copyright_identification_start; //1bit, can be '0' | ||
| 245 | + int16_t frame_length; //13bits | ||
| 246 | + int16_t adts_buffer_fullness; //11bits, 7FF signals that the bitstream is a variable rate bitstream. | ||
| 247 | + int8_t number_of_raw_data_blocks_in_frame; //2bits, 0 indicating 1 raw_data_block() | ||
| 248 | + */ | ||
| 249 | + // profile, 2bits | ||
| 250 | + adts_header[2] = (codec->aac_profile << 6) & 0xc0; | ||
| 251 | + // sampling_frequency_index 4bits | ||
| 252 | + adts_header[2] |= (codec->aac_sample_rate << 2) & 0x3c; | ||
| 253 | + // channel_configuration 3bits | ||
| 254 | + adts_header[2] |= (codec->aac_channels >> 2) & 0x01; | ||
| 255 | + adts_header[3] = (codec->aac_channels << 6) & 0xc0; | ||
| 256 | + // frame_length 13bits | ||
| 257 | + adts_header[3] |= (frame_length >> 11) & 0x03; | ||
| 258 | + adts_header[4] = (frame_length >> 3) & 0xff; | ||
| 259 | + adts_header[5] = ((frame_length << 5) & 0xe0); | ||
| 260 | + // adts_buffer_fullness; //11bits | ||
| 261 | + adts_header[5] |= 0x1f; | ||
| 262 | + | ||
| 263 | + // copy to audio buffer | ||
| 264 | + ab->append((const char*)adts_header, sizeof(adts_header)); | ||
| 265 | + ab->append(sample_unit->bytes, sample_unit->size); | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + return ret; | ||
| 269 | +} | ||
| 270 | + | ||
| 271 | +int SrsTsCache::do_cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample) | ||
| 272 | +{ | ||
| 273 | + int ret = ERROR_SUCCESS; | ||
| 274 | + | ||
| 275 | + // for type1/5/6, insert aud packet. | ||
| 276 | + static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; | ||
| 277 | + | ||
| 278 | + bool sps_pps_sent = false; | ||
| 279 | + bool aud_sent = false; | ||
| 280 | + /** | ||
| 281 | + * a ts sample is format as: | ||
| 282 | + * 00 00 00 01 // header | ||
| 283 | + * xxxxxxx // data bytes | ||
| 284 | + * 00 00 01 // continue header | ||
| 285 | + * xxxxxxx // data bytes. | ||
| 286 | + * so, for each sample, we append header in aud_nal, then appends the bytes in sample. | ||
| 287 | + */ | ||
| 288 | + for (int i = 0; i < sample->nb_sample_units; i++) { | ||
| 289 | + SrsCodecSampleUnit* sample_unit = &sample->sample_units[i]; | ||
| 290 | + int32_t size = sample_unit->size; | ||
| 291 | + | ||
| 292 | + if (!sample_unit->bytes || size <= 0) { | ||
| 293 | + ret = ERROR_HLS_AVC_SAMPLE_SIZE; | ||
| 294 | + srs_error("invalid avc sample length=%d, ret=%d", size, ret); | ||
| 295 | + return ret; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + /** | ||
| 299 | + * step 1: | ||
| 300 | + * first, before each "real" sample, | ||
| 301 | + * we add some packets according to the nal_unit_type, | ||
| 302 | + * for example, when got nal_unit_type=5, insert SPS/PPS before sample. | ||
| 303 | + */ | ||
| 304 | + | ||
| 305 | + // 5bits, 7.3.1 NAL unit syntax, | ||
| 306 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 307 | + u_int8_t nal_unit_type; | ||
| 308 | + nal_unit_type = *sample_unit->bytes; | ||
| 309 | + nal_unit_type &= 0x1f; | ||
| 310 | + | ||
| 311 | + // @see: ngx_rtmp_hls_video | ||
| 312 | + // Table 7-1 ¨C NAL unit type codes, page 61 | ||
| 313 | + // 1: Coded slice | ||
| 314 | + if (nal_unit_type == 1) { | ||
| 315 | + sps_pps_sent = false; | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + // 6: Supplemental enhancement information (SEI) sei_rbsp( ), page 61 | ||
| 319 | + // @see: ngx_rtmp_hls_append_aud | ||
| 320 | + if (!aud_sent) { | ||
| 321 | + // @remark, when got type 9, we donot send aud_nal, but it will make | ||
| 322 | + // ios unhappy, so we remove it. | ||
| 323 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/281 | ||
| 324 | + /*if (nal_unit_type == 9) { | ||
| 325 | + aud_sent = true; | ||
| 326 | + }*/ | ||
| 327 | + | ||
| 328 | + if (nal_unit_type == 1 || nal_unit_type == 5 || nal_unit_type == 6) { | ||
| 329 | + // for type 6, append a aud with type 9. | ||
| 330 | + vb->append((const char*)aud_nal, sizeof(aud_nal)); | ||
| 331 | + aud_sent = true; | ||
| 332 | + } | ||
| 333 | + } | ||
| 334 | + | ||
| 335 | + // 5: Coded slice of an IDR picture. | ||
| 336 | + // insert sps/pps before IDR or key frame is ok. | ||
| 337 | + if (nal_unit_type == 5 && !sps_pps_sent) { | ||
| 338 | + sps_pps_sent = true; | ||
| 339 | + | ||
| 340 | + // @see: ngx_rtmp_hls_append_sps_pps | ||
| 341 | + if (codec->sequenceParameterSetLength > 0) { | ||
| 342 | + // AnnexB prefix, for sps always 4 bytes header | ||
| 343 | + vb->append((const char*)aud_nal, 4); | ||
| 344 | + // sps | ||
| 345 | + vb->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength); | ||
| 346 | + } | ||
| 347 | + if (codec->pictureParameterSetLength > 0) { | ||
| 348 | + // AnnexB prefix, for pps always 4 bytes header | ||
| 349 | + vb->append((const char*)aud_nal, 4); | ||
| 350 | + // pps | ||
| 351 | + vb->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength); | ||
| 352 | + } | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + // 7-9, ignore, @see: ngx_rtmp_hls_video | ||
| 356 | + if (nal_unit_type >= 7 && nal_unit_type <= 9) { | ||
| 357 | + continue; | ||
| 358 | + } | ||
| 359 | + | ||
| 360 | + /** | ||
| 361 | + * step 2: | ||
| 362 | + * output the "real" sample, in buf. | ||
| 363 | + * when we output some special assist packets according to nal_unit_type | ||
| 364 | + */ | ||
| 365 | + | ||
| 366 | + // sample start prefix, '00 00 00 01' or '00 00 01' | ||
| 367 | + u_int8_t* p = aud_nal + 1; | ||
| 368 | + u_int8_t* end = p + 3; | ||
| 369 | + | ||
| 370 | + // first AnnexB prefix is long (4 bytes) | ||
| 371 | + if (vb->length() == 0) { | ||
| 372 | + p = aud_nal; | ||
| 373 | + } | ||
| 374 | + vb->append((const char*)p, end - p); | ||
| 375 | + | ||
| 376 | + // sample data | ||
| 377 | + vb->append(sample_unit->bytes, sample_unit->size); | ||
| 378 | + } | ||
| 379 | + | ||
| 380 | + return ret; | ||
| 381 | +} | ||
| 30 | 382 | ||
| 31 | SrsCodecSampleUnit::SrsCodecSampleUnit() | 383 | SrsCodecSampleUnit::SrsCodecSampleUnit() |
| 32 | { | 384 | { |
| @@ -33,11 +33,30 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -33,11 +33,30 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 33 | #include <srs_kernel_codec.hpp> | 33 | #include <srs_kernel_codec.hpp> |
| 34 | 34 | ||
| 35 | class SrsStream; | 35 | class SrsStream; |
| 36 | -class SrsAmf0Object; | 36 | +class SrsMpegtsFrame; |
| 37 | +class SrsSimpleBuffer; | ||
| 38 | +class SrsAvcAacCodec; | ||
| 39 | +class SrsCodecSample; | ||
| 40 | + | ||
| 41 | +/** | ||
| 42 | +* the public data, event HLS disable, others can use it. | ||
| 43 | +*/ | ||
| 44 | +/** | ||
| 45 | +* the flv sample rate map | ||
| 46 | +*/ | ||
| 47 | +extern int flv_sample_rates[]; | ||
| 48 | + | ||
| 49 | +/** | ||
| 50 | +* the aac sample rate map | ||
| 51 | +*/ | ||
| 52 | +extern int aac_sample_rates[]; | ||
| 37 | 53 | ||
| 38 | #define __SRS_SRS_MAX_CODEC_SAMPLE 128 | 54 | #define __SRS_SRS_MAX_CODEC_SAMPLE 128 |
| 39 | #define __SRS_AAC_SAMPLE_RATE_UNSET 15 | 55 | #define __SRS_AAC_SAMPLE_RATE_UNSET 15 |
| 40 | 56 | ||
| 57 | +// in ms, for HLS aac flush the audio | ||
| 58 | +#define SRS_CONF_DEFAULT_AAC_DELAY 100 | ||
| 59 | + | ||
| 41 | /** | 60 | /** |
| 42 | * the FLV/RTMP supported audio sample size. | 61 | * the FLV/RTMP supported audio sample size. |
| 43 | * Size of each audio sample. This parameter only pertains to | 62 | * Size of each audio sample. This parameter only pertains to |
| @@ -70,6 +89,90 @@ enum SrsCodecAudioSoundType | @@ -70,6 +89,90 @@ enum SrsCodecAudioSoundType | ||
| 70 | SrsCodecAudioSoundTypeStereo = 1, | 89 | SrsCodecAudioSoundTypeStereo = 1, |
| 71 | }; | 90 | }; |
| 72 | 91 | ||
| 92 | +// @see: ngx_rtmp_SrsMpegtsFrame_t | ||
| 93 | +class SrsMpegtsFrame | ||
| 94 | +{ | ||
| 95 | +public: | ||
| 96 | + int64_t pts; | ||
| 97 | + int64_t dts; | ||
| 98 | + int pid; | ||
| 99 | + int sid; | ||
| 100 | + int cc; | ||
| 101 | + bool key; | ||
| 102 | + | ||
| 103 | + SrsMpegtsFrame(); | ||
| 104 | +}; | ||
| 105 | + | ||
| 106 | +/** | ||
| 107 | +* jitter correct for audio, | ||
| 108 | +* the sample rate 44100/32000 will lost precise, | ||
| 109 | +* when mp4/ts(tbn=90000) covert to flv/rtmp(1000), | ||
| 110 | +* so the Hls on ipad or iphone will corrupt, | ||
| 111 | +* @see nginx-rtmp: est_pts | ||
| 112 | +*/ | ||
| 113 | +class SrsTsAacJitter | ||
| 114 | +{ | ||
| 115 | +private: | ||
| 116 | + int64_t base_pts; | ||
| 117 | + int64_t nb_samples; | ||
| 118 | + int sync_ms; | ||
| 119 | +public: | ||
| 120 | + SrsTsAacJitter(); | ||
| 121 | + virtual ~SrsTsAacJitter(); | ||
| 122 | + /** | ||
| 123 | + * when buffer start, calc the "correct" pts for ts, | ||
| 124 | + * @param flv_pts, the flv pts calc from flv header timestamp, | ||
| 125 | + * @param sample_rate, the sample rate in format(flv/RTMP packet header). | ||
| 126 | + * @param aac_sample_rate, the sample rate in codec(sequence header). | ||
| 127 | + * @return the calc correct pts. | ||
| 128 | + */ | ||
| 129 | + virtual int64_t on_buffer_start(int64_t flv_pts, int sample_rate, int aac_sample_rate); | ||
| 130 | + /** | ||
| 131 | + * when buffer continue, muxer donot write to file, | ||
| 132 | + * the audio buffer continue grow and donot need a pts, | ||
| 133 | + * for the ts audio PES packet only has one pts at the first time. | ||
| 134 | + */ | ||
| 135 | + virtual void on_buffer_continue(); | ||
| 136 | +}; | ||
| 137 | + | ||
| 138 | +/** | ||
| 139 | +* ts stream cache, | ||
| 140 | +* use to cache ts stream. | ||
| 141 | +* | ||
| 142 | +* about the flv tbn problem: | ||
| 143 | +* flv tbn is 1/1000, ts tbn is 1/90000, | ||
| 144 | +* when timestamp convert to flv tbn, it will loose precise, | ||
| 145 | +* so we must gather audio frame together, and recalc the timestamp @see SrsTsAacJitter, | ||
| 146 | +* we use a aac jitter to correct the audio pts. | ||
| 147 | +*/ | ||
| 148 | +class SrsTsCache | ||
| 149 | +{ | ||
| 150 | +public: | ||
| 151 | + // current frame and buffer | ||
| 152 | + SrsMpegtsFrame* af; | ||
| 153 | + SrsSimpleBuffer* ab; | ||
| 154 | + SrsMpegtsFrame* vf; | ||
| 155 | + SrsSimpleBuffer* vb; | ||
| 156 | +protected: | ||
| 157 | + // time jitter for aac | ||
| 158 | + SrsTsAacJitter* aac_jitter; | ||
| 159 | +public: | ||
| 160 | + SrsTsCache(); | ||
| 161 | + virtual ~SrsTsCache(); | ||
| 162 | +public: | ||
| 163 | + /** | ||
| 164 | + * write audio to cache | ||
| 165 | + */ | ||
| 166 | + virtual int cache_audio(SrsAvcAacCodec* codec, int64_t pts, SrsCodecSample* sample); | ||
| 167 | + /** | ||
| 168 | + * write video to muxer. | ||
| 169 | + */ | ||
| 170 | + virtual int cache_video(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample); | ||
| 171 | +private: | ||
| 172 | + virtual int do_cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample); | ||
| 173 | + virtual int do_cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample); | ||
| 174 | +}; | ||
| 175 | + | ||
| 73 | /** | 176 | /** |
| 74 | * the codec sample unit. | 177 | * the codec sample unit. |
| 75 | * for h.264 video packet, a NALU is a sample unit. | 178 | * for h.264 video packet, a NALU is a sample unit. |
trunk/src/kernel/srs_kernel_buffer.cpp
0 → 100644
| 1 | +/* | ||
| 2 | +The MIT License (MIT) | ||
| 3 | + | ||
| 4 | +Copyright (c) 2013-2015 winlin | ||
| 5 | + | ||
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 7 | +this software and associated documentation files (the "Software"), to deal in | ||
| 8 | +the Software without restriction, including without limitation the rights to | ||
| 9 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| 10 | +the Software, and to permit persons to whom the Software is furnished to do so, | ||
| 11 | +subject to the following conditions: | ||
| 12 | + | ||
| 13 | +The above copyright notice and this permission notice shall be included in all | ||
| 14 | +copies or substantial portions of the Software. | ||
| 15 | + | ||
| 16 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| 18 | +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| 19 | +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 20 | +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 21 | +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 22 | +*/ | ||
| 23 | + | ||
| 24 | +#include <srs_kernel_buffer.hpp> | ||
| 25 | + | ||
| 26 | +#include <srs_kernel_error.hpp> | ||
| 27 | +#include <srs_kernel_log.hpp> | ||
| 28 | +#include <srs_kernel_utility.hpp> | ||
| 29 | +#include <srs_core_performance.hpp> | ||
| 30 | + | ||
| 31 | +SrsSimpleBuffer::SrsSimpleBuffer() | ||
| 32 | +{ | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +SrsSimpleBuffer::~SrsSimpleBuffer() | ||
| 36 | +{ | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +int SrsSimpleBuffer::length() | ||
| 40 | +{ | ||
| 41 | + int len = (int)data.size(); | ||
| 42 | + srs_assert(len >= 0); | ||
| 43 | + return len; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +char* SrsSimpleBuffer::bytes() | ||
| 47 | +{ | ||
| 48 | + return (length() == 0)? NULL : &data.at(0); | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +void SrsSimpleBuffer::erase(int size) | ||
| 52 | +{ | ||
| 53 | + if (size <= 0) { | ||
| 54 | + return; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + if (size >= length()) { | ||
| 58 | + data.clear(); | ||
| 59 | + return; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + data.erase(data.begin(), data.begin() + size); | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +void SrsSimpleBuffer::append(const char* bytes, int size) | ||
| 66 | +{ | ||
| 67 | + srs_assert(size > 0); | ||
| 68 | + | ||
| 69 | + data.insert(data.end(), bytes, bytes + size); | ||
| 70 | +} |
trunk/src/kernel/srs_kernel_buffer.hpp
0 → 100644
| 1 | +/* | ||
| 2 | +The MIT License (MIT) | ||
| 3 | + | ||
| 4 | +Copyright (c) 2013-2015 winlin | ||
| 5 | + | ||
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 7 | +this software and associated documentation files (the "Software"), to deal in | ||
| 8 | +the Software without restriction, including without limitation the rights to | ||
| 9 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| 10 | +the Software, and to permit persons to whom the Software is furnished to do so, | ||
| 11 | +subject to the following conditions: | ||
| 12 | + | ||
| 13 | +The above copyright notice and this permission notice shall be included in all | ||
| 14 | +copies or substantial portions of the Software. | ||
| 15 | + | ||
| 16 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| 18 | +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| 19 | +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 20 | +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 21 | +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 22 | +*/ | ||
| 23 | + | ||
| 24 | +#ifndef SRS_KERNEL_BUFFER_HPP | ||
| 25 | +#define SRS_KERNEL_BUFFER_HPP | ||
| 26 | + | ||
| 27 | +/* | ||
| 28 | +#include <srs_kernel_buffer.hpp> | ||
| 29 | +*/ | ||
| 30 | + | ||
| 31 | +#include <srs_core.hpp> | ||
| 32 | + | ||
| 33 | +#include <vector> | ||
| 34 | + | ||
| 35 | +/** | ||
| 36 | +* the simple buffer use vector to append bytes, | ||
| 37 | +* it's for hls and http, and need to be refined in future. | ||
| 38 | +*/ | ||
| 39 | +class SrsSimpleBuffer | ||
| 40 | +{ | ||
| 41 | +private: | ||
| 42 | + std::vector<char> data; | ||
| 43 | +public: | ||
| 44 | + SrsSimpleBuffer(); | ||
| 45 | + virtual ~SrsSimpleBuffer(); | ||
| 46 | +public: | ||
| 47 | + /** | ||
| 48 | + * get the length of buffer. empty if zero. | ||
| 49 | + * @remark assert length() is not negative. | ||
| 50 | + */ | ||
| 51 | + virtual int length(); | ||
| 52 | + /** | ||
| 53 | + * get the buffer bytes. | ||
| 54 | + * @return the bytes, NULL if empty. | ||
| 55 | + */ | ||
| 56 | + virtual char* bytes(); | ||
| 57 | + /** | ||
| 58 | + * erase size of bytes from begin. | ||
| 59 | + * @param size to erase size of bytes. | ||
| 60 | + * clear if size greater than or equals to length() | ||
| 61 | + * @remark ignore size is not positive. | ||
| 62 | + */ | ||
| 63 | + virtual void erase(int size); | ||
| 64 | + /** | ||
| 65 | + * append specified bytes to buffer. | ||
| 66 | + * @param size the size of bytes | ||
| 67 | + * @remark assert size is positive. | ||
| 68 | + */ | ||
| 69 | + virtual void append(const char* bytes, int size); | ||
| 70 | +}; | ||
| 71 | + | ||
| 72 | +#endif |
| @@ -40,47 +40,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -40,47 +40,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 40 | // @see SrsProtocol::read_message_header(). | 40 | // @see SrsProtocol::read_message_header(). |
| 41 | #define SRS_RTMP_MAX_MESSAGE_HEADER 11 | 41 | #define SRS_RTMP_MAX_MESSAGE_HEADER 11 |
| 42 | 42 | ||
| 43 | -SrsSimpleBuffer::SrsSimpleBuffer() | ||
| 44 | -{ | ||
| 45 | -} | ||
| 46 | - | ||
| 47 | -SrsSimpleBuffer::~SrsSimpleBuffer() | ||
| 48 | -{ | ||
| 49 | -} | ||
| 50 | - | ||
| 51 | -int SrsSimpleBuffer::length() | ||
| 52 | -{ | ||
| 53 | - int len = (int)data.size(); | ||
| 54 | - srs_assert(len >= 0); | ||
| 55 | - return len; | ||
| 56 | -} | ||
| 57 | - | ||
| 58 | -char* SrsSimpleBuffer::bytes() | ||
| 59 | -{ | ||
| 60 | - return (length() == 0)? NULL : &data.at(0); | ||
| 61 | -} | ||
| 62 | - | ||
| 63 | -void SrsSimpleBuffer::erase(int size) | ||
| 64 | -{ | ||
| 65 | - if (size <= 0) { | ||
| 66 | - return; | ||
| 67 | - } | ||
| 68 | - | ||
| 69 | - if (size >= length()) { | ||
| 70 | - data.clear(); | ||
| 71 | - return; | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - data.erase(data.begin(), data.begin() + size); | ||
| 75 | -} | ||
| 76 | - | ||
| 77 | -void SrsSimpleBuffer::append(const char* bytes, int size) | ||
| 78 | -{ | ||
| 79 | - srs_assert(size > 0); | ||
| 80 | - | ||
| 81 | - data.insert(data.end(), bytes, bytes + size); | ||
| 82 | -} | ||
| 83 | - | ||
| 84 | #ifdef SRS_PERF_MERGED_READ | 43 | #ifdef SRS_PERF_MERGED_READ |
| 85 | IMergeReadHandler::IMergeReadHandler() | 44 | IMergeReadHandler::IMergeReadHandler() |
| 86 | { | 45 | { |
| @@ -30,47 +30,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -30,47 +30,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 30 | 30 | ||
| 31 | #include <srs_core.hpp> | 31 | #include <srs_core.hpp> |
| 32 | 32 | ||
| 33 | -#include <vector> | ||
| 34 | - | ||
| 35 | #include <srs_protocol_io.hpp> | 33 | #include <srs_protocol_io.hpp> |
| 36 | #include <srs_core_performance.hpp> | 34 | #include <srs_core_performance.hpp> |
| 37 | - | ||
| 38 | -/** | ||
| 39 | -* the simple buffer use vector to append bytes, | ||
| 40 | -* it's for hls and http, and need to be refined in future. | ||
| 41 | -*/ | ||
| 42 | -class SrsSimpleBuffer | ||
| 43 | -{ | ||
| 44 | -private: | ||
| 45 | - std::vector<char> data; | ||
| 46 | -public: | ||
| 47 | - SrsSimpleBuffer(); | ||
| 48 | - virtual ~SrsSimpleBuffer(); | ||
| 49 | -public: | ||
| 50 | - /** | ||
| 51 | - * get the length of buffer. empty if zero. | ||
| 52 | - * @remark assert length() is not negative. | ||
| 53 | - */ | ||
| 54 | - virtual int length(); | ||
| 55 | - /** | ||
| 56 | - * get the buffer bytes. | ||
| 57 | - * @return the bytes, NULL if empty. | ||
| 58 | - */ | ||
| 59 | - virtual char* bytes(); | ||
| 60 | - /** | ||
| 61 | - * erase size of bytes from begin. | ||
| 62 | - * @param size to erase size of bytes. | ||
| 63 | - * clear if size greater than or equals to length() | ||
| 64 | - * @remark ignore size is not positive. | ||
| 65 | - */ | ||
| 66 | - virtual void erase(int size); | ||
| 67 | - /** | ||
| 68 | - * append specified bytes to buffer. | ||
| 69 | - * @param size the size of bytes | ||
| 70 | - * @remark assert size is positive. | ||
| 71 | - */ | ||
| 72 | - virtual void append(const char* bytes, int size); | ||
| 73 | -}; | 35 | +#include <srs_kernel_buffer.hpp> |
| 74 | 36 | ||
| 75 | #ifdef SRS_PERF_MERGED_READ | 37 | #ifdef SRS_PERF_MERGED_READ |
| 76 | /** | 38 | /** |
-
请 注册 或 登录 后发表评论