diff --git a/trunk/research/librtmp/srs_bandwidth_check.c b/trunk/research/librtmp/srs_bandwidth_check.c index 3ce5d66eb..84666a4ab 100644 --- a/trunk/research/librtmp/srs_bandwidth_check.c +++ b/trunk/research/librtmp/srs_bandwidth_check.c @@ -35,9 +35,10 @@ int main(int argc, char** argv) srs_rtmp_t rtmp; // packet data - int type, size; - u_int32_t timestamp = 0; + int size; + char type; char* data; + u_int32_t timestamp; // srs debug info. char srs_server_ip[128]; diff --git a/trunk/research/librtmp/srs_detect_rtmp.c b/trunk/research/librtmp/srs_detect_rtmp.c index a1b12d121..083392f26 100644 --- a/trunk/research/librtmp/srs_detect_rtmp.c +++ b/trunk/research/librtmp/srs_detect_rtmp.c @@ -49,10 +49,11 @@ int main(int argc, char** argv) int64_t bytes_nrecv = 0; // packet data - int type, size; - u_int32_t basetime = 0; - u_int32_t timestamp = 0; + int size; + char type; char* data; + u_int32_t timestamp; + u_int32_t basetime = 0; // user options const char* rtmp_url = NULL; diff --git a/trunk/research/librtmp/srs_flv_parser.c b/trunk/research/librtmp/srs_flv_parser.c index fa4acd86a..22108d522 100644 --- a/trunk/research/librtmp/srs_flv_parser.c +++ b/trunk/research/librtmp/srs_flv_parser.c @@ -125,7 +125,7 @@ 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, char* data, int size, int64_t offset) +int parse_script_data(u_int32_t timestamp, u_int32_t pts, char* data, int size, int64_t offset) { int ret = 0; @@ -152,10 +152,10 @@ int parse_script_data(u_int32_t timestamp, char* data, int size, int64_t offset) } amf0_data = srs_amf0_parse(data + nparsed, size - nparsed, &nparsed); - srs_lib_trace("packet type=%s, time=%d, size=%d, data-size=%d, \n" + 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, size + FLV_HEADER_SIZE, size, - (int)offset, hbuf, tbuf, + 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)); @@ -168,7 +168,7 @@ int parse_script_data(u_int32_t timestamp, char* data, int size, int64_t offset) return ret; } -int parse_audio_data(u_int32_t timestamp, char* data, int size, int64_t offset) +int parse_audio_data(u_int32_t timestamp, u_int32_t pts, char* data, int size, int64_t offset) { int ret = 0; @@ -178,15 +178,15 @@ int parse_audio_data(u_int32_t timestamp, char* data, int size, int64_t offset) // bytes parse_bytes(data, size, hbuf, sizeof(hbuf), tbuf, sizeof(tbuf), 16); - srs_lib_trace("packet type=%s, time=%d, size=%d, data-size=%d, \n" + 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, size + FLV_HEADER_SIZE, size, - (int)offset, hbuf, tbuf); + 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, char* data, int size, int64_t offset) +int parse_video_data(u_int32_t timestamp, u_int32_t pts, char* data, int size, int64_t offset) { int ret = 0; @@ -196,10 +196,10 @@ int parse_video_data(u_int32_t timestamp, char* data, int size, int64_t offset) // bytes parse_bytes(data, size, hbuf, sizeof(hbuf), tbuf, sizeof(tbuf), 16); - srs_lib_trace("packet type=%s, time=%d, size=%d, data-size=%d, \n" + 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, size + FLV_HEADER_SIZE, size, - (int)offset, hbuf, tbuf); + srs_type2string(SRS_RTMP_TYPE_VIDEO), timestamp, pts, + size + FLV_HEADER_SIZE, size, (int)offset, hbuf, tbuf); return ret; } @@ -240,27 +240,27 @@ 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) { - return ret; - } - // data tag - if (type == SRS_RTMP_TYPE_AUDIO) { - if ((ret = parse_audio_data(timestamp, data, size, offset)) != 0) { - return ret; - } - } else if (type == SRS_RTMP_TYPE_VIDEO) { - if ((ret = parse_video_data(timestamp, data, size, offset)) != 0) { - return ret; - } - } else { - if ((ret = parse_script_data(timestamp, data, size, offset)) != 0) { - return ret; + 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); + } else { + ret = parse_script_data(timestamp, pts, data, size, offset); } } free(data); + + if (ret != 0) { + srs_lib_trace("parse failed, ret=%d", ret); + return ret; + } } return ret; diff --git a/trunk/research/librtmp/srs_ingest_rtmp.c b/trunk/research/librtmp/srs_ingest_rtmp.c index 48a370238..3bec458c6 100644 --- a/trunk/research/librtmp/srs_ingest_rtmp.c +++ b/trunk/research/librtmp/srs_ingest_rtmp.c @@ -94,9 +94,10 @@ int proxy(srs_rtmp_t irtmp, srs_rtmp_t ortmp) int ret = 0; // packet data - int type, size; - u_int32_t timestamp = 0; - char* data = NULL; + int size; + char type; + char* data; + u_int32_t timestamp; if ((ret = connect_ic(irtmp)) != 0) { return ret; diff --git a/trunk/research/librtmp/srs_play.c b/trunk/research/librtmp/srs_play.c index 1106f3a22..0b0410474 100644 --- a/trunk/research/librtmp/srs_play.c +++ b/trunk/research/librtmp/srs_play.c @@ -66,15 +66,19 @@ int main(int argc, char** argv) srs_lib_trace("play stream success"); for (;;) { - int type, size; - u_int32_t timestamp = 0; + int size; + char type; char* data; + u_int32_t timestamp, pts; if (srs_read_packet(rtmp, &type, ×tamp, &data, &size) != 0) { goto rtmp_destroy; } - srs_lib_trace("got packet: type=%s, time=%d, size=%d", - srs_type2string(type), timestamp, size); + if (srs_parse_timestamp(timestamp, type, data, size, &pts) != 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/research/librtmp/srs_publish.c b/trunk/research/librtmp/srs_publish.c index 0865a4b98..beea77692 100644 --- a/trunk/research/librtmp/srs_publish.c +++ b/trunk/research/librtmp/srs_publish.c @@ -75,7 +75,7 @@ int main(int argc, char** argv) u_int32_t timestamp = 0; for (;;) { - int type = SRS_RTMP_TYPE_VIDEO; + char type = SRS_RTMP_TYPE_VIDEO; int size = 4096; char* data = (char*)malloc(4096); diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index d7450a9e6..d344ceac1 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 18 +#define VERSION_REVISION 19 // server info. #define RTMP_SIG_SRS_KEY "SRS" #define RTMP_SIG_SRS_ROLE "origin/edge server" diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 21ca885de..d9997c16c 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -185,6 +185,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_EDGE_VHOST_REMOVED 3039 #define ERROR_HLS_AVC_TRY_OTHERS 3040 #define ERROR_H264_API_NO_PREFIXED 3041 +#define ERROR_FLV_INVALID_VIDEO_TAG 3042 /** * whether the error code is an system control error. diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp index 38e75542c..afa018b55 100644 --- a/trunk/src/libs/srs_librtmp.cpp +++ b/trunk/src/libs/srs_librtmp.cpp @@ -337,7 +337,7 @@ int srs_publish_stream(srs_rtmp_t rtmp) return ret; } -const char* srs_type2string(int type) +const char* srs_type2string(char type) { static const char* audio = "Audio"; static const char* video = "Video"; @@ -390,7 +390,7 @@ int srs_bandwidth_check(srs_rtmp_t rtmp, return ret; } -int srs_read_packet(srs_rtmp_t rtmp, int* type, u_int32_t* timestamp, char** data, int* size) +int srs_read_packet(srs_rtmp_t rtmp, char* type, u_int32_t* timestamp, char** data, int* size) { *type = 0; *timestamp = 0; @@ -445,7 +445,7 @@ int srs_read_packet(srs_rtmp_t rtmp, int* type, u_int32_t* timestamp, char** dat return ret; } -int srs_write_packet(srs_rtmp_t rtmp, int type, u_int32_t timestamp, char* data, int size) +int srs_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char* data, int size) { int ret = ERROR_SUCCESS; @@ -531,6 +531,47 @@ int64_t srs_get_nrecv_bytes(srs_rtmp_t rtmp) return context->rtmp->get_recv_bytes(); } +int srs_parse_timestamp( + u_int32_t time, char type, char* data, int size, + u_int32_t* ppts +) { + int ret = ERROR_SUCCESS; + + if (type != SRS_RTMP_TYPE_VIDEO) { + *ppts = time; + return ret; + } + + if (!SrsFlvCodec::video_is_h264(data, size)) { + return ERROR_FLV_INVALID_VIDEO_TAG; + } + + if (SrsFlvCodec::video_is_sequence_header(data, size)) { + *ppts = time; + return ret; + } + + // 1bytes, frame type and codec id. + // 1bytes, avc packet type. + // 3bytes, cts, composition time, + // pts = dts + cts, or + // cts = pts - dts. + if (size < 5) { + return ERROR_FLV_INVALID_VIDEO_TAG; + } + + u_int32_t cts = 0; + char* p = data + 2; + char* pp = (char*)&cts; + pp[2] = *p++; + pp[1] = *p++; + pp[0] = *p++; + + *ppts = time + cts; + + return ret; +} + const char* srs_format_time() { struct timeval tv; diff --git a/trunk/src/libs/srs_librtmp.hpp b/trunk/src/libs/srs_librtmp.hpp index 9eccd7511..65c1eb756 100644 --- a/trunk/src/libs/srs_librtmp.hpp +++ b/trunk/src/libs/srs_librtmp.hpp @@ -192,7 +192,7 @@ extern int srs_bandwidth_check(srs_rtmp_t rtmp, * @remark user never free the return char*, * it's static shared const string. */ -extern const char* srs_type2string(int type); +extern const char* srs_type2string(char type); /** * read a audio/video/script-data packet from rtmp stream. * @param type, output the packet type, macros: @@ -215,10 +215,10 @@ extern const char* srs_type2string(int type); * @return 0, success; otherswise, failed. */ extern int srs_read_packet(srs_rtmp_t rtmp, - int* type, u_int32_t* timestamp, char** data, int* size + char* type, u_int32_t* timestamp, char** data, int* size ); extern int srs_write_packet(srs_rtmp_t rtmp, - int type, u_int32_t timestamp, char* data, int size + char type, u_int32_t timestamp, char* data, int size ); // get protocol stack version @@ -234,6 +234,25 @@ extern int srs_version_revision(); extern int64_t srs_get_time_ms(); extern int64_t srs_get_nsend_bytes(srs_rtmp_t rtmp); 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(). +* +* @param time, the timestamp of tag, read by srs_flv_read_tag_header(). +* @param type, the type of tag, read by srs_flv_read_tag_header(). +* @param data, the data of tag, read by srs_flv_read_tag_data(). +* @param size, the size of tag, read by srs_flv_read_tag_header(). +* @param ppts, output the pts in ms, +* +* @return 0, success; otherswise, failed. +* @remark, the dts always equals to @param time. +* @remark, the pts=dts for audio or data. +* @remark, video only support h.264. +*/ +extern int srs_parse_timestamp( + u_int32_t time, char type, char* data, int size, + u_int32_t* ppts +); // log to console, for use srs-librtmp application. extern const char* srs_format_time(); @@ -255,19 +274,68 @@ typedef int flv_bool; extern srs_flv_t srs_flv_open_read(const char* file); extern srs_flv_t srs_flv_open_write(const char* file); extern void srs_flv_close(srs_flv_t flv); -/* read the flv header. 9bytes header. drop the 4bytes zero previous tag size */ +/** +* read the flv header. 9bytes header. +* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. +* 3bytes, signature, "FLV", +* 1bytes, version, 0x01, +* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. +* 4bytes, dataoffset, 0x09, The length of this header in bytes +* +* @return 0, success; otherswise, failed. +* @remark, drop the 4bytes zero previous tag size. +*/ extern int srs_flv_read_header(srs_flv_t flv, char header[9]); -/* read the flv tag header, 1bytes tag, 3bytes data_size, 4bytes time, 3bytes stream id. */ +/** +* read the flv tag header, 1bytes tag, 3bytes data_size, +* 4bytes time, 3bytes stream id. +* @param ptype, output the type of tag, macros: +* SRS_RTMP_TYPE_AUDIO, FlvTagAudio +* SRS_RTMP_TYPE_VIDEO, FlvTagVideo +* SRS_RTMP_TYPE_SCRIPT, FlvTagScript +* @param pdata_size, output the size of tag data. +* @param ptime, output the time of tag, the dts in ms. +* +* @return 0, success; otherswise, failed. +* @remark, user must ensure the next is a tag, srs never check it. +*/ extern int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime ); -/* read the tag data. drop the 4bytes previous tag size */ +/** +* read the tag data. drop the 4bytes previous tag size +* @param data, the data to read, user alloc and free it. +* @param size, the size of data to read, get by srs_flv_read_tag_header(). +* @remark, srs will ignore and drop the 4bytes previous tag size. +*/ extern int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); -/* write flv header to file, auto write the 4bytes zero previous tag size. */ +/** +* write the flv header. 9bytes header. +* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. +* 3bytes, signature, "FLV", +* 1bytes, version, 0x01, +* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. +* 4bytes, dataoffset, 0x09, The length of this header in bytes +* +* @return 0, success; otherswise, failed. +* @remark, auto write the 4bytes zero previous tag size. +*/ extern int srs_flv_write_header(srs_flv_t flv, char header[9]); +/** +* write the flv tag to file. +* +* @return 0, success; otherswise, failed. +* @remark, auto write the 4bytes zero previous tag size. +*/ /* write flv tag to file, auto write the 4bytes previous tag size */ -extern int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size); -/* get the tag size, for flv injecter to adjust offset, size=tag_header+data+previous_tag */ +extern int srs_flv_write_tag(srs_flv_t flv, + char type, int32_t time, char* data, int size +); +/** +* get the tag size, for flv injecter to adjust offset, +* size = tag_header(11B) + data_size + previous_tag(4B) +* @return the size of tag. +*/ extern int srs_flv_size_tag(int data_size); /* file stream */ /* file stream tellg to get offset */ @@ -278,9 +346,17 @@ extern void srs_flv_lseek(srs_flv_t flv, int64_t offset); /* whether the error code indicates EOF */ extern flv_bool srs_flv_is_eof(int error_code); /* media codec */ -/* whether the video body is sequence header */ +/** +* whether the video body is sequence header +* @param data, the data of tag, read by srs_flv_read_tag_data(). +* @param size, the size of tag, read by srs_flv_read_tag_data(). +*/ extern flv_bool srs_flv_is_sequence_header(char* data, int32_t size); -/* whether the video body is keyframe */ +/** +* whether the video body is keyframe +* @param data, the data of tag, read by srs_flv_read_tag_data(). +* @param size, the size of tag, read by srs_flv_read_tag_data(). +*/ extern flv_bool srs_flv_is_keyframe(char* data, int32_t size); /*************************************************************