winlin

add api convert h264 to rtmp packet, for bug #66

... ... @@ -28,6 +28,11 @@ gcc srs_h264_raw_publish.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_h
#include <stdlib.h>
#include <unistd.h>
// for open h264 raw file.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#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 <h264_raw_file> <rtmp_publish_url>", 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 ((size = read(raw_fd, data, size)) < 0) {
srs_trace("read h264 raw data failed. nread=%d", size);
goto rtmp_destroy;
}
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, &timestamp) < 0) {
srs_trace("h264 raw data to rtmp data failed.");
goto rtmp_destroy;
}
if (srs_write_packet(rtmp, type, timestamp, data, size) != 0) {
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, size);
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;
}
... ...
... ... @@ -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
... ...
... ... @@ -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
}
... ...