mirror of
https://github.com/ossrs/srs.git
synced 2025-02-14 12:21:55 +00:00
refine examples of srs-librtmp, add srs_print_rtmp_packet. 2.0.28.
This commit is contained in:
parent
a058eeeb20
commit
d9474d7600
8 changed files with 284 additions and 101 deletions
|
@ -482,6 +482,7 @@ Supported operating systems and hardware:
|
|||
* 2013-10-17, Created.<br/>
|
||||
|
||||
## 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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue