From d9474d760076b1cd298c8317d82c8e266545ac6e Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 21 Nov 2014 13:48:57 +0800 Subject: [PATCH] refine examples of srs-librtmp, add srs_print_rtmp_packet. 2.0.28. --- README.md | 1 + trunk/research/librtmp/srs_flv_parser.c | 98 ++------------ trunk/research/librtmp/srs_ingest_flv.c | 9 +- trunk/research/librtmp/srs_ingest_rtmp.c | 7 +- trunk/research/librtmp/srs_play.c | 7 +- trunk/src/core/srs_core.hpp | 2 +- trunk/src/libs/srs_librtmp.cpp | 161 ++++++++++++++++++++++- trunk/src/libs/srs_librtmp.hpp | 100 ++++++++++++++ 8 files changed, 284 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 25fd07033..e5027c2b8 100755 --- a/README.md +++ b/README.md @@ -482,6 +482,7 @@ Supported operating systems and hardware: * 2013-10-17, Created.
## History +* v2.0, 2014-11-21, refine examples of srs-librtmp, add srs_print_rtmp_packet. 2.0.28. * v2.0, 2014-11-20, fix [#212](https://github.com/winlinvip/simple-rtmp-server/issues/212), support publish audio raw frames. 2.0.27 * v2.0, 2014-11-19, fix [#213](https://github.com/winlinvip/simple-rtmp-server/issues/213), support compile [srs-librtmp on windows](https://github.com/winlinvip/srs.librtmp), [bug #213](https://github.com/winlinvip/simple-rtmp-server/issues/213). 2.0.26 * v2.0, 2014-11-18, all wiki translated to English. 2.0.23. diff --git a/trunk/research/librtmp/srs_flv_parser.c b/trunk/research/librtmp/srs_flv_parser.c index 22108d522..82a7470a0 100644 --- a/trunk/research/librtmp/srs_flv_parser.c +++ b/trunk/research/librtmp/srs_flv_parser.c @@ -124,86 +124,6 @@ int parse_bytes(char* data, int size, char* hbuf, int hsize, char* tbuf, int tsi } } -#define FLV_HEADER_SIZE 11 -int parse_script_data(u_int32_t timestamp, u_int32_t pts, char* data, int size, int64_t offset) -{ - int ret = 0; - - char hbuf[48]; - char tbuf[48]; - - int amf0_size = 0; - int nparsed = 0; - - srs_amf0_t amf0_name; - char* amf0_name_str = NULL; - - srs_amf0_t amf0_data; - char* amf0_data_str = NULL; - - // bytes - parse_bytes(data, size, hbuf, sizeof(hbuf), tbuf, sizeof(tbuf), 16); - - // amf0 - amf0_name = srs_amf0_parse(data, size, &nparsed); - if (amf0_name == NULL || nparsed >= size) { - srs_lib_trace("invalid amf0 name data."); - return -1; - } - amf0_data = srs_amf0_parse(data + nparsed, size - nparsed, &nparsed); - - srs_lib_trace("packet type=%s, dts=%d, pts=%d, size=%d, data-size=%d, \n" - "offset=%d\n[+00, +15] %s\n[-15, EOF] %s\n%s%s", - srs_type2string(SRS_RTMP_TYPE_SCRIPT), timestamp, pts, - size + FLV_HEADER_SIZE, size, (int)offset, hbuf, tbuf, - srs_amf0_human_print(amf0_name, &amf0_name_str, &amf0_size), - srs_amf0_human_print(amf0_data, &amf0_data_str, &amf0_size)); - - srs_amf0_free(amf0_name); - srs_amf0_free_bytes(amf0_name_str); - - srs_amf0_free(amf0_data); - srs_amf0_free_bytes(amf0_data_str); - - return ret; -} - -int parse_audio_data(u_int32_t timestamp, u_int32_t pts, char* data, int size, int64_t offset) -{ - int ret = 0; - - char hbuf[48]; - char tbuf[48]; - - // bytes - parse_bytes(data, size, hbuf, sizeof(hbuf), tbuf, sizeof(tbuf), 16); - - srs_lib_trace("packet type=%s, dts=%d, pts=%d, size=%d, data-size=%d, \n" - "offset=%d\n[+00, +15] %s\n[-15, EOF] %s\n", - srs_type2string(SRS_RTMP_TYPE_AUDIO), timestamp, pts, - size + FLV_HEADER_SIZE, size, (int)offset, hbuf, tbuf); - - return ret; -} - -int parse_video_data(u_int32_t timestamp, u_int32_t pts, char* data, int size, int64_t offset) -{ - int ret = 0; - - char hbuf[48]; - char tbuf[48]; - - // bytes - parse_bytes(data, size, hbuf, sizeof(hbuf), tbuf, sizeof(tbuf), 16); - - srs_lib_trace("packet type=%s, dts=%d, pts=%d, size=%d, data-size=%d, \n" - "offset=%d\n[+00, +15] %s\n[-15, EOF] %s\n", - srs_type2string(SRS_RTMP_TYPE_VIDEO), timestamp, pts, - size + FLV_HEADER_SIZE, size, (int)offset, hbuf, tbuf); - - return ret; -} - int parse_flv(srs_flv_t flv) { int ret = 0; @@ -240,19 +160,19 @@ int parse_flv(srs_flv_t flv) break; } - u_int32_t pts = 0; data = (char*)malloc(size); - if ((ret = srs_flv_read_tag_data(flv, data, size)) == 0 - && (ret = srs_parse_timestamp(timestamp, type, data, size, &pts)) == 0 - ) { - if (type == SRS_RTMP_TYPE_AUDIO) { - ret = parse_audio_data(timestamp, pts, data, size, offset); - } else if (type == SRS_RTMP_TYPE_VIDEO) { - ret = parse_video_data(timestamp, pts, data, size, offset); + if ((ret = srs_flv_read_tag_data(flv, data, size)) == 0) { + if ((ret = srs_print_rtmp_packet(type, timestamp, data, size)) == 0) { + char hbuf[48]; char tbuf[48]; + parse_bytes(data, size, hbuf, sizeof(hbuf), tbuf, sizeof(tbuf), 16); + srs_raw_trace("offset=%d, first and last 16 bytes:\n" + "[+00, +15] %s\n[-15, EOF] %s\n", (int)offset, hbuf, tbuf); } else { - ret = parse_script_data(timestamp, pts, data, size, offset); + srs_lib_trace("print packet failed. ret=%d", ret); } + } else { + srs_lib_trace("read flv failed. ret=%d", ret); } free(data); diff --git a/trunk/research/librtmp/srs_ingest_flv.c b/trunk/research/librtmp/srs_ingest_flv.c index baa9881cb..141354933 100644 --- a/trunk/research/librtmp/srs_ingest_flv.c +++ b/trunk/research/librtmp/srs_ingest_flv.c @@ -141,12 +141,17 @@ int do_proxy(srs_flv_t flv, srs_rtmp_t ortmp, int64_t re, int32_t* pstarttime, u return ret; } + u_int32_t timestamp = *ptimestamp; + + if ((ret = srs_print_rtmp_packet(type, timestamp, data, size)) != 0) { + srs_lib_trace("print packet failed. ret=%d", ret); + return ret; + } + if ((ret = srs_write_packet(ortmp, type, *ptimestamp, data, size)) != 0) { srs_lib_trace("irtmp get packet failed. ret=%d", ret); return ret; } - srs_lib_verbose("ortmp sent packet: type=%s, time=%d, size=%d", - srs_type2string(type), *ptimestamp, size); if (*pstarttime < 0) { *pstarttime = *ptimestamp; diff --git a/trunk/research/librtmp/srs_ingest_rtmp.c b/trunk/research/librtmp/srs_ingest_rtmp.c index 3bec458c6..25357ce93 100644 --- a/trunk/research/librtmp/srs_ingest_rtmp.c +++ b/trunk/research/librtmp/srs_ingest_rtmp.c @@ -112,8 +112,11 @@ int proxy(srs_rtmp_t irtmp, srs_rtmp_t ortmp) srs_lib_trace("irtmp get packet failed. ret=%d", ret); return ret; } - srs_lib_verbose("irtmp got packet: type=%s, time=%d, size=%d", - srs_type2string(type), timestamp, size); + + if ((ret = srs_print_rtmp_packet(type, timestamp, data, size)) != 0) { + srs_lib_trace("print packet failed. ret=%d", ret); + return ret; + } if ((ret = srs_write_packet(ortmp, type, timestamp, data, size)) != 0) { srs_lib_trace("irtmp get packet failed. ret=%d", ret); diff --git a/trunk/research/librtmp/srs_play.c b/trunk/research/librtmp/srs_play.c index 0b0410474..4039ed3c2 100644 --- a/trunk/research/librtmp/srs_play.c +++ b/trunk/research/librtmp/srs_play.c @@ -69,16 +69,15 @@ int main(int argc, char** argv) int size; char type; char* data; - u_int32_t timestamp, pts; + u_int32_t timestamp; if (srs_read_packet(rtmp, &type, ×tamp, &data, &size) != 0) { goto rtmp_destroy; } - if (srs_parse_timestamp(timestamp, type, data, size, &pts) != 0) { + + if (srs_print_rtmp_packet(type, timestamp, data, size) != 0) { goto rtmp_destroy; } - srs_lib_trace("got packet: type=%s, dts=%d, pts=%d, size=%d", - srs_type2string(type), timestamp, pts, size); free(data); } diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index c277518df..494556c55 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_REVISION 27 +#define VERSION_REVISION 28 // server info. #define RTMP_SIG_SRS_KEY "SRS" #define RTMP_SIG_SRS_ROLE "origin/edge server" diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp index e789d21a8..b0565c493 100644 --- a/trunk/src/libs/srs_librtmp.cpp +++ b/trunk/src/libs/srs_librtmp.cpp @@ -936,6 +936,161 @@ int srs_parse_timestamp( return ret; } +char srs_get_codec_id(char* data, int size) +{ + if (size < 1) { + return 0; + } + + char codec_id = data[0]; + codec_id = codec_id & 0x0F; + + return codec_id; +} + +const char* srs_code_id2string(char codec_id) +{ + static const char* h263 = "H.263"; + static const char* screen = "Screen"; + static const char* vp6 = "VP6"; + static const char* vp6_alpha = "VP6Alpha"; + static const char* screen2 = "Screen2"; + static const char* h264 = "H.264"; + static const char* unknown = "Unknown"; + + switch (codec_id) { + case 2: return h263; + case 3: return screen; + case 4: return vp6; + case 5: return vp6_alpha; + case 6: return screen2; + case 7: return h264; + default: return unknown; + } + + return unknown; +} + +char srs_get_avc_packet_type(char* data, int size) +{ + if (size < 2) { + return -1; + } + + if (!SrsFlvCodec::video_is_h264(data, size)) { + return -1; + } + + u_int8_t avc_packet_type = data[1]; + + if (avc_packet_type > 2) { + return -1; + } + + return avc_packet_type; +} + +const char* srs_avc_packet2string(char avc_packet_type) +{ + static const char* sps_pps = "SpsPps"; + static const char* nalu = "Nalu"; + static const char* sps_pps_end = "SpsPpsEnd"; + static const char* unknown = "Unknown"; + + switch (avc_packet_type) { + case 0: return sps_pps; + case 1: return nalu; + case 2: return sps_pps_end; + default: return unknown; + } + + return unknown; +} + +char srs_get_frame_type(char* data, int size) +{ + if (size < 1) { + return -1; + } + + if (!SrsFlvCodec::video_is_h264(data, size)) { + return -1; + } + + u_int8_t frame_type = data[0]; + frame_type = (frame_type >> 4) & 0x0f; + if (frame_type < 1 || frame_type > 5) { + return -1; + } + + return frame_type; +} + +const char* srs_frame_type2string(char frame_type) +{ + static const char* keyframe = "I"; + static const char* interframe = "P/B"; + static const char* disposable_interframe = "DI"; + static const char* generated_keyframe = "GI"; + static const char* video_infoframe = "VI"; + static const char* unknown = "Unknown"; + + switch (frame_type) { + case 1: return keyframe; + case 2: return interframe; + case 3: return disposable_interframe; + case 4: return generated_keyframe; + case 5: return video_infoframe; + default: return unknown; + } + + return unknown; +} + +int srs_print_rtmp_packet(char type, u_int32_t timestamp, char* data, int size) +{ + int ret = ERROR_SUCCESS; + + u_int32_t pts; + if (srs_parse_timestamp(timestamp, type, data, size, &pts) != 0) { + return ret; + } + + if (type == SRS_RTMP_TYPE_VIDEO) { + srs_lib_trace("Video packet type=%s, dts=%d, pts=%d, size=%d, %s(%s,%s)", + srs_type2string(type), timestamp, pts, size, + srs_code_id2string(srs_get_codec_id(data, size)), + srs_avc_packet2string(srs_get_avc_packet_type(data, size)), + srs_frame_type2string(srs_get_frame_type(data, size)) + ); + } else if (type == SRS_RTMP_TYPE_AUDIO) { + srs_lib_trace("Audio packet type=%s, dts=%d, pts=%d, size=%d", + srs_type2string(type), timestamp, pts, size); + } else if (type == SRS_RTMP_TYPE_SCRIPT) { + srs_lib_verbose("Data packet type=%s, time=%d, size=%d", + srs_type2string(type), timestamp, size); + int nparsed = 0; + while (nparsed < size) { + int nb_parsed_this = 0; + srs_amf0_t amf0 = srs_amf0_parse(data + nparsed, size - nparsed, &nb_parsed_this); + if (amf0 == NULL) { + break; + } + + nparsed += nb_parsed_this; + + char* amf0_str = NULL; + srs_raw_trace("%s", srs_amf0_human_print(amf0, &amf0_str, NULL)); + srs_amf0_free_bytes(amf0_str); + } + } else { + srs_lib_trace("Unknown packet type=%s, dts=%d, pts=%d, size=%d", + srs_type2string(type), timestamp, pts, size); + } + + return ret; +} + const char* srs_format_time() { struct timeval tv; @@ -1171,7 +1326,9 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) return amf0; } - *nparsed = stream.pos(); + if (nparsed) { + *nparsed = stream.pos(); + } amf0 = (srs_amf0_t)any; return amf0; @@ -1445,8 +1602,6 @@ int srs_audio_write_raw_frame(srs_rtmp_t rtmp, char sound_format, char sound_rate, char sound_size, char sound_type, char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp ) { - int ret = ERROR_SUCCESS; - Context* context = (Context*)rtmp; srs_assert(context); diff --git a/trunk/src/libs/srs_librtmp.hpp b/trunk/src/libs/srs_librtmp.hpp index 6df3be0ba..8b35f0742 100644 --- a/trunk/src/libs/srs_librtmp.hpp +++ b/trunk/src/libs/srs_librtmp.hpp @@ -273,9 +273,22 @@ extern int srs_version_revision(); * utilities ************************************************************** *************************************************************/ +/** +* get the current system time in ms. +* use gettimeofday() to get system time. +*/ extern int64_t srs_get_time_ms(); + +/** +* get the send bytes. +*/ extern int64_t srs_get_nsend_bytes(srs_rtmp_t rtmp); + +/** +* get the recv bytes. +*/ extern int64_t srs_get_nrecv_bytes(srs_rtmp_t rtmp); + /** * parse the dts and pts by time in header and data in tag, * or to parse the RTMP packet by srs_read_packet(). @@ -296,10 +309,92 @@ extern int srs_parse_timestamp( u_int32_t* ppts ); +/** +* get the CodecID of video tag. +* Codec Identifier. The following values are defined: +* 2 = Sorenson H.263 +* 3 = Screen video +* 4 = On2 VP6 +* 5 = On2 VP6 with alpha channel +* 6 = Screen video version 2 +* 7 = AVC +* @return the code id. 0 for error. +*/ +extern char srs_get_codec_id(char* data, int size); + +/** +* get the codec id string. +* H.263 = Sorenson H.263 +* Screen = Screen video +* VP6 = On2 VP6 +* VP6Alpha = On2 VP6 with alpha channel +* Screen2 = Screen video version 2 +* H.264 = AVC +* otherwise, "Unknown" +* @remark user never free the return char*, +* it's static shared const string. +*/ +extern const char* srs_code_id2string(char codec_id); + +/** +* get the AVCPacketType of video tag. +* The following values are defined: +* 0 = AVC sequence header +* 1 = AVC NALU +* 2 = AVC end of sequence (lower level NALU sequence ender is +* not required or supported) +* @return the avc packet type. -1(0xff) for error. +*/ +extern char srs_get_avc_packet_type(char* data, int size); + +/** +* get the avc packet type string. +* SpsPps = AVC sequence header +* Nalu = AVC NALU +* SpsPpsEnd = AVC end of sequence +* otherwise, "Unknown" +* @remark user never free the return char*, +* it's static shared const string. +*/ +extern const char* srs_avc_packet2string(char avc_packet_type); + +/** +* get the FrameType of video tag. +* Type of video frame. The following values are defined: +* 1 = key frame (for AVC, a seekable frame) +* 2 = inter frame (for AVC, a non-seekable frame) +* 3 = disposable inter frame (H.263 only) +* 4 = generated key frame (reserved for server use only) +* 5 = video info/command frame +* @return the frame type. 0 for error. +*/ +extern char srs_get_frame_type(char* data, int size); + +/** +* get the frame type string. +* I = key frame (for AVC, a seekable frame) +* P/B = inter frame (for AVC, a non-seekable frame) +* DI = disposable inter frame (H.263 only) +* GI = generated key frame (reserved for server use only) +* VI = video info/command frame +* otherwise, "Unknown" +* @remark user never free the return char*, +* it's static shared const string. +*/ +extern const char* srs_frame_type2string(char frame_type); + +/** +* print the rtmp packet, use srs_lib_trace/srs_lib_verbose for packet, +* and use srs_raw_trace for script data body. +* @return an error code for parse the timetstamp to dts and pts. +*/ +extern int srs_print_rtmp_packet(char type, u_int32_t timestamp, char* data, int size); + // log to console, for use srs-librtmp application. extern const char* srs_format_time(); #define srs_lib_trace(msg, ...) printf("[%s] ", srs_format_time());printf(msg, ##__VA_ARGS__);printf("\n") #define srs_lib_verbose(msg, ...) printf("[%s] ", srs_format_time());printf(msg, ##__VA_ARGS__);printf("\n") +#define srs_raw_trace(msg, ...) printf(msg, ##__VA_ARGS__) /************************************************************* ************************************************************** @@ -412,6 +507,11 @@ extern srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size); typedef void* srs_amf0_t; typedef int srs_amf0_bool; typedef double srs_amf0_number; +/** +* parse amf0 from data. +* @param nparsed, the parsed size, NULL to ignore. +* @return the parsed amf0 object. NULL for error. +*/ extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value); extern srs_amf0_t srs_amf0_create_ecma_array();