diff --git a/trunk/research/librtmp/srs_h264_raw_publish.c b/trunk/research/librtmp/srs_h264_raw_publish.c index f4326498e..df1a76c40 100644 --- a/trunk/research/librtmp/srs_h264_raw_publish.c +++ b/trunk/research/librtmp/srs_h264_raw_publish.c @@ -28,6 +28,11 @@ gcc srs_h264_raw_publish.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_h #include #include +// for open h264 raw file. +#include +#include +#include + #include "../../objs/include/srs_librtmp.h" #define srs_trace(msg, ...) printf(msg, ##__VA_ARGS__);printf("\n") @@ -40,7 +45,7 @@ int main(int argc, char** argv) if (argc <= 2) { srs_trace("Usage: %s ", argv[0]); - srs_trace(" h264_raw_file: the raw h264 steam file."); + srs_trace(" h264_raw_file: the h264 raw steam file."); srs_trace(" rtmp_publish_url: the rtmp publish url."); srs_trace("For example:"); srs_trace(" %s ./720p.h264.raw rtmp://127.0.0.1:1935/live/livestream", argv[0]); @@ -53,6 +58,14 @@ int main(int argc, char** argv) const char* rtmp_url = argv[2]; srs_trace("raw_file=%s, rtmp_url=%s", raw_file, rtmp_url); + // open file + int raw_fd = open(raw_file, O_RDONLY); + if (raw_fd < 0) { + srs_trace("open h264 raw file %s failed.", raw_fd); + goto rtmp_destroy; + } + + // connect rtmp context srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url); if (srs_simple_handshake(rtmp) != 0) { @@ -73,23 +86,42 @@ int main(int argc, char** argv) } srs_trace("publish stream success"); - u_int32_t timestamp = 0; + u_int32_t dts = 0; + u_int32_t pts = 0; for (;;) { - int type = SRS_RTMP_TYPE_VIDEO; - timestamp += 40; + // read from file, or get h264 raw data from device, whatever. int size = 4096; char* data = (char*)malloc(4096); - - if (srs_write_packet(rtmp, type, timestamp, data, size) != 0) { + if ((size = read(raw_fd, data, size)) < 0) { + srs_trace("read h264 raw data failed. nread=%d", size); goto rtmp_destroy; } - srs_trace("sent packet: type=%s, time=%d, size=%d", srs_type2string(type), timestamp, size); + if (size == 0) { + srs_trace("publish h264 raw data completed."); + goto rtmp_destroy; + } + + char* rtmp_data = NULL; + int rtmp_size = 0; + u_int32_t timestamp = 0; + if (srs_h264_to_rtmp(data, size, dts, pts, &rtmp_data, &rtmp_size, ×tamp) < 0) { + srs_trace("h264 raw data to rtmp data failed."); + goto rtmp_destroy; + } + + int type = SRS_RTMP_TYPE_VIDEO; + if (srs_write_packet(rtmp, type, timestamp, rtmp_data, rtmp_size) != 0) { + goto rtmp_destroy; + } + srs_trace("sent packet: type=%s, time=%d, size=%d", srs_type2string(type), timestamp, rtmp_size); usleep(40 * 1000); } rtmp_destroy: srs_rtmp_destroy(rtmp); + close(raw_fd); return 0; } + diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp index d1838f10e..d8eede766 100644 --- a/trunk/src/libs/srs_librtmp.cpp +++ b/trunk/src/libs/srs_librtmp.cpp @@ -996,6 +996,13 @@ char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize) return any->human_print(pdata, psize); } +int srs_h264_to_rtmp(char* h264_raw_data, int h264_raw_size, u_int32_t dts, u_int32_t pts, char** prtmp_data, int* prtmp_size, u_int32_t* ptimestamp) +{ + *prtmp_data = h264_raw_data; + *prtmp_size = h264_raw_size; + return 0; +} + #ifdef __cplusplus } #endif diff --git a/trunk/src/libs/srs_librtmp.hpp b/trunk/src/libs/srs_librtmp.hpp index 8db2adbd3..384820a91 100644 --- a/trunk/src/libs/srs_librtmp.hpp +++ b/trunk/src/libs/srs_librtmp.hpp @@ -42,6 +42,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. extern "C"{ #endif +/************************************************************* +************************************************************** +* RTMP protocol context +************************************************************** +*************************************************************/ // the RTMP handler. typedef void* srs_rtmp_t; @@ -51,7 +56,7 @@ typedef void* srs_rtmp_t; * rtmp://localhost/live/livestream * @return a rtmp handler, or NULL if error occured. */ -srs_rtmp_t srs_rtmp_create(const char* url); +extern srs_rtmp_t srs_rtmp_create(const char* url); /** * create rtmp with url, used for connection specified application. * @param url the tcUrl, for exmple: @@ -59,13 +64,18 @@ srs_rtmp_t srs_rtmp_create(const char* url); * @remark this is used to create application connection-oriented, * for example, the bandwidth client used this, no stream specified. */ -srs_rtmp_t srs_rtmp_create2(const char* url); +extern srs_rtmp_t srs_rtmp_create2(const char* url); /** * close and destroy the rtmp stack. * @remark, user should use the rtmp again. */ -void srs_rtmp_destroy(srs_rtmp_t rtmp); +extern void srs_rtmp_destroy(srs_rtmp_t rtmp); +/************************************************************* +************************************************************** +* RTMP protocol stack +************************************************************** +*************************************************************/ /** * connect and handshake with server * category: publish/play @@ -84,13 +94,13 @@ void srs_rtmp_destroy(srs_rtmp_t rtmp); * __srs_do_simple_handshake() * user can use these functions if needed. */ -int srs_simple_handshake(srs_rtmp_t rtmp); +extern int srs_simple_handshake(srs_rtmp_t rtmp); // parse uri, create socket, resolve host -int __srs_dns_resolve(srs_rtmp_t rtmp); +extern int __srs_dns_resolve(srs_rtmp_t rtmp); // connect socket to server -int __srs_connect_server(srs_rtmp_t rtmp); +extern int __srs_connect_server(srs_rtmp_t rtmp); // do simple handshake over socket. -int __srs_do_simple_handshake(srs_rtmp_t rtmp); +extern int __srs_do_simple_handshake(srs_rtmp_t rtmp); /** * connect to rtmp vhost/app @@ -99,7 +109,7 @@ int __srs_do_simple_handshake(srs_rtmp_t rtmp); * next: publish or play * @return 0, success; otherwise, failed. */ -int srs_connect_app(srs_rtmp_t rtmp); +extern int srs_connect_app(srs_rtmp_t rtmp); /** * connect to server, get the debug srs info. @@ -112,7 +122,7 @@ int srs_connect_app(srs_rtmp_t rtmp); * @param srs_id, int, debug info, client id in server log. * @param srs_pid, int, debug info, server pid in log. */ -int srs_connect_app2(srs_rtmp_t rtmp, +extern int srs_connect_app2(srs_rtmp_t rtmp, char srs_server_ip[128], char srs_server[128], char srs_primary_authors[128], char srs_version[32], int* srs_id, int* srs_pid ); @@ -124,7 +134,7 @@ int srs_connect_app2(srs_rtmp_t rtmp, * next: destroy * @return 0, success; otherwise, failed. */ -int srs_play_stream(srs_rtmp_t rtmp); +extern int srs_play_stream(srs_rtmp_t rtmp); /** * publish a live stream. @@ -133,7 +143,7 @@ int srs_play_stream(srs_rtmp_t rtmp); * next: destroy * @return 0, success; otherwise, failed. */ -int srs_publish_stream(srs_rtmp_t rtmp); +extern int srs_publish_stream(srs_rtmp_t rtmp); /** * do bandwidth check with srs server. @@ -148,7 +158,7 @@ int srs_publish_stream(srs_rtmp_t rtmp); * @param play_duration, output the play/download test duration, in ms. * @param publish_duration, output the publish/upload test duration, in ms. */ -int srs_bandwidth_check(srs_rtmp_t rtmp, +extern int srs_bandwidth_check(srs_rtmp_t rtmp, int64_t* start_time, int64_t* end_time, int* play_kbps, int* publish_kbps, int* play_bytes, int* publish_bytes, @@ -173,7 +183,7 @@ int srs_bandwidth_check(srs_rtmp_t rtmp, * @remark user never free the return char*, * it's static shared const string. */ -const char* srs_type2string(int type); +extern const char* srs_type2string(int type); /** * read a audio/video/script-data packet from rtmp stream. * @param type, output the packet type, macros: @@ -191,113 +201,144 @@ const char* srs_type2string(int type); * @remark: for read, user must free the data. * @remark: for write, user should never free the data, even if error. */ -int srs_read_packet(srs_rtmp_t rtmp, int* type, u_int32_t* timestamp, char** data, int* size); -int srs_write_packet(srs_rtmp_t rtmp, int type, u_int32_t timestamp, char* data, int size); +extern int srs_read_packet(srs_rtmp_t rtmp, + int* 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 +); -/** -* get protocol stack version -*/ -int srs_version_major(); -int srs_version_minor(); -int srs_version_revision(); +// get protocol stack version +extern int srs_version_major(); +extern int srs_version_minor(); +extern int srs_version_revision(); -/** +/************************************************************* +************************************************************** * utilities -*/ -int64_t srs_get_time_ms(); -int64_t srs_get_nsend_bytes(srs_rtmp_t rtmp); -int64_t srs_get_nrecv_bytes(srs_rtmp_t rtmp); +************************************************************** +*************************************************************/ +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); -/** + +/************************************************************* +************************************************************** * flv codec -*/ +************************************************************** +*************************************************************/ typedef void* srs_flv_t; typedef int flv_bool; /* open flv file for both read/write. */ -srs_flv_t srs_flv_open_read(const char* file); -srs_flv_t srs_flv_open_write(const char* file); -void srs_flv_close(srs_flv_t flv); +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 */ -int srs_flv_read_header(srs_flv_t flv, char header[9]); +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. */ -int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime); +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 */ -int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t 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. */ -int srs_flv_write_header(srs_flv_t flv, char header[9]); +extern int srs_flv_write_header(srs_flv_t flv, char header[9]); /* write flv tag to file, auto write the 4bytes previous tag size */ -int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int 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 */ -int srs_flv_size_tag(int data_size); +extern int srs_flv_size_tag(int data_size); /* file stream */ /* file stream tellg to get offset */ -int64_t srs_flv_tellg(srs_flv_t flv); +extern int64_t srs_flv_tellg(srs_flv_t flv); /* seek file stream, offset is form the start of file */ -void srs_flv_lseek(srs_flv_t flv, int64_t offset); +extern void srs_flv_lseek(srs_flv_t flv, int64_t offset); /* error code */ /* whether the error code indicates EOF */ -flv_bool srs_flv_is_eof(int error_code); +extern flv_bool srs_flv_is_eof(int error_code); /* media codec */ /* whether the video body is sequence header */ -flv_bool srs_flv_is_sequence_header(char* data, int32_t size); +extern flv_bool srs_flv_is_sequence_header(char* data, int32_t size); /* whether the video body is keyframe */ -flv_bool srs_flv_is_keyframe(char* data, int32_t size); +extern flv_bool srs_flv_is_keyframe(char* data, int32_t size); -/** +/************************************************************* +************************************************************** * amf0 codec -*/ +************************************************************** +*************************************************************/ /* the output handler. */ typedef void* srs_amf0_t; typedef int amf0_bool; typedef double amf0_number; -srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); -srs_amf0_t srs_amf0_create_number(amf0_number value); -srs_amf0_t srs_amf0_create_ecma_array(); -srs_amf0_t srs_amf0_create_strict_array(); -srs_amf0_t srs_amf0_create_object(); -void srs_amf0_free(srs_amf0_t amf0); -void srs_amf0_free_bytes(char* data); +extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); +extern srs_amf0_t srs_amf0_create_number(amf0_number value); +extern srs_amf0_t srs_amf0_create_ecma_array(); +extern srs_amf0_t srs_amf0_create_strict_array(); +extern srs_amf0_t srs_amf0_create_object(); +extern void srs_amf0_free(srs_amf0_t amf0); +extern void srs_amf0_free_bytes(char* data); /* size and to bytes */ -int srs_amf0_size(srs_amf0_t amf0); -int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); +extern int srs_amf0_size(srs_amf0_t amf0); +extern int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); /* type detecter */ -amf0_bool srs_amf0_is_string(srs_amf0_t amf0); -amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); -amf0_bool srs_amf0_is_number(srs_amf0_t amf0); -amf0_bool srs_amf0_is_null(srs_amf0_t amf0); -amf0_bool srs_amf0_is_object(srs_amf0_t amf0); -amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0); -amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0); +extern amf0_bool srs_amf0_is_string(srs_amf0_t amf0); +extern amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); +extern amf0_bool srs_amf0_is_number(srs_amf0_t amf0); +extern amf0_bool srs_amf0_is_null(srs_amf0_t amf0); +extern amf0_bool srs_amf0_is_object(srs_amf0_t amf0); +extern amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0); +extern amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0); /* value converter */ -const char* srs_amf0_to_string(srs_amf0_t amf0); -amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0); -amf0_number srs_amf0_to_number(srs_amf0_t amf0); +extern const char* srs_amf0_to_string(srs_amf0_t amf0); +extern amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0); +extern amf0_number srs_amf0_to_number(srs_amf0_t amf0); /* value setter */ -void srs_amf0_set_number(srs_amf0_t amf0, amf0_number value); +extern void srs_amf0_set_number(srs_amf0_t amf0, amf0_number value); /* object value converter */ -int srs_amf0_object_property_count(srs_amf0_t amf0); -const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); -srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); -srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); -void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); -void srs_amf0_object_clear(srs_amf0_t amf0); +extern int srs_amf0_object_property_count(srs_amf0_t amf0); +extern const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); +extern srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); +extern srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); +extern void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); +extern void srs_amf0_object_clear(srs_amf0_t amf0); /* ecma array value converter */ -int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); -const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); -srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); -srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); -void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); +extern int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); +extern const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); +extern srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); +extern srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); +extern void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); /* strict array value converter */ -int srs_amf0_strict_array_property_count(srs_amf0_t amf0); -srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); -void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); +extern int srs_amf0_strict_array_property_count(srs_amf0_t amf0); +extern srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); +extern void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); /** * human readable print * @param pdata, output the heap data, NULL to ignore. * user must use srs_amf0_free_bytes to free it. * @return return the *pdata for print. NULL to ignore. */ -char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize); +extern char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize); + +/************************************************************* +************************************************************** +* h264 raw codec +************************************************************** +*************************************************************/ +/** +convert h264 stream data to rtmp packet. +@param h264_raw_data the input h264 raw data, a encoded h.264 I/P/B frame data. +@paam h264_raw_size the size of h264 raw data. +@param dts the dts of h.264 raw data. +@param pts the pts of h.264 raw data. +@param prtmp_data the output rtmp format packet, which can be send by srs_write_packet. +@param prtmp_size the size of rtmp packet, for srs_write_packet. +@param ptimestamp the timestamp of rtmp packet, for srs_write_packet. +*/ +extern int srs_h264_to_rtmp( + char* h264_raw_data, int h264_raw_size, u_int32_t dts, u_int32_t pts, + char** prtmp_data, int* prtmp_size, u_int32_t* ptimestamp +); #ifdef __cplusplus }