正在显示
10 个修改的文件
包含
387 行增加
和
97 行删除
trunk/doc/H.264-AVC-ISO_IEC_14496-15.pdf
0 → 100644
不能预览此文件类型
| @@ -151,6 +151,7 @@ int SrsClient::do_cycle() | @@ -151,6 +151,7 @@ int SrsClient::do_cycle() | ||
| 151 | // find a source to publish. | 151 | // find a source to publish. |
| 152 | SrsSource* source = SrsSource::find(req->get_stream_url()); | 152 | SrsSource* source = SrsSource::find(req->get_stream_url()); |
| 153 | srs_assert(source != NULL); | 153 | srs_assert(source != NULL); |
| 154 | + SrsHLS* hls = source->get_hls(); | ||
| 154 | 155 | ||
| 155 | bool enabled_cache = true; | 156 | bool enabled_cache = true; |
| 156 | conf = config->get_gop_cache(req->vhost); | 157 | conf = config->get_gop_cache(req->vhost); |
| @@ -181,6 +182,7 @@ int SrsClient::do_cycle() | @@ -181,6 +182,7 @@ int SrsClient::do_cycle() | ||
| 181 | } | 182 | } |
| 182 | srs_info("start to publish stream %s success", req->stream.c_str()); | 183 | srs_info("start to publish stream %s success", req->stream.c_str()); |
| 183 | ret = publish(source, true); | 184 | ret = publish(source, true); |
| 185 | + hls->on_unpublish(); | ||
| 184 | source->on_unpublish(); | 186 | source->on_unpublish(); |
| 185 | return ret; | 187 | return ret; |
| 186 | } | 188 | } |
| @@ -193,6 +195,7 @@ int SrsClient::do_cycle() | @@ -193,6 +195,7 @@ int SrsClient::do_cycle() | ||
| 193 | } | 195 | } |
| 194 | srs_info("flash start to publish stream %s success", req->stream.c_str()); | 196 | srs_info("flash start to publish stream %s success", req->stream.c_str()); |
| 195 | ret = publish(source, false); | 197 | ret = publish(source, false); |
| 198 | + hls->on_unpublish(); | ||
| 196 | source->on_unpublish(); | 199 | source->on_unpublish(); |
| 197 | return ret; | 200 | return ret; |
| 198 | } | 201 | } |
| @@ -330,8 +333,15 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) | @@ -330,8 +333,15 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) | ||
| 330 | srs_verbose("check publish_refer success."); | 333 | srs_verbose("check publish_refer success."); |
| 331 | 334 | ||
| 332 | SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); | 335 | SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); |
| 333 | - | ||
| 334 | SrsHLS* hls = source->get_hls(); | 336 | SrsHLS* hls = source->get_hls(); |
| 337 | + | ||
| 338 | + // notify the hls to prepare when publish start. | ||
| 339 | + if ((ret = hls->on_publish()) != ERROR_SUCCESS) { | ||
| 340 | + srs_error("hls on_publish failed. ret=%d", ret); | ||
| 341 | + return ret; | ||
| 342 | + } | ||
| 343 | + srs_verbose("hls on_publish success."); | ||
| 344 | + | ||
| 335 | while (true) { | 345 | while (true) { |
| 336 | // switch to other st-threads. | 346 | // switch to other st-threads. |
| 337 | st_usleep(0); | 347 | st_usleep(0); |
| @@ -366,14 +376,26 @@ int SrsClient::process_publish_message(SrsSource* source, SrsHLS* hls, SrsCommon | @@ -366,14 +376,26 @@ int SrsClient::process_publish_message(SrsSource* source, SrsHLS* hls, SrsCommon | ||
| 366 | int ret = ERROR_SUCCESS; | 376 | int ret = ERROR_SUCCESS; |
| 367 | 377 | ||
| 368 | // process audio packet | 378 | // process audio packet |
| 369 | - if (msg->header.is_audio() && ((ret = source->on_audio(msg)) != ERROR_SUCCESS)) { | ||
| 370 | - srs_error("process audio message failed. ret=%d", ret); | ||
| 371 | - return ret; | 379 | + if (msg->header.is_audio()) { |
| 380 | + if ((ret = hls->on_audio(msg)) != ERROR_SUCCESS) { | ||
| 381 | + srs_error("hls process audio message failed. ret=%d", ret); | ||
| 382 | + return ret; | ||
| 383 | + } | ||
| 384 | + if ((ret = source->on_audio(msg)) != ERROR_SUCCESS) { | ||
| 385 | + srs_error("source process audio message failed. ret=%d", ret); | ||
| 386 | + return ret; | ||
| 387 | + } | ||
| 372 | } | 388 | } |
| 373 | // process video packet | 389 | // process video packet |
| 374 | - if (msg->header.is_video() && ((ret = source->on_video(msg)) != ERROR_SUCCESS)) { | ||
| 375 | - srs_error("process video message failed. ret=%d", ret); | ||
| 376 | - return ret; | 390 | + if (msg->header.is_video()) { |
| 391 | + if ((ret = hls->on_video(msg)) != ERROR_SUCCESS) { | ||
| 392 | + srs_error("hls process video message failed. ret=%d", ret); | ||
| 393 | + return ret; | ||
| 394 | + } | ||
| 395 | + if ((ret = source->on_video(msg)) != ERROR_SUCCESS) { | ||
| 396 | + srs_error("source process video message failed. ret=%d", ret); | ||
| 397 | + return ret; | ||
| 398 | + } | ||
| 377 | } | 399 | } |
| 378 | 400 | ||
| 379 | // process onMetaData | 401 | // process onMetaData |
| @@ -386,8 +408,12 @@ int SrsClient::process_publish_message(SrsSource* source, SrsHLS* hls, SrsCommon | @@ -386,8 +408,12 @@ int SrsClient::process_publish_message(SrsSource* source, SrsHLS* hls, SrsCommon | ||
| 386 | SrsPacket* pkt = msg->get_packet(); | 408 | SrsPacket* pkt = msg->get_packet(); |
| 387 | if (dynamic_cast<SrsOnMetaDataPacket*>(pkt)) { | 409 | if (dynamic_cast<SrsOnMetaDataPacket*>(pkt)) { |
| 388 | SrsOnMetaDataPacket* metadata = dynamic_cast<SrsOnMetaDataPacket*>(pkt); | 410 | SrsOnMetaDataPacket* metadata = dynamic_cast<SrsOnMetaDataPacket*>(pkt); |
| 411 | + if ((ret = hls->on_meta_data(metadata)) != ERROR_SUCCESS) { | ||
| 412 | + srs_error("hls process onMetaData message failed. ret=%d", ret); | ||
| 413 | + return ret; | ||
| 414 | + } | ||
| 389 | if ((ret = source->on_meta_data(msg, metadata)) != ERROR_SUCCESS) { | 415 | if ((ret = source->on_meta_data(msg, metadata)) != ERROR_SUCCESS) { |
| 390 | - srs_error("process onMetaData message failed. ret=%d", ret); | 416 | + srs_error("source process onMetaData message failed. ret=%d", ret); |
| 391 | return ret; | 417 | return ret; |
| 392 | } | 418 | } |
| 393 | srs_trace("process onMetaData message success."); | 419 | srs_trace("process onMetaData message success."); |
| @@ -23,32 +23,84 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -23,32 +23,84 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | 23 | ||
| 24 | #include <srs_core_codec.hpp> | 24 | #include <srs_core_codec.hpp> |
| 25 | 25 | ||
| 26 | +#include <srs_core_error.hpp> | ||
| 27 | +#include <srs_core_stream.hpp> | ||
| 28 | + | ||
| 26 | SrsCodec::SrsCodec() | 29 | SrsCodec::SrsCodec() |
| 27 | { | 30 | { |
| 31 | + width = 0; | ||
| 32 | + height = 0; | ||
| 33 | + duration = 0; | ||
| 34 | + frame_rate = 0; | ||
| 35 | + video_data_rate = 0; | ||
| 36 | + video_codec_id = 0; | ||
| 37 | + audio_data_rate = 0; | ||
| 38 | + audio_codec_id = 0; | ||
| 39 | + aac_sample_rate = 0; | ||
| 40 | + sample_rate = 0; | ||
| 41 | + sample_size = 0; | ||
| 42 | + audio_channels = 0; | ||
| 43 | + profile = 0; | ||
| 44 | + level = 0; | ||
| 45 | + avc_extra_size = 0; | ||
| 46 | + avc_extra_data = NULL; | ||
| 47 | + aac_extra_size = 0; | ||
| 48 | + aac_extra_data = NULL; | ||
| 49 | + | ||
| 50 | + stream = new SrsStream(); | ||
| 28 | } | 51 | } |
| 29 | 52 | ||
| 30 | SrsCodec::~SrsCodec() | 53 | SrsCodec::~SrsCodec() |
| 31 | { | 54 | { |
| 55 | + srs_freepa(avc_extra_data); | ||
| 56 | + srs_freepa(aac_extra_data); | ||
| 57 | + | ||
| 58 | + srs_freep(stream); | ||
| 32 | } | 59 | } |
| 33 | 60 | ||
| 34 | -bool SrsCodec::video_is_keyframe(int8_t* data, int size) | 61 | +int SrsCodec::parse_av_codec(bool is_video, int8_t* data, int size) |
| 35 | { | 62 | { |
| 36 | - // E.4.3.1 VIDEODATA | ||
| 37 | - // Frame Type UB [4] | ||
| 38 | - // Type of video frame. The following values are defined: | ||
| 39 | - // 1 = key frame (for AVC, a seekable frame) | ||
| 40 | - // 2 = inter frame (for AVC, a non-seekable frame) | ||
| 41 | - // 3 = disposable inter frame (H.263 only) | ||
| 42 | - // 4 = generated key frame (reserved for server use only) | ||
| 43 | - // 5 = video info/command frame | ||
| 44 | - // | ||
| 45 | - // AVCPacketType IF CodecID == 7 UI8 | ||
| 46 | - // The following values are defined: | ||
| 47 | - // 0 = AVC sequence header | ||
| 48 | - // 1 = AVC NALU | ||
| 49 | - // 2 = AVC end of sequence (lower level NALU sequence ender is | ||
| 50 | - // not required or supported) | 63 | + int ret = ERROR_SUCCESS; |
| 64 | + | ||
| 65 | + if (!data || size <= 0) { | ||
| 66 | + return ret; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + if ((ret = stream->initialize((char*)data, size)) != ERROR_SUCCESS) { | ||
| 70 | + return ret; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + if (is_video) { | ||
| 74 | + if (!stream->require(1)) { | ||
| 75 | + return ret; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + int8_t frame_type = stream->read_1bytes(); | ||
| 79 | + int8_t codec_id = frame_type & 0x0f; | ||
| 80 | + frame_type = (frame_type >> 4) & 0x0f; | ||
| 81 | + | ||
| 82 | + video_codec_id = codec_id; | ||
| 83 | + if (codec_id != SrsCodecVideoAVC) { | ||
| 84 | + return ret; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + if (!stream->require(4)) { | ||
| 88 | + return ret; | ||
| 89 | + } | ||
| 90 | + int8_t avc_packet_type = stream->read_1bytes(); | ||
| 91 | + int32_t composition_time = stream->read_3bytes(); | ||
| 92 | + | ||
| 93 | + // 5.2.4.1.1 Syntax | ||
| 94 | + if (avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { | ||
| 95 | + } | ||
| 96 | + } else { | ||
| 97 | + } | ||
| 51 | 98 | ||
| 99 | + return ret; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +bool SrsCodec::video_is_keyframe(int8_t* data, int size) | ||
| 103 | +{ | ||
| 52 | // 2bytes required. | 104 | // 2bytes required. |
| 53 | if (size < 1) { | 105 | if (size < 1) { |
| 54 | return false; | 106 | return false; |
| @@ -57,27 +109,11 @@ bool SrsCodec::video_is_keyframe(int8_t* data, int size) | @@ -57,27 +109,11 @@ bool SrsCodec::video_is_keyframe(int8_t* data, int size) | ||
| 57 | char frame_type = *(char*)data; | 109 | char frame_type = *(char*)data; |
| 58 | frame_type = (frame_type >> 4) & 0x0F; | 110 | frame_type = (frame_type >> 4) & 0x0F; |
| 59 | 111 | ||
| 60 | - return frame_type == 1; | 112 | + return frame_type == SrsCodecVideoAVCFrameKeyFrame; |
| 61 | } | 113 | } |
| 62 | 114 | ||
| 63 | bool SrsCodec::video_is_sequence_header(int8_t* data, int size) | 115 | bool SrsCodec::video_is_sequence_header(int8_t* data, int size) |
| 64 | { | 116 | { |
| 65 | - // E.4.3.1 VIDEODATA | ||
| 66 | - // Frame Type UB [4] | ||
| 67 | - // Type of video frame. The following values are defined: | ||
| 68 | - // 1 = key frame (for AVC, a seekable frame) | ||
| 69 | - // 2 = inter frame (for AVC, a non-seekable frame) | ||
| 70 | - // 3 = disposable inter frame (H.263 only) | ||
| 71 | - // 4 = generated key frame (reserved for server use only) | ||
| 72 | - // 5 = video info/command frame | ||
| 73 | - // | ||
| 74 | - // AVCPacketType IF CodecID == 7 UI8 | ||
| 75 | - // The following values are defined: | ||
| 76 | - // 0 = AVC sequence header | ||
| 77 | - // 1 = AVC NALU | ||
| 78 | - // 2 = AVC end of sequence (lower level NALU sequence ender is | ||
| 79 | - // not required or supported) | ||
| 80 | - | ||
| 81 | // sequence header only for h264 | 117 | // sequence header only for h264 |
| 82 | if (!video_is_h264(data, size)) { | 118 | if (!video_is_h264(data, size)) { |
| 83 | return false; | 119 | return false; |
| @@ -93,16 +129,12 @@ bool SrsCodec::video_is_sequence_header(int8_t* data, int size) | @@ -93,16 +129,12 @@ bool SrsCodec::video_is_sequence_header(int8_t* data, int size) | ||
| 93 | 129 | ||
| 94 | char avc_packet_type = *(char*)(data + 1); | 130 | char avc_packet_type = *(char*)(data + 1); |
| 95 | 131 | ||
| 96 | - return frame_type == 1 && avc_packet_type == 0; | 132 | + return frame_type == SrsCodecVideoAVCFrameKeyFrame |
| 133 | + && avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader; | ||
| 97 | } | 134 | } |
| 98 | 135 | ||
| 99 | bool SrsCodec::audio_is_sequence_header(int8_t* data, int size) | 136 | bool SrsCodec::audio_is_sequence_header(int8_t* data, int size) |
| 100 | { | 137 | { |
| 101 | - // AACPacketType IF SoundFormat == 10 UI8 | ||
| 102 | - // The following values are defined: | ||
| 103 | - // 0 = AAC sequence header | ||
| 104 | - // 1 = AAC raw | ||
| 105 | - | ||
| 106 | // sequence header only for aac | 138 | // sequence header only for aac |
| 107 | if (!audio_is_aac(data, size)) { | 139 | if (!audio_is_aac(data, size)) { |
| 108 | return false; | 140 | return false; |
| @@ -115,21 +147,11 @@ bool SrsCodec::audio_is_sequence_header(int8_t* data, int size) | @@ -115,21 +147,11 @@ bool SrsCodec::audio_is_sequence_header(int8_t* data, int size) | ||
| 115 | 147 | ||
| 116 | char aac_packet_type = *(char*)(data + 1); | 148 | char aac_packet_type = *(char*)(data + 1); |
| 117 | 149 | ||
| 118 | - return aac_packet_type == 0; | 150 | + return aac_packet_type == SrsCodecAudioTypeSequenceHeader; |
| 119 | } | 151 | } |
| 120 | 152 | ||
| 121 | bool SrsCodec::video_is_h264(int8_t* data, int size) | 153 | bool SrsCodec::video_is_h264(int8_t* data, int size) |
| 122 | { | 154 | { |
| 123 | - // E.4.3.1 VIDEODATA | ||
| 124 | - // CodecID UB [4] | ||
| 125 | - // Codec Identifier. The following values are defined: | ||
| 126 | - // 2 = Sorenson H.263 | ||
| 127 | - // 3 = Screen video | ||
| 128 | - // 4 = On2 VP6 | ||
| 129 | - // 5 = On2 VP6 with alpha channel | ||
| 130 | - // 6 = Screen video version 2 | ||
| 131 | - // 7 = AVC | ||
| 132 | - | ||
| 133 | // 1bytes required. | 155 | // 1bytes required. |
| 134 | if (size < 1) { | 156 | if (size < 1) { |
| 135 | return false; | 157 | return false; |
| @@ -138,31 +160,11 @@ bool SrsCodec::video_is_h264(int8_t* data, int size) | @@ -138,31 +160,11 @@ bool SrsCodec::video_is_h264(int8_t* data, int size) | ||
| 138 | char codec_id = *(char*)data; | 160 | char codec_id = *(char*)data; |
| 139 | codec_id = codec_id & 0x0F; | 161 | codec_id = codec_id & 0x0F; |
| 140 | 162 | ||
| 141 | - return codec_id == 7; | 163 | + return codec_id == SrsCodecVideoAVC; |
| 142 | } | 164 | } |
| 143 | 165 | ||
| 144 | bool SrsCodec::audio_is_aac(int8_t* data, int size) | 166 | bool SrsCodec::audio_is_aac(int8_t* data, int size) |
| 145 | { | 167 | { |
| 146 | - // SoundFormat UB [4] | ||
| 147 | - // Format of SoundData. The following values are defined: | ||
| 148 | - // 0 = Linear PCM, platform endian | ||
| 149 | - // 1 = ADPCM | ||
| 150 | - // 2 = MP3 | ||
| 151 | - // 3 = Linear PCM, little endian | ||
| 152 | - // 4 = Nellymoser 16 kHz mono | ||
| 153 | - // 5 = Nellymoser 8 kHz mono | ||
| 154 | - // 6 = Nellymoser | ||
| 155 | - // 7 = G.711 A-law logarithmic PCM | ||
| 156 | - // 8 = G.711 mu-law logarithmic PCM | ||
| 157 | - // 9 = reserved | ||
| 158 | - // 10 = AAC | ||
| 159 | - // 11 = Speex | ||
| 160 | - // 14 = MP3 8 kHz | ||
| 161 | - // 15 = Device-specific sound | ||
| 162 | - // Formats 7, 8, 14, and 15 are reserved. | ||
| 163 | - // AAC is supported in Flash Player 9,0,115,0 and higher. | ||
| 164 | - // Speex is supported in Flash Player 10 and higher. | ||
| 165 | - | ||
| 166 | // 1bytes required. | 168 | // 1bytes required. |
| 167 | if (size < 1) { | 169 | if (size < 1) { |
| 168 | return false; | 170 | return false; |
| @@ -171,5 +173,5 @@ bool SrsCodec::audio_is_aac(int8_t* data, int size) | @@ -171,5 +173,5 @@ bool SrsCodec::audio_is_aac(int8_t* data, int size) | ||
| 171 | char sound_format = *(char*)data; | 173 | char sound_format = *(char*)data; |
| 172 | sound_format = (sound_format >> 4) & 0x0F; | 174 | sound_format = (sound_format >> 4) & 0x0F; |
| 173 | 175 | ||
| 174 | - return sound_format == 10; | 176 | + return sound_format == SrsCodecAudioAAC; |
| 175 | } | 177 | } |
| @@ -30,36 +30,170 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -30,36 +30,170 @@ 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 | +class SrsStream; | ||
| 34 | + | ||
| 35 | +// E.4.3.1 VIDEODATA | ||
| 36 | +// CodecID UB [4] | ||
| 37 | +// Codec Identifier. The following values are defined: | ||
| 38 | +// 2 = Sorenson H.263 | ||
| 39 | +// 3 = Screen video | ||
| 40 | +// 4 = On2 VP6 | ||
| 41 | +// 5 = On2 VP6 with alpha channel | ||
| 42 | +// 6 = Screen video version 2 | ||
| 43 | +// 7 = AVC | ||
| 44 | +enum SrsCodecVideo | ||
| 45 | +{ | ||
| 46 | + SrsCodecVideoSorensonH263 = 2, | ||
| 47 | + SrsCodecVideoScreenVideo = 3, | ||
| 48 | + SrsCodecVideoOn2VP6 = 4, | ||
| 49 | + SrsCodecVideoOn2VP6WithAlphaChannel = 5, | ||
| 50 | + SrsCodecVideoScreenVideoVersion2 = 6, | ||
| 51 | + SrsCodecVideoAVC = 7, | ||
| 52 | +}; | ||
| 53 | + | ||
| 54 | +// E.4.3.1 VIDEODATA | ||
| 55 | +// Frame Type UB [4] | ||
| 56 | +// Type of video frame. The following values are defined: | ||
| 57 | +// 1 = key frame (for AVC, a seekable frame) | ||
| 58 | +// 2 = inter frame (for AVC, a non-seekable frame) | ||
| 59 | +// 3 = disposable inter frame (H.263 only) | ||
| 60 | +// 4 = generated key frame (reserved for server use only) | ||
| 61 | +// 5 = video info/command frame | ||
| 62 | +enum SrsCodecVideoAVCFrame | ||
| 63 | +{ | ||
| 64 | + SrsCodecVideoAVCFrameKeyFrame = 1, | ||
| 65 | + SrsCodecVideoAVCFrameInterFrame = 2, | ||
| 66 | + SrsCodecVideoAVCFrameDisposableInterFrame = 3, | ||
| 67 | + SrsCodecVideoAVCFrameGeneratedKeyFrame = 4, | ||
| 68 | + SrsCodecVideoAVCFrameVideoInfoFrame = 5, | ||
| 69 | +}; | ||
| 70 | + | ||
| 71 | +// AVCPacketType IF CodecID == 7 UI8 | ||
| 72 | +// The following values are defined: | ||
| 73 | +// 0 = AVC sequence header | ||
| 74 | +// 1 = AVC NALU | ||
| 75 | +// 2 = AVC end of sequence (lower level NALU sequence ender is | ||
| 76 | +// not required or supported) | ||
| 77 | +enum SrsCodecVideoAVCType | ||
| 78 | +{ | ||
| 79 | + SrsCodecVideoAVCTypeSequenceHeader = 0, | ||
| 80 | + SrsCodecVideoAVCTypeNALU = 1, | ||
| 81 | + SrsCodecVideoAVCTypeSequenceHeaderEOF = 2, | ||
| 82 | +}; | ||
| 83 | + | ||
| 84 | +// SoundFormat UB [4] | ||
| 85 | +// Format of SoundData. The following values are defined: | ||
| 86 | +// 0 = Linear PCM, platform endian | ||
| 87 | +// 1 = ADPCM | ||
| 88 | +// 2 = MP3 | ||
| 89 | +// 3 = Linear PCM, little endian | ||
| 90 | +// 4 = Nellymoser 16 kHz mono | ||
| 91 | +// 5 = Nellymoser 8 kHz mono | ||
| 92 | +// 6 = Nellymoser | ||
| 93 | +// 7 = G.711 A-law logarithmic PCM | ||
| 94 | +// 8 = G.711 mu-law logarithmic PCM | ||
| 95 | +// 9 = reserved | ||
| 96 | +// 10 = AAC | ||
| 97 | +// 11 = Speex | ||
| 98 | +// 14 = MP3 8 kHz | ||
| 99 | +// 15 = Device-specific sound | ||
| 100 | +// Formats 7, 8, 14, and 15 are reserved. | ||
| 101 | +// AAC is supported in Flash Player 9,0,115,0 and higher. | ||
| 102 | +// Speex is supported in Flash Player 10 and higher. | ||
| 103 | +enum SrsCodecAudio | ||
| 104 | +{ | ||
| 105 | + SrsCodecAudioLinearPCMPlatformEndian = 0, | ||
| 106 | + SrsCodecAudioADPCM = 1, | ||
| 107 | + SrsCodecAudioMP3 = 2, | ||
| 108 | + SrsCodecAudioLinearPCMLittleEndian = 3, | ||
| 109 | + SrsCodecAudioNellymoser16kHzMono = 4, | ||
| 110 | + SrsCodecAudioNellymoser8kHzMono = 5, | ||
| 111 | + SrsCodecAudioNellymoser = 6, | ||
| 112 | + SrsCodecAudioReservedG711AlawLogarithmicPCM = 7, | ||
| 113 | + SrsCodecAudioReservedG711MuLawLogarithmicPCM = 8, | ||
| 114 | + SrsCodecAudioReserved = 9, | ||
| 115 | + SrsCodecAudioAAC = 10, | ||
| 116 | + SrsCodecAudioSpeex = 11, | ||
| 117 | + SrsCodecAudioReservedMP3_8kHz = 14, | ||
| 118 | + SrsCodecAudioReservedDeviceSpecificSound = 15, | ||
| 119 | +}; | ||
| 120 | + | ||
| 121 | +// AACPacketType IF SoundFormat == 10 UI8 | ||
| 122 | +// The following values are defined: | ||
| 123 | +// 0 = AAC sequence header | ||
| 124 | +// 1 = AAC raw | ||
| 125 | +enum SrsCodecAudioType | ||
| 126 | +{ | ||
| 127 | + SrsCodecAudioTypeSequenceHeader = 0, | ||
| 128 | + SrsCodecAudioTypeRawData = 1, | ||
| 129 | +}; | ||
| 130 | + | ||
| 33 | /** | 131 | /** |
| 34 | * Annex E. The FLV File Format | 132 | * Annex E. The FLV File Format |
| 35 | */ | 133 | */ |
| 36 | class SrsCodec | 134 | class SrsCodec |
| 37 | { | 135 | { |
| 136 | +private: | ||
| 137 | + SrsStream* stream; | ||
| 138 | +public: | ||
| 139 | + /** | ||
| 140 | + * video specified | ||
| 141 | + */ | ||
| 142 | + int width; | ||
| 143 | + int height; | ||
| 144 | + int duration; | ||
| 145 | + int frame_rate; | ||
| 146 | + // @see: SrsCodecVideo | ||
| 147 | + int video_codec_id; | ||
| 148 | + int video_data_rate; // in bps | ||
| 149 | + u_int8_t profile; // profile_idc, page 45. | ||
| 150 | + u_int8_t level; // level_idc, page 45. | ||
| 151 | + /** | ||
| 152 | + * audio specified | ||
| 153 | + */ | ||
| 154 | + int audio_codec_id; | ||
| 155 | + int audio_data_rate; // in bps | ||
| 156 | + int aac_sample_rate; | ||
| 157 | + int sample_rate; /* 5512, 11025, 22050, 44100 */ | ||
| 158 | + int sample_size; /* 1=8bit, 2=16bit */ | ||
| 159 | + int audio_channels; /* 1, 2 */ | ||
| 160 | + // the avc extra data, the AVC sequence header, | ||
| 161 | + // without the flv codec header | ||
| 162 | + int avc_extra_size; | ||
| 163 | + char* avc_extra_data; | ||
| 164 | + // the aac extra data, the AAC sequence header, | ||
| 165 | + // without the flv codec header | ||
| 166 | + int aac_extra_size; | ||
| 167 | + char* aac_extra_data; | ||
| 38 | public: | 168 | public: |
| 39 | SrsCodec(); | 169 | SrsCodec(); |
| 40 | virtual ~SrsCodec(); | 170 | virtual ~SrsCodec(); |
| 171 | +// the following function used for hls to build the codec info. | ||
| 172 | +public: | ||
| 173 | + virtual int parse_av_codec(bool is_video, int8_t* data, int size); | ||
| 174 | +// the following function used to finger out the flv/rtmp packet detail. | ||
| 41 | public: | 175 | public: |
| 42 | /** | 176 | /** |
| 43 | * only check the frame_type, not check the codec type. | 177 | * only check the frame_type, not check the codec type. |
| 44 | */ | 178 | */ |
| 45 | - virtual bool video_is_keyframe(int8_t* data, int size); | 179 | + static bool video_is_keyframe(int8_t* data, int size); |
| 46 | /** | 180 | /** |
| 47 | * check codec h264, keyframe, sequence header | 181 | * check codec h264, keyframe, sequence header |
| 48 | */ | 182 | */ |
| 49 | - virtual bool video_is_sequence_header(int8_t* data, int size); | 183 | + static bool video_is_sequence_header(int8_t* data, int size); |
| 50 | /** | 184 | /** |
| 51 | * check codec aac, sequence header | 185 | * check codec aac, sequence header |
| 52 | */ | 186 | */ |
| 53 | - virtual bool audio_is_sequence_header(int8_t* data, int size); | 187 | + static bool audio_is_sequence_header(int8_t* data, int size); |
| 54 | /** | 188 | /** |
| 55 | * check codec h264. | 189 | * check codec h264. |
| 56 | */ | 190 | */ |
| 57 | - virtual bool video_is_h264(int8_t* data, int size); | 191 | + static bool video_is_h264(int8_t* data, int size); |
| 58 | private: | 192 | private: |
| 59 | /** | 193 | /** |
| 60 | * check codec aac. | 194 | * check codec aac. |
| 61 | */ | 195 | */ |
| 62 | - virtual bool audio_is_aac(int8_t* data, int size); | 196 | + static bool audio_is_aac(int8_t* data, int size); |
| 63 | }; | 197 | }; |
| 64 | 198 | ||
| 65 | #endif | 199 | #endif |
| @@ -23,11 +23,117 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -23,11 +23,117 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | 23 | ||
| 24 | #include <srs_core_hls.hpp> | 24 | #include <srs_core_hls.hpp> |
| 25 | 25 | ||
| 26 | +#include <srs_core_error.hpp> | ||
| 27 | +#include <srs_core_codec.hpp> | ||
| 28 | +#include <srs_core_amf0.hpp> | ||
| 29 | +#include <srs_core_protocol.hpp> | ||
| 30 | + | ||
| 26 | SrsHLS::SrsHLS() | 31 | SrsHLS::SrsHLS() |
| 27 | { | 32 | { |
| 33 | + codec = new SrsCodec(); | ||
| 28 | } | 34 | } |
| 29 | 35 | ||
| 30 | SrsHLS::~SrsHLS() | 36 | SrsHLS::~SrsHLS() |
| 31 | { | 37 | { |
| 38 | + srs_freep(codec); | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +int SrsHLS::on_publish() | ||
| 42 | +{ | ||
| 43 | + int ret = ERROR_SUCCESS; | ||
| 44 | + return ret; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +void SrsHLS::on_unpublish() | ||
| 48 | +{ | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata) | ||
| 52 | +{ | ||
| 53 | + int ret = ERROR_SUCCESS; | ||
| 54 | + | ||
| 55 | + if (!metadata || !metadata->metadata) { | ||
| 56 | + return ret; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + SrsAmf0Object* obj = metadata->metadata; | ||
| 60 | + if (obj->size() <= 0) { | ||
| 61 | + return ret; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + // finger out the codec info from metadata if possible. | ||
| 65 | + SrsAmf0Any* prop = NULL; | ||
| 66 | + | ||
| 67 | + if ((prop = obj->get_property("duration")) != NULL && prop->is_number()) { | ||
| 68 | + codec->duration = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 69 | + } | ||
| 70 | + if ((prop = obj->get_property("width")) != NULL && prop->is_number()) { | ||
| 71 | + codec->width = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 72 | + } | ||
| 73 | + if ((prop = obj->get_property("height")) != NULL && prop->is_number()) { | ||
| 74 | + codec->height = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 75 | + } | ||
| 76 | + if ((prop = obj->get_property("framerate")) != NULL && prop->is_number()) { | ||
| 77 | + codec->frame_rate = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 78 | + } | ||
| 79 | + if ((prop = obj->get_property("videocodecid")) != NULL && prop->is_number()) { | ||
| 80 | + codec->video_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 81 | + } | ||
| 82 | + if ((prop = obj->get_property("videodatarate")) != NULL && prop->is_number()) { | ||
| 83 | + codec->video_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + if ((prop = obj->get_property("audiocodecid")) != NULL && prop->is_number()) { | ||
| 87 | + codec->audio_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 88 | + } | ||
| 89 | + if ((prop = obj->get_property("audiodatarate")) != NULL && prop->is_number()) { | ||
| 90 | + codec->audio_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value); | ||
| 91 | + } | ||
| 92 | + if ((prop = obj->get_property("audiosamplerate")) != NULL && prop->is_number()) { | ||
| 93 | + codec->sample_rate = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 94 | + } | ||
| 95 | + if ((prop = obj->get_property("audiosamplesize")) != NULL && prop->is_number()) { | ||
| 96 | + codec->sample_size = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value; | ||
| 97 | + if (codec->sample_size == 16) { | ||
| 98 | + codec->sample_size = 2; | ||
| 99 | + } else { | ||
| 100 | + codec->sample_size = 1; | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + if ((prop = obj->get_property("stereo")) != NULL && prop->is_number()) { | ||
| 104 | + if (srs_amf0_convert<SrsAmf0Boolean>(prop)->value) { | ||
| 105 | + codec->audio_channels = 2; | ||
| 106 | + } else { | ||
| 107 | + codec->audio_channels = 1; | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + return ret; | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +int SrsHLS::on_audio(SrsCommonMessage* audio) | ||
| 115 | +{ | ||
| 116 | + int ret = ERROR_SUCCESS; | ||
| 117 | + | ||
| 118 | + if ((ret = codec->parse_av_codec(false, audio->payload, audio->size)) != ERROR_SUCCESS) { | ||
| 119 | + return ret; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + return ret; | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +int SrsHLS::on_video(SrsCommonMessage* video) | ||
| 126 | +{ | ||
| 127 | + int ret = ERROR_SUCCESS; | ||
| 128 | + | ||
| 129 | + if ((ret = codec->parse_av_codec(true, video->payload, video->size)) != ERROR_SUCCESS) { | ||
| 130 | + return ret; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + if (codec->video_codec_id != SrsCodecVideoAVC) { | ||
| 134 | + return ret; | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + return ret; | ||
| 32 | } | 138 | } |
| 33 | 139 |
| @@ -29,11 +29,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -29,11 +29,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 29 | */ | 29 | */ |
| 30 | #include <srs_core.hpp> | 30 | #include <srs_core.hpp> |
| 31 | 31 | ||
| 32 | +class SrsOnMetaDataPacket; | ||
| 33 | +class SrsCommonMessage; | ||
| 34 | +class SrsCodec; | ||
| 35 | + | ||
| 32 | class SrsHLS | 36 | class SrsHLS |
| 33 | { | 37 | { |
| 38 | +private: | ||
| 39 | + SrsCodec* codec; | ||
| 34 | public: | 40 | public: |
| 35 | SrsHLS(); | 41 | SrsHLS(); |
| 36 | virtual ~SrsHLS(); | 42 | virtual ~SrsHLS(); |
| 43 | +public: | ||
| 44 | + virtual int on_publish(); | ||
| 45 | + virtual void on_unpublish(); | ||
| 46 | + virtual int on_meta_data(SrsOnMetaDataPacket* metadata); | ||
| 47 | + virtual int on_audio(SrsCommonMessage* audio); | ||
| 48 | + virtual int on_video(SrsCommonMessage* video); | ||
| 37 | }; | 49 | }; |
| 38 | 50 | ||
| 39 | #endif | 51 | #endif |
| @@ -53,13 +53,11 @@ SrsConsumer::SrsConsumer(SrsSource* _source) | @@ -53,13 +53,11 @@ SrsConsumer::SrsConsumer(SrsSource* _source) | ||
| 53 | source = _source; | 53 | source = _source; |
| 54 | last_pkt_correct_time = last_pkt_time = 0; | 54 | last_pkt_correct_time = last_pkt_time = 0; |
| 55 | paused = false; | 55 | paused = false; |
| 56 | - codec = new SrsCodec(); | ||
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | SrsConsumer::~SrsConsumer() | 58 | SrsConsumer::~SrsConsumer() |
| 60 | { | 59 | { |
| 61 | - clear(); | ||
| 62 | - srs_freep(codec); | 60 | + clear(); |
| 63 | 61 | ||
| 64 | source->on_consumer_destroy(this); | 62 | source->on_consumer_destroy(this); |
| 65 | } | 63 | } |
| @@ -141,7 +139,7 @@ void SrsConsumer::shrink() | @@ -141,7 +139,7 @@ void SrsConsumer::shrink() | ||
| 141 | SrsSharedPtrMessage* msg = *it; | 139 | SrsSharedPtrMessage* msg = *it; |
| 142 | if (msg->header.is_video()) { | 140 | if (msg->header.is_video()) { |
| 143 | has_video = true; | 141 | has_video = true; |
| 144 | - if (codec->video_is_keyframe(msg->payload, msg->size)) { | 142 | + if (SrsCodec::video_is_keyframe(msg->payload, msg->size)) { |
| 145 | iframe = it; | 143 | iframe = it; |
| 146 | frame_to_remove = i + 1; | 144 | frame_to_remove = i + 1; |
| 147 | } | 145 | } |
| @@ -240,7 +238,6 @@ void SrsConsumer::clear() | @@ -240,7 +238,6 @@ void SrsConsumer::clear() | ||
| 240 | SrsSource::SrsSource(std::string _stream_url) | 238 | SrsSource::SrsSource(std::string _stream_url) |
| 241 | { | 239 | { |
| 242 | stream_url = _stream_url; | 240 | stream_url = _stream_url; |
| 243 | - codec = new SrsCodec(); | ||
| 244 | hls = new SrsHLS(); | 241 | hls = new SrsHLS(); |
| 245 | 242 | ||
| 246 | cache_metadata = cache_sh_video = cache_sh_audio = NULL; | 243 | cache_metadata = cache_sh_video = cache_sh_audio = NULL; |
| @@ -266,7 +263,6 @@ SrsSource::~SrsSource() | @@ -266,7 +263,6 @@ SrsSource::~SrsSource() | ||
| 266 | srs_freep(cache_sh_video); | 263 | srs_freep(cache_sh_video); |
| 267 | srs_freep(cache_sh_audio); | 264 | srs_freep(cache_sh_audio); |
| 268 | 265 | ||
| 269 | - srs_freep(codec); | ||
| 270 | srs_freep(hls); | 266 | srs_freep(hls); |
| 271 | } | 267 | } |
| 272 | 268 | ||
| @@ -364,7 +360,7 @@ int SrsSource::on_audio(SrsCommonMessage* audio) | @@ -364,7 +360,7 @@ int SrsSource::on_audio(SrsCommonMessage* audio) | ||
| 364 | srs_info("dispatch audio success."); | 360 | srs_info("dispatch audio success."); |
| 365 | 361 | ||
| 366 | // cache the sequence header if h264 | 362 | // cache the sequence header if h264 |
| 367 | - if (codec->audio_is_sequence_header(msg->payload, msg->size)) { | 363 | + if (SrsCodec::audio_is_sequence_header(msg->payload, msg->size)) { |
| 368 | srs_freep(cache_sh_audio); | 364 | srs_freep(cache_sh_audio); |
| 369 | cache_sh_audio = msg->copy(); | 365 | cache_sh_audio = msg->copy(); |
| 370 | srs_trace("update audio sequence header success. size=%d", msg->header.payload_length); | 366 | srs_trace("update audio sequence header success. size=%d", msg->header.payload_length); |
| @@ -409,7 +405,7 @@ int SrsSource::on_video(SrsCommonMessage* video) | @@ -409,7 +405,7 @@ int SrsSource::on_video(SrsCommonMessage* video) | ||
| 409 | srs_info("dispatch video success."); | 405 | srs_info("dispatch video success."); |
| 410 | 406 | ||
| 411 | // cache the sequence header if h264 | 407 | // cache the sequence header if h264 |
| 412 | - if (codec->video_is_sequence_header(msg->payload, msg->size)) { | 408 | + if (SrsCodec::video_is_sequence_header(msg->payload, msg->size)) { |
| 413 | srs_freep(cache_sh_video); | 409 | srs_freep(cache_sh_video); |
| 414 | cache_sh_video = msg->copy(); | 410 | cache_sh_video = msg->copy(); |
| 415 | srs_trace("update video sequence header success. size=%d", msg->header.payload_length); | 411 | srs_trace("update video sequence header success. size=%d", msg->header.payload_length); |
| @@ -521,7 +517,7 @@ int SrsSource::cache_last_gop(SrsSharedPtrMessage* msg) | @@ -521,7 +517,7 @@ int SrsSource::cache_last_gop(SrsSharedPtrMessage* msg) | ||
| 521 | } | 517 | } |
| 522 | 518 | ||
| 523 | // clear gop cache when got key frame | 519 | // clear gop cache when got key frame |
| 524 | - if (msg->header.is_video() && codec->video_is_keyframe(msg->payload, msg->size)) { | 520 | + if (msg->header.is_video() && SrsCodec::video_is_keyframe(msg->payload, msg->size)) { |
| 525 | srs_info("clear gop cache when got keyframe. vcount=%d, count=%d", | 521 | srs_info("clear gop cache when got keyframe. vcount=%d, count=%d", |
| 526 | cached_video_count, (int)gop_cache.size()); | 522 | cached_video_count, (int)gop_cache.size()); |
| 527 | 523 |
| @@ -34,7 +34,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -34,7 +34,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 34 | #include <vector> | 34 | #include <vector> |
| 35 | #include <string> | 35 | #include <string> |
| 36 | 36 | ||
| 37 | -class SrsCodec; | ||
| 38 | class SrsSource; | 37 | class SrsSource; |
| 39 | class SrsCommonMessage; | 38 | class SrsCommonMessage; |
| 40 | class SrsOnMetaDataPacket; | 39 | class SrsOnMetaDataPacket; |
| @@ -52,7 +51,6 @@ private: | @@ -52,7 +51,6 @@ private: | ||
| 52 | SrsSource* source; | 51 | SrsSource* source; |
| 53 | std::vector<SrsSharedPtrMessage*> msgs; | 52 | std::vector<SrsSharedPtrMessage*> msgs; |
| 54 | bool paused; | 53 | bool paused; |
| 55 | - SrsCodec* codec; | ||
| 56 | public: | 54 | public: |
| 57 | SrsConsumer(SrsSource* _source); | 55 | SrsConsumer(SrsSource* _source); |
| 58 | virtual ~SrsConsumer(); | 56 | virtual ~SrsConsumer(); |
| @@ -108,7 +106,6 @@ public: | @@ -108,7 +106,6 @@ public: | ||
| 108 | static SrsSource* find(std::string stream_url); | 106 | static SrsSource* find(std::string stream_url); |
| 109 | private: | 107 | private: |
| 110 | SrsHLS* hls; | 108 | SrsHLS* hls; |
| 111 | - SrsCodec* codec; | ||
| 112 | std::string stream_url; | 109 | std::string stream_url; |
| 113 | std::vector<SrsConsumer*> consumers; | 110 | std::vector<SrsConsumer*> consumers; |
| 114 | // gop cache for client fast startup. | 111 | // gop cache for client fast startup. |
| @@ -106,6 +106,19 @@ int16_t SrsStream::read_2bytes() | @@ -106,6 +106,19 @@ int16_t SrsStream::read_2bytes() | ||
| 106 | return value; | 106 | return value; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | +int32_t SrsStream::read_3bytes() | ||
| 110 | +{ | ||
| 111 | + srs_assert(require(3)); | ||
| 112 | + | ||
| 113 | + int32_t value = 0x00; | ||
| 114 | + pp = (char*)&value; | ||
| 115 | + pp[2] = *p++; | ||
| 116 | + pp[1] = *p++; | ||
| 117 | + pp[0] = *p++; | ||
| 118 | + | ||
| 119 | + return value; | ||
| 120 | +} | ||
| 121 | + | ||
| 109 | int32_t SrsStream::read_4bytes() | 122 | int32_t SrsStream::read_4bytes() |
| 110 | { | 123 | { |
| 111 | srs_assert(require(4)); | 124 | srs_assert(require(4)); |
| @@ -84,6 +84,10 @@ public: | @@ -84,6 +84,10 @@ public: | ||
| 84 | */ | 84 | */ |
| 85 | virtual int16_t read_2bytes(); | 85 | virtual int16_t read_2bytes(); |
| 86 | /** | 86 | /** |
| 87 | + * get 3bytes int from stream. | ||
| 88 | + */ | ||
| 89 | + virtual int32_t read_3bytes(); | ||
| 90 | + /** | ||
| 87 | * get 4bytes int from stream. | 91 | * get 4bytes int from stream. |
| 88 | */ | 92 | */ |
| 89 | virtual int32_t read_4bytes(); | 93 | virtual int32_t read_4bytes(); |
-
请 注册 或 登录 后发表评论