diff --git a/trunk/src/app/srs_app_json.hpp b/trunk/src/app/srs_app_json.hpp index 002492fdf..d8aeba818 100644 --- a/trunk/src/app/srs_app_json.hpp +++ b/trunk/src/app/srs_app_json.hpp @@ -217,6 +217,7 @@ that is: #define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\"" #define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v #define __SRS_JFIELD_BOOL(k, v) __SRS_JFIELD_ORG(k, (v? "true":"false")) +#define __SRS_JFIELD_NULL(k) "\"" << k << "\":null" #define __SRS_JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret #define __SRS_JFIELD_CONT "," #define __SRS_JOBJECT_END "}" diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index dcdff73d2..c91d1fe12 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -202,7 +202,7 @@ int SrsRtmpConn::do_cycle() ret = service_cycle(); http_hooks_on_close(); SrsStatistic* stat = SrsStatistic::instance(); - stat->on_close(_srs_context->get_id()); + stat->on_disconnect(_srs_context->get_id()); return ret; } diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index fa12bda4f..cf8883620 100644 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -42,6 +42,7 @@ using namespace std; #include #include #include +#include #define CONST_MAX_JITTER_MS 500 #define DEFAULT_FRAME_TIME_MS 40 @@ -1373,6 +1374,7 @@ int SrsSource::on_audio(SrsCommonMessage* __audio) // cache the sequence header of aac, or first packet of mp3. // for example, the mp3 is used for hls to write the "right" audio codec. + // TODO: FIXME: to refine the stream info system. bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg.payload, msg.size); if (is_aac_sequence_header || !cache_sh_audio) { srs_freep(cache_sh_audio); @@ -1392,6 +1394,13 @@ int SrsSource::on_audio(SrsCommonMessage* __audio) static int flv_sample_sizes[] = {8, 16, 0}; static int flv_sound_types[] = {1, 2, 0}; + + // when got audio stream info. + SrsStatistic* stat = SrsStatistic::instance(); + if ((ret = stat->on_audio_info(_req, SrsCodecAudioAAC, sample.sound_rate, sample.sound_type, codec.aac_profile)) != ERROR_SUCCESS) { + return ret; + } + srs_trace("%dB audio sh, " "codec(%d, profile=%d, %dchannels, %dkbps, %dHZ), " "flv(%dbits, %dchannels, %dHZ)", @@ -1515,6 +1524,12 @@ int SrsSource::on_video(SrsCommonMessage* __video) return ret; } + // when got video stream info. + SrsStatistic* stat = SrsStatistic::instance(); + if ((ret = stat->on_video_info(_req, SrsCodecVideoAVC, codec.avc_profile, codec.avc_level)) != ERROR_SUCCESS) { + return ret; + } + srs_trace("%dB video sh, " "codec(%d, profile=%d, level=%d, %dx%d, %dkbps, %dfps, %ds)", msg.size, codec.video_codec_id, diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index e58d547bb..a246bf42d 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -50,12 +50,29 @@ SrsStatisticStream::SrsStatisticStream() { id = __srs_generate_id(); vhost = NULL; + + has_video = false; + vcodec = SrsCodecVideoReserved; + avc_profile = 0; + avc_level = 0; + + has_audio = false; + acodec = SrsCodecAudioReserved1; + asample_rate = SrsCodecAudioSampleRateReserved; + asound_type = SrsCodecAudioSoundTypeReserved; + aac_profile = 0; } SrsStatisticStream::~SrsStatisticStream() { } +void SrsStatisticStream::close() +{ + has_video = false; + has_audio = false; +} + SrsStatistic* SrsStatistic::_instance = new SrsStatistic(); SrsStatistic::SrsStatistic() @@ -93,34 +110,54 @@ SrsStatistic* SrsStatistic::instance() return _instance; } +int SrsStatistic::on_video_info(SrsRequest* req, + SrsCodecVideo vcodec, u_int8_t avc_profile, u_int8_t avc_level +) { + int ret = ERROR_SUCCESS; + + SrsStatisticVhost* vhost = create_vhost(req); + SrsStatisticStream* stream = create_stream(vhost, req); + + stream->has_video = true; + stream->vcodec = vcodec; + stream->avc_profile = avc_profile; + stream->avc_level = avc_level; + + return ret; +} + +int SrsStatistic::on_audio_info(SrsRequest* req, + SrsCodecAudio acodec, SrsCodecAudioSampleRate asample_rate, SrsCodecAudioSoundType asound_type, + u_int8_t aac_profile +) { + int ret = ERROR_SUCCESS; + + SrsStatisticVhost* vhost = create_vhost(req); + SrsStatisticStream* stream = create_stream(vhost, req); + + stream->has_audio = true; + stream->acodec = acodec; + stream->asample_rate = asample_rate; + stream->asound_type = asound_type; + stream->aac_profile = aac_profile; + + return ret; +} + +void SrsStatistic::on_stream_close(SrsRequest* req) +{ + SrsStatisticVhost* vhost = create_vhost(req); + SrsStatisticStream* stream = create_stream(vhost, req); + + stream->close(); +} + int SrsStatistic::on_client(int id, SrsRequest* req) { int ret = ERROR_SUCCESS; - // create vhost if not exists. - SrsStatisticVhost* vhost = NULL; - if (vhosts.find(req->vhost) == vhosts.end()) { - vhost = new SrsStatisticVhost(); - vhost->vhost = req->vhost; - vhosts[req->vhost] = vhost; - } else { - vhost = vhosts[req->vhost]; - } - - // the url to identify the stream. - std::string url = req->get_stream_url(); - - // create stream if not exists. - SrsStatisticStream* stream = NULL; - if (streams.find(url) == streams.end()) { - stream = new SrsStatisticStream(); - stream->vhost = vhost; - stream->stream = req->stream; - stream->url = url; - streams[url] = stream; - } else { - stream = streams[url]; - } + SrsStatisticVhost* vhost = create_vhost(req); + SrsStatisticStream* stream = create_stream(vhost, req); // create client if not exists SrsStatisticClient* client = NULL; @@ -135,7 +172,7 @@ int SrsStatistic::on_client(int id, SrsRequest* req) return ret; } -void SrsStatistic::on_close(int id) +void SrsStatistic::on_disconnect(int id) { std::map::iterator it; it = clients.find(id); @@ -198,10 +235,74 @@ int SrsStatistic::dumps_streams(stringstream& ss) << __SRS_JFIELD_ORG("id", stream->id) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("name", stream->stream) << __SRS_JFIELD_CONT << __SRS_JFIELD_ORG("vhost", stream->vhost->id) << __SRS_JFIELD_CONT - << __SRS_JFIELD_ORG("clients", client_num) - << __SRS_JOBJECT_END; + << __SRS_JFIELD_ORG("clients", client_num) << __SRS_JFIELD_CONT; + + if (!stream->has_video) { + ss << __SRS_JFIELD_NULL("video") << __SRS_JFIELD_CONT; + } else { + ss << __SRS_JFIELD_NAME("video") + << __SRS_JOBJECT_START + << __SRS_JFIELD_STR("codec", srs_codec_video2str(stream->vcodec)) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("profile", (int)stream->avc_profile) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("level", (int)stream->avc_level) + << __SRS_JOBJECT_END + << __SRS_JFIELD_CONT; + } + + if (!stream->has_audio) { + ss << __SRS_JFIELD_NULL("audio"); + } else { + ss << __SRS_JFIELD_NAME("audio") + << __SRS_JOBJECT_START + << __SRS_JFIELD_STR("codec", srs_codec_audio2str(stream->acodec)) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("sample_rate", (int)flv_sample_rates[stream->asample_rate]) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("channel", (int)stream->asound_type + 1) << __SRS_JFIELD_CONT + << __SRS_JFIELD_STR("profile", srs_codec_aac_profile2str(stream->aac_profile)) + << __SRS_JOBJECT_END; + } + + ss << __SRS_JOBJECT_END; } ss << __SRS_JARRAY_END; return ret; } + +SrsStatisticVhost* SrsStatistic::create_vhost(SrsRequest* req) +{ + SrsStatisticVhost* vhost = NULL; + + // create vhost if not exists. + if (vhosts.find(req->vhost) == vhosts.end()) { + vhost = new SrsStatisticVhost(); + vhost->vhost = req->vhost; + vhosts[req->vhost] = vhost; + return vhost; + } + + vhost = vhosts[req->vhost]; + + return vhost; +} + +SrsStatisticStream* SrsStatistic::create_stream(SrsStatisticVhost* vhost, SrsRequest* req) +{ + std::string url = req->get_stream_url(); + + SrsStatisticStream* stream = NULL; + + // create stream if not exists. + if (streams.find(url) == streams.end()) { + stream = new SrsStatisticStream(); + stream->vhost = vhost; + stream->stream = req->stream; + stream->url = url; + streams[url] = stream; + return stream; + } + + stream = streams[url]; + + return stream; +} + diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 0e3c5aa89..441e09be4 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include + class SrsRequest; struct SrsStatisticVhost @@ -53,9 +55,33 @@ public: std::string app; std::string stream; std::string url; +public: + bool has_video; + SrsCodecVideo vcodec; + // profile_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45. + u_int8_t avc_profile; + // level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45. + u_int8_t avc_level; +public: + bool has_audio; + SrsCodecAudio acodec; + SrsCodecAudioSampleRate asample_rate; + SrsCodecAudioSoundType asound_type; + /** + * audio specified + * audioObjectType, in 1.6.2.1 AudioSpecificConfig, page 33, + * 1.5.1.1 Audio object type definition, page 23, + * in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf. + */ + u_int8_t aac_profile; public: SrsStatisticStream(); virtual ~SrsStatisticStream(); +public: + /** + * close the stream. + */ + virtual void close(); }; struct SrsStatisticClient @@ -73,7 +99,7 @@ private: int64_t _server_id; // key: vhost name, value: vhost object. std::map vhosts; - // key: stream name, value: stream object. + // key: stream url, value: stream object. std::map streams; // key: client id, value: stream object. std::map clients; @@ -82,6 +108,24 @@ private: virtual ~SrsStatistic(); public: static SrsStatistic* instance(); +public: + /** + * when got video info for stream. + */ + virtual int on_video_info(SrsRequest* req, + SrsCodecVideo vcodec, u_int8_t avc_profile, u_int8_t avc_level + ); + /** + * when got audio info for stream. + */ + virtual int on_audio_info(SrsRequest* req, + SrsCodecAudio acodec, SrsCodecAudioSampleRate asample_rate, SrsCodecAudioSoundType asound_type, + u_int8_t aac_profile + ); + /** + * when close stream. + */ + virtual void on_stream_close(SrsRequest* req); public: /** * when got a client to publish/play stream, @@ -90,9 +134,9 @@ public: */ virtual int on_client(int id, SrsRequest* req); /** - * client close + * client disconnect */ - virtual void on_close(int id); + virtual void on_disconnect(int id); public: /** * get the server id, used to identify the server. @@ -107,6 +151,9 @@ public: * dumps the streams to sstream in json. */ virtual int dumps_streams(std::stringstream& ss); +private: + virtual SrsStatisticVhost* create_vhost(SrsRequest* req); + virtual SrsStatisticStream* create_stream(SrsStatisticVhost* vhost, SrsRequest* req); }; #endif diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index 90512b06e..a14082172 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -32,6 +32,80 @@ using namespace std; #include #include +string srs_codec_video2str(SrsCodecVideo codec) +{ + switch (codec) { + case SrsCodecVideoAVC: + return "H264"; + case SrsCodecVideoOn2VP6: + case SrsCodecVideoOn2VP6WithAlphaChannel: + return "H264"; + case SrsCodecVideoReserved: + case SrsCodecVideoReserved1: + case SrsCodecVideoReserved2: + case SrsCodecVideoDisabled: + case SrsCodecVideoSorensonH263: + case SrsCodecVideoScreenVideo: + case SrsCodecVideoScreenVideoVersion2: + default: + return "Other"; + } +} + +string srs_codec_audio2str(SrsCodecAudio codec) +{ + switch (codec) { + case SrsCodecAudioAAC: + return "AAC"; + case SrsCodecAudioMP3: + return "MP3"; + case SrsCodecAudioReserved1: + case SrsCodecAudioLinearPCMPlatformEndian: + case SrsCodecAudioADPCM: + case SrsCodecAudioLinearPCMLittleEndian: + case SrsCodecAudioNellymoser16kHzMono: + case SrsCodecAudioNellymoser8kHzMono: + case SrsCodecAudioNellymoser: + case SrsCodecAudioReservedG711AlawLogarithmicPCM: + case SrsCodecAudioReservedG711MuLawLogarithmicPCM: + case SrsCodecAudioReserved: + case SrsCodecAudioSpeex: + case SrsCodecAudioReservedMP3_8kHz: + case SrsCodecAudioReservedDeviceSpecificSound: + default: + return "Other"; + } +} + +string srs_codec_aac_profile2str(u_int8_t aac_profile) +{ + switch (aac_profile) { + case 1: return "Main"; + case 2: return "LC"; + case 3: return "SSR"; + default: return "Other"; + } +} + +/** +* 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() { } diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index 34604a6a1..c7fda2b85 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -110,6 +110,7 @@ enum SrsCodecVideo SrsCodecVideoScreenVideoVersion2 = 6, SrsCodecVideoAVC = 7, }; +std::string srs_codec_video2str(SrsCodecVideo codec); // SoundFormat UB [4] // Format of SoundData. The following values are defined: @@ -150,6 +151,7 @@ enum SrsCodecAudio SrsCodecAudioReservedMP3_8kHz = 14, SrsCodecAudioReservedDeviceSpecificSound = 15, }; +std::string srs_codec_audio2str(SrsCodecAudio codec); /** * the FLV/RTMP supported audio sample rate. @@ -373,6 +375,21 @@ enum SrsAvcPayloadFormat SrsAvcPayloadFormatIbmf, }; +// the profile = object_id + 1 +// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, +// Table 1. A.9 C MPEG-2 Audio profiles and MPEG-4 Audio object types +// the valid object type: +// AAC Main(ID == 0) +// AAC LC(ID == 1) +// AAC SSR(ID == 2) +// AAC LTP(ID == 3) +// the valid aac profile: +// Main profile (ID == 1) +// Low Complexity profile (LC) (ID == 2) +// Scalable Sampling Rate profile (SSR) (ID == 3) +// (reserved) (ID == 4) +std::string srs_codec_aac_profile2str(u_int8_t aac_profile); + /** * the h264/avc and aac codec, for media stream. * diff --git a/trunk/src/kernel/srs_kernel_ts.cpp b/trunk/src/kernel/srs_kernel_ts.cpp index 76dc0b2fd..154bbef42 100644 --- a/trunk/src/kernel/srs_kernel_ts.cpp +++ b/trunk/src/kernel/srs_kernel_ts.cpp @@ -56,25 +56,6 @@ using namespace std; #define TS_AUDIO_AAC_PID 0x102 #define TS_AUDIO_MP3_PID 0x103 -/** -* 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_ts_stream2string(SrsTsStream stream) { switch (stream) {