diff --git a/trunk/configure b/trunk/configure index c80250245..df8d863d7 100755 --- a/trunk/configure +++ b/trunk/configure @@ -167,7 +167,7 @@ ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack" "srs_rtmp_handshake" "srs_protocol_utility" "srs_rtmp_msg_array" "srs_protocol_stream" "srs_raw_avc" "srs_rtsp_stack" "srs_http_stack" "srs_protocol_kbps" "srs_protocol_json" - "srs_kafka_stack") + "srs_kafka_stack" "srs_protocol_format") PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh PROTOCOL_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj b/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj index 3ea84eaba..e404ce5ab 100644 --- a/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj +++ b/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj @@ -116,6 +116,7 @@ 3C82802C1BAFF8CC004A1794 /* srs_kafka_stack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C82802A1BAFF8CC004A1794 /* srs_kafka_stack.cpp */; }; 3C8CE01E1C3F482100548CC6 /* srs_app_hourglass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C8CE01D1C3F482100548CC6 /* srs_app_hourglass.cpp */; }; 3C9F82221E4ECA8200F5B2D2 /* srs_app_dash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F82201E4ECA8200F5B2D2 /* srs_app_dash.cpp */; }; + 3C9F82251E4F5D2A00F5B2D2 /* srs_protocol_format.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F82231E4F5D2A00F5B2D2 /* srs_protocol_format.cpp */; }; 3CA432A81E3F46DD001DA0C6 /* srs_kernel_io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3CA432A61E3F46DD001DA0C6 /* srs_kernel_io.cpp */; }; 3CA432AB1E40AEBC001DA0C6 /* Makefile in Sources */ = {isa = PBXBuildFile; fileRef = 3CA432A91E40AEBC001DA0C6 /* Makefile */; }; 3CA432AC1E40AEBC001DA0C6 /* srs_ingest_mp4.c in Sources */ = {isa = PBXBuildFile; fileRef = 3CA432AA1E40AEBC001DA0C6 /* srs_ingest_mp4.c */; }; @@ -409,6 +410,8 @@ 3C8CE01D1C3F482100548CC6 /* srs_app_hourglass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_hourglass.cpp; path = ../../../src/app/srs_app_hourglass.cpp; sourceTree = ""; }; 3C9F82201E4ECA8200F5B2D2 /* srs_app_dash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_dash.cpp; path = ../../../src/app/srs_app_dash.cpp; sourceTree = ""; }; 3C9F82211E4ECA8200F5B2D2 /* srs_app_dash.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_dash.hpp; path = ../../../src/app/srs_app_dash.hpp; sourceTree = ""; }; + 3C9F82231E4F5D2A00F5B2D2 /* srs_protocol_format.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_protocol_format.cpp; path = ../../../src/protocol/srs_protocol_format.cpp; sourceTree = ""; }; + 3C9F82241E4F5D2A00F5B2D2 /* srs_protocol_format.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_protocol_format.hpp; path = ../../../src/protocol/srs_protocol_format.hpp; sourceTree = ""; }; 3CA432A61E3F46DD001DA0C6 /* srs_kernel_io.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_kernel_io.cpp; path = ../../../src/kernel/srs_kernel_io.cpp; sourceTree = ""; }; 3CA432A71E3F46DD001DA0C6 /* srs_kernel_io.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_kernel_io.hpp; path = ../../../src/kernel/srs_kernel_io.hpp; sourceTree = ""; }; 3CA432A91E40AEBC001DA0C6 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../../research/librtmp/Makefile; sourceTree = ""; }; @@ -571,6 +574,8 @@ 3C82802B1BAFF8CC004A1794 /* srs_kafka_stack.hpp */, 3C12322F1AAE81A400CE8F6C /* srs_protocol_amf0.cpp */, 3C1232301AAE81A400CE8F6C /* srs_protocol_amf0.hpp */, + 3C9F82231E4F5D2A00F5B2D2 /* srs_protocol_format.cpp */, + 3C9F82241E4F5D2A00F5B2D2 /* srs_protocol_format.hpp */, 3C1232351AAE81A400CE8F6C /* srs_protocol_io.cpp */, 3C1232361AAE81A400CE8F6C /* srs_protocol_io.hpp */, 3C0D422C1B87165900C2508B /* srs_protocol_json.cpp */, @@ -1037,6 +1042,7 @@ 3C1232411AAE81A400CE8F6C /* srs_raw_avc.cpp in Sources */, 3C1232491AAE81A400CE8F6C /* srs_protocol_utility.cpp in Sources */, 3C663F191AB0155100286D8B /* srs_publish.c in Sources */, + 3C9F82251E4F5D2A00F5B2D2 /* srs_protocol_format.cpp in Sources */, 3C0E1B8D1B0F5ADF003ADEF7 /* srs_http_stack.cpp in Sources */, 3C1232A01AAE81D900CE8F6C /* srs_app_http_client.cpp in Sources */, 3C689F981AB6AAAC00C9CEEE /* key.c in Sources */, diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index e54555d11..73cb1d57e 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -50,6 +50,7 @@ using namespace std; #include #include #include +#include // drop the segment when duration of ts too small. #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 @@ -1117,13 +1118,12 @@ SrsHls::SrsHls() { req = NULL; hub = NULL; + format = NULL; enabled = false; disposable = false; last_update_time = 0; - codec = new SrsAvcAacCodec(); - sample = new SrsCodecSample(); jitter = new SrsRtmpJitter(); muxer = new SrsHlsMuxer(); @@ -1135,8 +1135,6 @@ SrsHls::SrsHls() SrsHls::~SrsHls() { - srs_freep(codec); - srs_freep(sample); srs_freep(jitter); srs_freep(muxer); @@ -1188,12 +1186,13 @@ int SrsHls::cycle() return ret; } -int SrsHls::initialize(SrsOriginHub* h, SrsRequest* r) +int SrsHls::initialize(SrsOriginHub* h, SrsFormat* f, SrsRequest* r) { int ret = ERROR_SUCCESS; hub = h; req = r; + format = f; if ((ret = muxer->initialize()) != ERROR_SUCCESS) { return ret; diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index dc856266c..ec50c1523 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -36,12 +36,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +class SrsFormat; class SrsSharedPtrMessage; -class SrsCodecSample; class SrsAmf0Object; class SrsRtmpJitter; class SrsTSMuxer; -class SrsAvcAacCodec; class SrsRequest; class SrsPithyPrint; class SrsSource; @@ -343,8 +342,7 @@ private: }; /** -* delivery RTMP stream to HLS(m3u8 and ts), -* SrsHls provides interface with SrsSource. +* Transmux RTMP stream to HLS(m3u8 and ts). * TODO: FIXME: add utest for hls. */ class SrsHls @@ -359,8 +357,7 @@ private: int64_t last_update_time; private: SrsOriginHub* hub; - SrsAvcAacCodec* codec; - SrsCodecSample* sample; + SrsFormat* format; SrsRtmpJitter* jitter; SrsPithyPrint* pprint; /** @@ -387,7 +384,7 @@ public: /** * initialize the hls by handler and source. */ - virtual int initialize(SrsOriginHub* h, SrsRequest* r); + virtual int initialize(SrsOriginHub* h, SrsFormat* f, SrsRequest* r); /** * publish stream event, continue to write the m3u8, * for the muxer object not destroyed. diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index f0f51597c..3b4b1fd91 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -48,6 +48,7 @@ using namespace std; #include #include #include +#include #define CONST_MAX_JITTER_MS 250 #define CONST_MAX_JITTER_MS_NEG -250 @@ -853,6 +854,7 @@ SrsOriginHub::SrsOriginHub() hds = new SrsHds(); #endif ng_exec = new SrsNgExec(); + format = new SrsFormat(); _srs_config->subscribe(this); } @@ -871,6 +873,7 @@ SrsOriginHub::~SrsOriginHub() } srs_freep(ng_exec); + srs_freep(format); srs_freep(hls); srs_freep(dash); srs_freep(dvr); @@ -889,7 +892,11 @@ int SrsOriginHub::initialize(SrsSource* s, SrsRequest* r) req = r; source = s; - if ((ret = hls->initialize(this, req)) != ERROR_SUCCESS) { + if ((ret = format->initialize()) != ERROR_SUCCESS) { + return ret; + } + + if ((ret = hls->initialize(this, format, req)) != ERROR_SUCCESS) { return ret; } @@ -924,10 +931,15 @@ int SrsOriginHub::cycle() return ret; } -int SrsOriginHub::on_meta_data(SrsSharedPtrMessage* shared_metadata) +int SrsOriginHub::on_meta_data(SrsSharedPtrMessage* shared_metadata, SrsOnMetaDataPacket* packet) { int ret = ERROR_SUCCESS; + if ((ret = format->on_metadata(packet)) != ERROR_SUCCESS) { + srs_error("Codec parse metadata failed, ret=%d", ret); + return ret; + } + // copy to all forwarders if (true) { std::vector::iterator it; @@ -954,6 +966,11 @@ int SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio) SrsSharedPtrMessage* msg = shared_audio; + if ((ret = format->on_audio(msg)) != ERROR_SUCCESS) { + srs_error("Codec parse audio failed, ret=%d", ret); + return ret; + } + if ((ret = hls->on_audio(msg)) != ERROR_SUCCESS) { // apply the error strategy for hls. // @see https://github.com/ossrs/srs/issues/264 @@ -1027,6 +1044,11 @@ int SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_h SrsSharedPtrMessage* msg = shared_video; + if ((ret = format->on_video(msg, is_sequence_header)) != ERROR_SUCCESS) { + srs_error("Codec parse video failed, ret=%d", ret); + return ret; + } + if ((ret = hls->on_video(msg, is_sequence_header)) != ERROR_SUCCESS) { // apply the error strategy for hls. // @see https://github.com/ossrs/srs/issues/264 @@ -2048,7 +2070,7 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata } // Copy to hub to all utilities. - return hub->on_meta_data(meta->data()); + return hub->on_meta_data(meta->data(), metadata); } int SrsSource::on_audio(SrsCommonMessage* shared_audio) diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 9ef381db5..9d7d09678 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +class SrsFormat; class SrsConsumer; class SrsPlayEdge; class SrsPublishEdge; @@ -421,6 +422,8 @@ private: // Whether the stream hub is active, or stream is publishing. bool is_active; private: + // The format, codec information. + SrsFormat* format; // hls handler. SrsHls* hls; // The DASH encoder. @@ -454,7 +457,7 @@ public: virtual int cycle(); public: // When got a parsed metadata. - virtual int on_meta_data(SrsSharedPtrMessage* shared_metadata); + virtual int on_meta_data(SrsSharedPtrMessage* shared_metadata, SrsOnMetaDataPacket* packet); // When got a parsed audio packet. virtual int on_audio(SrsSharedPtrMessage* shared_audio); // When got a parsed video packet. diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index 6404321b8..4cd4383a0 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -36,7 +36,7 @@ using namespace std; string srs_codec_video2str(SrsCodecVideo codec) { switch (codec) { - case SrsCodecVideoAVC: + case SrsCodecVideoAVC: return "H264"; case SrsCodecVideoOn2VP6: case SrsCodecVideoOn2VP6WithAlphaChannel: @@ -78,6 +78,185 @@ string srs_codec_audio2str(SrsCodecAudio codec) } } +string srs_codec_audio_samplerate2str(SrsCodecAudioSampleRate v) +{ + switch (v) { + case SrsCodecAudioSampleRate5512: return "5512"; + case SrsCodecAudioSampleRate11025: return "11025"; + case SrsCodecAudioSampleRate22050: return "22050"; + case SrsCodecAudioSampleRate44100: return "44100"; + default: return "Other"; + } +} + +SrsFlvCodec::SrsFlvCodec() +{ +} + +SrsFlvCodec::~SrsFlvCodec() +{ +} + +bool SrsFlvCodec::video_is_keyframe(char* data, int size) +{ + // 2bytes required. + if (size < 1) { + return false; + } + + char frame_type = data[0]; + frame_type = (frame_type >> 4) & 0x0F; + + return frame_type == SrsCodecVideoAVCFrameKeyFrame; +} + +bool SrsFlvCodec::video_is_sequence_header(char* data, int size) +{ + // sequence header only for h264 + if (!video_is_h264(data, size)) { + return false; + } + + // 2bytes required. + if (size < 2) { + return false; + } + + char frame_type = data[0]; + frame_type = (frame_type >> 4) & 0x0F; + + char avc_packet_type = data[1]; + + return frame_type == SrsCodecVideoAVCFrameKeyFrame + && avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader; +} + +bool SrsFlvCodec::audio_is_sequence_header(char* data, int size) +{ + // sequence header only for aac + if (!audio_is_aac(data, size)) { + return false; + } + + // 2bytes required. + if (size < 2) { + return false; + } + + char aac_packet_type = data[1]; + + return aac_packet_type == SrsCodecAudioTypeSequenceHeader; +} + +bool SrsFlvCodec::video_is_h264(char* data, int size) +{ + // 1bytes required. + if (size < 1) { + return false; + } + + char codec_id = data[0]; + codec_id = codec_id & 0x0F; + + return codec_id == SrsCodecVideoAVC; +} + +bool SrsFlvCodec::audio_is_aac(char* data, int size) +{ + // 1bytes required. + if (size < 1) { + return false; + } + + char sound_format = data[0]; + sound_format = (sound_format >> 4) & 0x0F; + + return sound_format == SrsCodecAudioAAC; +} + +bool SrsFlvCodec::video_is_acceptable(char* data, int size) +{ + // 1bytes required. + if (size < 1) { + return false; + } + + char frame_type = data[0]; + char codec_id = frame_type & 0x0f; + frame_type = (frame_type >> 4) & 0x0f; + + if (frame_type < 1 || frame_type > 5) { + return false; + } + + if (codec_id < 2 || codec_id > 7) { + return false; + } + + return true; +} + +/** + * the public data, event HLS disable, others can use it. + */ +// 0 = 5.5 kHz = 5512 Hz +// 1 = 11 kHz = 11025 Hz +// 2 = 22 kHz = 22050 Hz +// 3 = 44 kHz = 44100 Hz +int flv_sample_rates[] = {5512, 11025, 22050, 44100}; + +// the sample rates in the codec, +// in the sequence header. +int aac_sample_rates[] = +{ + 96000, 88200, 64000, 48000, + 44100, 32000, 24000, 22050, + 16000, 12000, 11025, 8000, + 7350, 0, 0, 0 +}; + +string srs_codec_audio_samplesize2str(SrsCodecAudioSampleSize v) +{ + switch (v) { + case SrsCodecAudioSampleSize16bit: return "16bits"; + case SrsCodecAudioSampleSize8bit: return "8bits"; + default: return "Other"; + } +} + +string srs_codec_audio_channels2str(SrsCodecAudioSoundType v) +{ + switch (v) { + case SrsCodecAudioSoundTypeStereo: return "Stereo"; + case SrsCodecAudioSoundTypeMono: return "Mono"; + default: return "Other"; + } +} + +string srs_codec_avc_nalu2str(SrsAvcNaluType nalu_type) +{ + switch (nalu_type) { + case SrsAvcNaluTypeNonIDR: return "NonIDR"; + case SrsAvcNaluTypeDataPartitionA: return "DataPartitionA"; + case SrsAvcNaluTypeDataPartitionB: return "DataPartitionB"; + case SrsAvcNaluTypeDataPartitionC: return "DataPartitionC"; + case SrsAvcNaluTypeIDR: return "IDR"; + case SrsAvcNaluTypeSEI: return "SEI"; + case SrsAvcNaluTypeSPS: return "SPS"; + case SrsAvcNaluTypePPS: return "PPS"; + case SrsAvcNaluTypeAccessUnitDelimiter: return "AccessUnitDelimiter"; + case SrsAvcNaluTypeEOSequence: return "EOSequence"; + case SrsAvcNaluTypeEOStream: return "EOStream"; + case SrsAvcNaluTypeFilterData: return "FilterData"; + case SrsAvcNaluTypeSPSExt: return "SPSExt"; + case SrsAvcNaluTypePrefixNALU: return "PrefixNALU"; + case SrsAvcNaluTypeSubsetSPS: return "SubsetSPS"; + case SrsAvcNaluTypeLayerWithoutPartition: return "LayerWithoutPartition"; + case SrsAvcNaluTypeCodedSliceExt: return "CodedSliceExt"; + case SrsAvcNaluTypeReserved: default: return "Other"; + } +} + string srs_codec_aac_profile2str(SrsAacProfile aac_profile) { switch (aac_profile) { @@ -162,193 +341,68 @@ string srs_codec_avc_level2str(SrsAvcLevel level) } } -string srs_codec_audio_samplerate2str(SrsCodecAudioSampleRate v) +SrsSample::SrsSample() { - switch (v) { - case SrsCodecAudioSampleRate5512: return "5512"; - case SrsCodecAudioSampleRate11025: return "11025"; - case SrsCodecAudioSampleRate22050: return "22050"; - case SrsCodecAudioSampleRate44100: return "44100"; - default: return "Other"; - } + nb_unit = 0; + unit = NULL; } -/** -* the public data, event HLS disable, others can use it. -*/ -// 0 = 5.5 kHz = 5512 Hz -// 1 = 11 kHz = 11025 Hz -// 2 = 22 kHz = 22050 Hz -// 3 = 44 kHz = 44100 Hz -int flv_sample_rates[] = {5512, 11025, 22050, 44100}; - -// the sample rates in the codec, -// in the sequence header. -int aac_sample_rates[] = -{ - 96000, 88200, 64000, 48000, - 44100, 32000, 24000, 22050, - 16000, 12000, 11025, 8000, - 7350, 0, 0, 0 -}; - -SrsFlvCodec::SrsFlvCodec() +SrsSample::~SrsSample() { } -SrsFlvCodec::~SrsFlvCodec() +SrsCodec::SrsCodec() { } -bool SrsFlvCodec::video_is_keyframe(char* data, int size) +SrsCodec::~SrsCodec() { - // 2bytes required. - if (size < 1) { - return false; - } - - char frame_type = data[0]; - frame_type = (frame_type >> 4) & 0x0F; - - return frame_type == SrsCodecVideoAVCFrameKeyFrame; } -bool SrsFlvCodec::video_is_sequence_header(char* data, int size) +SrsAudioCodec::SrsAudioCodec() { - // sequence header only for h264 - if (!video_is_h264(data, size)) { - return false; - } - - // 2bytes required. - if (size < 2) { - return false; - } - - char frame_type = data[0]; - frame_type = (frame_type >> 4) & 0x0F; - - char avc_packet_type = data[1]; - - return frame_type == SrsCodecVideoAVCFrameKeyFrame - && avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader; + acodec = SrsCodecAudioForbidden; + sound_rate = SrsCodecAudioSampleRateForbidden; + sound_size = SrsCodecAudioSampleSizeForbidden; + sound_type = SrsCodecAudioSoundTypeForbidden; + aac_packet_type = SrsCodecAudioTypeForbidden; } -bool SrsFlvCodec::audio_is_sequence_header(char* data, int size) +SrsAudioCodec::~SrsAudioCodec() { - // sequence header only for aac - if (!audio_is_aac(data, size)) { - return false; - } - - // 2bytes required. - if (size < 2) { - return false; - } - - char aac_packet_type = data[1]; - - return aac_packet_type == SrsCodecAudioTypeSequenceHeader; } -bool SrsFlvCodec::video_is_h264(char* data, int size) +SrsCodecFlvTag SrsAudioCodec::codec() { - // 1bytes required. - if (size < 1) { - return false; - } - - char codec_id = data[0]; - codec_id = codec_id & 0x0F; - - return codec_id == SrsCodecVideoAVC; + return SrsCodecFlvTagAudio; } -bool SrsFlvCodec::audio_is_aac(char* data, int size) +SrsVideoCodec::SrsVideoCodec() { - // 1bytes required. - if (size < 1) { - return false; - } - - char sound_format = data[0]; - sound_format = (sound_format >> 4) & 0x0F; - - return sound_format == SrsCodecAudioAAC; + frame_type = SrsCodecVideoAVCFrameForbidden; + avc_packet_type = SrsCodecVideoAVCTypeForbidden; + has_idr = has_aud = has_sps_pps = false; + first_nalu_type = SrsAvcNaluTypeForbidden; } -bool SrsFlvCodec::video_is_acceptable(char* data, int size) +SrsVideoCodec::~SrsVideoCodec() { - // 1bytes required. - if (size < 1) { - return false; - } - - char frame_type = data[0]; - char codec_id = frame_type & 0x0f; - frame_type = (frame_type >> 4) & 0x0f; - - if (frame_type < 1 || frame_type > 5) { - return false; - } - - if (codec_id < 2 || codec_id > 7) { - return false; - } - - return true; } -string srs_codec_audio_samplesize2str(SrsCodecAudioSampleSize v) +SrsCodecFlvTag SrsVideoCodec::codec() { - switch (v) { - case SrsCodecAudioSampleSize16bit: return "16bits"; - case SrsCodecAudioSampleSize8bit: return "8bits"; - default: return "Other"; - } + return SrsCodecFlvTagVideo; } -string srs_codec_audio_channels2str(SrsCodecAudioSoundType v) +SrsFrame::SrsFrame() { - switch (v) { - case SrsCodecAudioSoundTypeStereo: return "Stereo"; - case SrsCodecAudioSoundTypeMono: return "Mono"; - default: return "Other"; - } + codec = NULL; + nb_samples = 0; } -string srs_codec_avc_nalu2str(SrsAvcNaluType nalu_type) -{ - switch (nalu_type) { - case SrsAvcNaluTypeNonIDR: return "NonIDR"; - case SrsAvcNaluTypeDataPartitionA: return "DataPartitionA"; - case SrsAvcNaluTypeDataPartitionB: return "DataPartitionB"; - case SrsAvcNaluTypeDataPartitionC: return "DataPartitionC"; - case SrsAvcNaluTypeIDR: return "IDR"; - case SrsAvcNaluTypeSEI: return "SEI"; - case SrsAvcNaluTypeSPS: return "SPS"; - case SrsAvcNaluTypePPS: return "PPS"; - case SrsAvcNaluTypeAccessUnitDelimiter: return "AccessUnitDelimiter"; - case SrsAvcNaluTypeEOSequence: return "EOSequence"; - case SrsAvcNaluTypeEOStream: return "EOStream"; - case SrsAvcNaluTypeFilterData: return "FilterData"; - case SrsAvcNaluTypeSPSExt: return "SPSExt"; - case SrsAvcNaluTypePrefixNALU: return "PrefixNALU"; - case SrsAvcNaluTypeSubsetSPS: return "SubsetSPS"; - case SrsAvcNaluTypeLayerWithoutPartition: return "LayerWithoutPartition"; - case SrsAvcNaluTypeCodedSliceExt: return "CodedSliceExt"; - case SrsAvcNaluTypeReserved: default: return "Other"; - } -} - -SrsCodecSampleUnit::SrsCodecSampleUnit() -{ - size = 0; - bytes = NULL; -} - -SrsCodecSampleUnit::~SrsCodecSampleUnit() +SrsFrame::~SrsFrame() { + srs_freep(codec); } SrsCodecSample::SrsCodecSample() @@ -412,8 +466,6 @@ int SrsCodecSample::add_sample_unit(char* bytes, int size) return ret; } -#if !defined(SRS_EXPORT_LIBRTMP) - SrsAvcAacCodec::SrsAvcAacCodec() { avc_parse_sps = true; @@ -1205,7 +1257,7 @@ int SrsAvcAacCodec::avc_demux_annexb_format(SrsBuffer* stream, SrsCodecSample* s } // got the NALU. - if ((ret = sample->add_sample_unit(p, pp - p)) != ERROR_SUCCESS) { + if ((ret = sample->add_sample_unit(p, (int)(pp - p))) != ERROR_SUCCESS) { srs_error("annexb add video sample failed. ret=%d", ret); return ret; } @@ -1271,5 +1323,3 @@ int SrsAvcAacCodec::avc_demux_ibmf_format(SrsBuffer* stream, SrsCodecSample* sam return ret; } -#endif - diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index 79073f58a..66248f165 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -301,6 +301,7 @@ enum SrsAvcNaluType { // Unspecified SrsAvcNaluTypeReserved = 0, + SrsAvcNaluTypeForbidden = 0, // Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp( ) SrsAvcNaluTypeNonIDR = 1, @@ -340,23 +341,201 @@ enum SrsAvcNaluType std::string srs_codec_avc_nalu2str(SrsAvcNaluType nalu_type); /** -* the codec sample unit. -* for h.264 video packet, a NALU is a sample unit. -* for aac raw audio packet, a NALU is the entire aac raw data. -* for sequence header, it's not a sample unit. -*/ -class SrsCodecSampleUnit + * the avc payload format, must be ibmf or annexb format. + * we guess by annexb first, then ibmf for the first time, + * and we always use the guessed format for the next time. + */ +enum SrsAvcPayloadFormat +{ + SrsAvcPayloadFormatGuess = 0, + SrsAvcPayloadFormatAnnexb, + SrsAvcPayloadFormatIbmf, +}; + +/** + * the aac profile, for ADTS(HLS/TS) + * @see https://github.com/ossrs/srs/issues/310 + */ +enum SrsAacProfile +{ + SrsAacProfileReserved = 3, + + // @see 7.1 Profiles, aac-iso-13818-7.pdf, page 40 + SrsAacProfileMain = 0, + SrsAacProfileLC = 1, + SrsAacProfileSSR = 2, +}; +std::string srs_codec_aac_profile2str(SrsAacProfile aac_profile); + +/** + * the aac object type, for RTMP sequence header + * for AudioSpecificConfig, @see ISO_IEC_14496-3-AAC-2001.pdf, page 33 + * for audioObjectType, @see ISO_IEC_14496-3-AAC-2001.pdf, page 23 + */ +enum SrsAacObjectType +{ + SrsAacObjectTypeReserved = 0, + + // Table 1.1 - Audio Object Type definition + // @see @see ISO_IEC_14496-3-AAC-2001.pdf, page 23 + SrsAacObjectTypeAacMain = 1, + SrsAacObjectTypeAacLC = 2, + SrsAacObjectTypeAacSSR = 3, + + // AAC HE = LC+SBR + SrsAacObjectTypeAacHE = 5, + // AAC HEv2 = LC+SBR+PS + SrsAacObjectTypeAacHEV2 = 29, +}; +std::string srs_codec_aac_object2str(SrsAacObjectType aac_object); +// ts/hls/adts audio header profile to RTMP sequence header object type. +SrsAacObjectType srs_codec_aac_ts2rtmp(SrsAacProfile profile); +// RTMP sequence header object type to ts/hls/adts audio header profile. +SrsAacProfile srs_codec_aac_rtmp2ts(SrsAacObjectType object_type); + +/** + * the profile for avc/h.264. + * @see Annex A Profiles and levels, ISO_IEC_14496-10-AVC-2003.pdf, page 205. + */ +enum SrsAvcProfile +{ + SrsAvcProfileReserved = 0, + + // @see ffmpeg, libavcodec/avcodec.h:2713 + SrsAvcProfileBaseline = 66, + // FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag + // FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) + SrsAvcProfileConstrainedBaseline = 578, + SrsAvcProfileMain = 77, + SrsAvcProfileExtended = 88, + SrsAvcProfileHigh = 100, + SrsAvcProfileHigh10 = 110, + SrsAvcProfileHigh10Intra = 2158, + SrsAvcProfileHigh422 = 122, + SrsAvcProfileHigh422Intra = 2170, + SrsAvcProfileHigh444 = 144, + SrsAvcProfileHigh444Predictive = 244, + SrsAvcProfileHigh444Intra = 2192, +}; +std::string srs_codec_avc_profile2str(SrsAvcProfile profile); + +/** + * the level for avc/h.264. + * @see Annex A Profiles and levels, ISO_IEC_14496-10-AVC-2003.pdf, page 207. + */ +enum SrsAvcLevel +{ + SrsAvcLevelReserved = 0, + + SrsAvcLevel_1 = 10, + SrsAvcLevel_11 = 11, + SrsAvcLevel_12 = 12, + SrsAvcLevel_13 = 13, + SrsAvcLevel_2 = 20, + SrsAvcLevel_21 = 21, + SrsAvcLevel_22 = 22, + SrsAvcLevel_3 = 30, + SrsAvcLevel_31 = 31, + SrsAvcLevel_32 = 32, + SrsAvcLevel_4 = 40, + SrsAvcLevel_41 = 41, + SrsAvcLevel_5 = 50, + SrsAvcLevel_51 = 51, +}; +std::string srs_codec_avc_level2str(SrsAvcLevel level); + +/** + * A sample is the unit of frame. + * It's a NALU for H.264. + * It's the whole AAC raw data for AAC. + * @remark Neither SPS/PPS or ASC is sample unit, it's codec sequence header. + */ +class SrsSample { public: - /** - * the sample bytes is directly ptr to packet bytes, - * user should never use it when packet destroyed. - */ - int size; - char* bytes; + // The size of unit. + int nb_unit; + // The ptr of unit, user must manage it. + char* unit; public: - SrsCodecSampleUnit(); - virtual ~SrsCodecSampleUnit(); + SrsSample(); + virtual ~SrsSample(); +}; + +/** + * The codec is the information of encoder, + * corresponding to the sequence header of FLV, + * parsed to detail info. + */ +class SrsCodec +{ +public: + SrsCodec(); + virtual ~SrsCodec(); +public: + // Get the codec type. + virtual SrsCodecFlvTag codec() = 0; +}; + +/** + * The audio codec info. + */ +class SrsAudioCodec : public SrsCodec +{ +public: + // audio specified + SrsCodecAudio acodec; + // audio aac specified. + SrsCodecAudioSampleRate sound_rate; + SrsCodecAudioSampleSize sound_size; + SrsCodecAudioSoundType sound_type; + SrsCodecAudioType aac_packet_type; +public: + SrsAudioCodec(); + virtual ~SrsAudioCodec(); +public: + virtual SrsCodecFlvTag codec(); +}; + +/** + * The video codec info. + */ +class SrsVideoCodec : public SrsCodec +{ +public: + // video specified + SrsCodecVideoAVCFrame frame_type; + SrsCodecVideoAVCType avc_packet_type; + // whether sample_units contains IDR frame. + bool has_idr; + // Whether exists AUD NALU. + bool has_aud; + // Whether exists SPS/PPS NALU. + bool has_sps_pps; + // The first nalu type. + SrsAvcNaluType first_nalu_type; +public: + SrsVideoCodec(); + virtual ~SrsVideoCodec(); +public: + virtual SrsCodecFlvTag codec(); +}; + +/** + * A codec frame, consists of a codec and a group of samples. + */ +class SrsFrame +{ +public: + // The codec info of frame. + SrsCodec* codec; + // The actual parsed number of samples. + int nb_samples; + // The sampels cache. + SrsSample samples[SRS_MAX_CODEC_SAMPLE]; +public: + SrsFrame(); + virtual ~SrsFrame(); }; /** @@ -435,112 +614,6 @@ public: int add_sample_unit(char* bytes, int size); }; -/** -* the avc payload format, must be ibmf or annexb format. -* we guess by annexb first, then ibmf for the first time, -* and we always use the guessed format for the next time. -*/ -enum SrsAvcPayloadFormat -{ - SrsAvcPayloadFormatGuess = 0, - SrsAvcPayloadFormatAnnexb, - SrsAvcPayloadFormatIbmf, -}; - -/** -* the aac profile, for ADTS(HLS/TS) -* @see https://github.com/ossrs/srs/issues/310 -*/ -enum SrsAacProfile -{ - SrsAacProfileReserved = 3, - - // @see 7.1 Profiles, aac-iso-13818-7.pdf, page 40 - SrsAacProfileMain = 0, - SrsAacProfileLC = 1, - SrsAacProfileSSR = 2, -}; -std::string srs_codec_aac_profile2str(SrsAacProfile aac_profile); - -/** -* the aac object type, for RTMP sequence header -* for AudioSpecificConfig, @see ISO_IEC_14496-3-AAC-2001.pdf, page 33 -* for audioObjectType, @see ISO_IEC_14496-3-AAC-2001.pdf, page 23 -*/ -enum SrsAacObjectType -{ - SrsAacObjectTypeReserved = 0, - - // Table 1.1 - Audio Object Type definition - // @see @see ISO_IEC_14496-3-AAC-2001.pdf, page 23 - SrsAacObjectTypeAacMain = 1, - SrsAacObjectTypeAacLC = 2, - SrsAacObjectTypeAacSSR = 3, - - // AAC HE = LC+SBR - SrsAacObjectTypeAacHE = 5, - // AAC HEv2 = LC+SBR+PS - SrsAacObjectTypeAacHEV2 = 29, -}; -std::string srs_codec_aac_object2str(SrsAacObjectType aac_object); -// ts/hls/adts audio header profile to RTMP sequence header object type. -SrsAacObjectType srs_codec_aac_ts2rtmp(SrsAacProfile profile); -// RTMP sequence header object type to ts/hls/adts audio header profile. -SrsAacProfile srs_codec_aac_rtmp2ts(SrsAacObjectType object_type); - -/** -* the profile for avc/h.264. -* @see Annex A Profiles and levels, ISO_IEC_14496-10-AVC-2003.pdf, page 205. -*/ -enum SrsAvcProfile -{ - SrsAvcProfileReserved = 0, - - // @see ffmpeg, libavcodec/avcodec.h:2713 - SrsAvcProfileBaseline = 66, - // FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag - // FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) - SrsAvcProfileConstrainedBaseline = 578, - SrsAvcProfileMain = 77, - SrsAvcProfileExtended = 88, - SrsAvcProfileHigh = 100, - SrsAvcProfileHigh10 = 110, - SrsAvcProfileHigh10Intra = 2158, - SrsAvcProfileHigh422 = 122, - SrsAvcProfileHigh422Intra = 2170, - SrsAvcProfileHigh444 = 144, - SrsAvcProfileHigh444Predictive = 244, - SrsAvcProfileHigh444Intra = 2192, -}; -std::string srs_codec_avc_profile2str(SrsAvcProfile profile); - -/** -* the level for avc/h.264. -* @see Annex A Profiles and levels, ISO_IEC_14496-10-AVC-2003.pdf, page 207. -*/ -enum SrsAvcLevel -{ - SrsAvcLevelReserved = 0, - - SrsAvcLevel_1 = 10, - SrsAvcLevel_11 = 11, - SrsAvcLevel_12 = 12, - SrsAvcLevel_13 = 13, - SrsAvcLevel_2 = 20, - SrsAvcLevel_21 = 21, - SrsAvcLevel_22 = 22, - SrsAvcLevel_3 = 30, - SrsAvcLevel_31 = 31, - SrsAvcLevel_32 = 32, - SrsAvcLevel_4 = 40, - SrsAvcLevel_41 = 41, - SrsAvcLevel_5 = 50, - SrsAvcLevel_51 = 51, -}; -std::string srs_codec_avc_level2str(SrsAvcLevel level); - -#if !defined(SRS_EXPORT_LIBRTMP) - /** * the h264/avc and aac codec, for media stream. * @@ -682,5 +755,3 @@ private: #endif -#endif - diff --git a/trunk/src/protocol/srs_protocol_format.cpp b/trunk/src/protocol/srs_protocol_format.cpp new file mode 100644 index 000000000..75425233f --- /dev/null +++ b/trunk/src/protocol/srs_protocol_format.cpp @@ -0,0 +1,66 @@ +/* + The MIT License (MIT) + + Copyright (c) 2013-2017 SRS(ossrs) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include + +SrsFormat::SrsFormat() +{ + audio = video = NULL; +} + +SrsFormat::~SrsFormat() +{ + srs_freep(audio); + srs_freep(video); +} + +int SrsFormat::initialize() +{ + return ERROR_SUCCESS; +} + +int SrsFormat::on_metadata(SrsOnMetaDataPacket* meta) +{ + int ret = ERROR_SUCCESS; + + // TODO: FIXME: Try to initialize format from metadata. + + return ret; +} + +int SrsFormat::on_audio(SrsSharedPtrMessage* shared_audio) +{ + int ret = ERROR_SUCCESS; + return ret; +} + +int SrsFormat::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header) +{ + int ret = ERROR_SUCCESS; + return ret; +} + diff --git a/trunk/src/protocol/srs_protocol_format.hpp b/trunk/src/protocol/srs_protocol_format.hpp new file mode 100644 index 000000000..d3f61aa22 --- /dev/null +++ b/trunk/src/protocol/srs_protocol_format.hpp @@ -0,0 +1,62 @@ +/* + The MIT License (MIT) + + Copyright (c) 2013-2017 SRS(ossrs) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_PROTOCOL_FORMAT_HPP +#define SRS_PROTOCOL_FORMAT_HPP + +/* +#include +*/ + +#include + +class SrsFrame; +class SrsOnMetaDataPacket; +class SrsSharedPtrMessage; + +/** + * A codec format, including one or many stream, each stream identified by a frame. + * For example, a typical RTMP stream format, consits of a video and audio frame. + * Maybe some RTMP stream only has a audio stream, for instance, redio application. + */ +class SrsFormat +{ +public: + SrsFrame* audio; + SrsFrame* video; +public: + SrsFormat(); + virtual ~SrsFormat(); +public: + // Initialize the format. + virtual int initialize(); + // Initialize the format from metadata, optional. + virtual int on_metadata(SrsOnMetaDataPacket* meta); + // When got a parsed audio packet. + virtual int on_audio(SrsSharedPtrMessage* shared_audio); + // When got a parsed video packet. + virtual int on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header); +}; + +#endif +