diff --git a/trunk/research/librtmp/srs_h264_raw_publish.c b/trunk/research/librtmp/srs_h264_raw_publish.c index b0b6d7379..6af340f8a 100644 --- a/trunk/research/librtmp/srs_h264_raw_publish.c +++ b/trunk/research/librtmp/srs_h264_raw_publish.c @@ -37,6 +37,40 @@ gcc srs_h264_raw_publish.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_h #define srs_trace(msg, ...) printf(msg, ##__VA_ARGS__);printf("\n") +int read_h264_frame(char* data, int size, char** p, int fps, + char** frame, int* frame_size, int* dts, int* pts) +{ + // @remark, for this demo, to publish h264 raw file to SRS, + // we search the h264 frame from the buffer which cached the h264 data. + // please get h264 raw data from device, it always a encoded frame. + int pnb_start_code = 0; + if (!srs_h264_startswith_annexb(*p, size - (*p - data), &pnb_start_code)) { + srs_trace("h264 raw data invalid."); + return -1; + } + *p += pnb_start_code; + + *frame = *p; + for (;*p < data + size; *p = *p + 1) { + if (srs_h264_startswith_annexb(*p, size - (*p - data), &pnb_start_code)) { + break; + } + } + *frame_size = *p - *frame; + if (*frame_size <= 0) { + srs_trace("h264 raw data invalid."); + return -1; + } + + // @remark, please get the dts and pts from device, + // we assume there is no B frame, and the fps can guess the fps and dts, + // while the dts and pts must read from encode lib or device. + *dts += 1000 / fps; + *pts = *dts; + + return 0; +} + int main(int argc, char** argv) { srs_trace("publish raw h.264 as rtmp stream to server like FMLE/FFMPEG/Encoder"); @@ -107,24 +141,22 @@ int main(int argc, char** argv) } srs_trace("publish stream success"); + u_int32_t dts = 0; + u_int32_t pts = 0; // @remark, the dts and pts if read from device, for instance, the encode lib, // so we assume the fps is 25, and each h264 frame is 1000ms/25fps=40ms/f. u_int32_t fps = 25; - u_int32_t dts = 0; - u_int32_t pts = 0; - for (;;) { - // 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); + // @remark, to decode the file. + char* p = h264_raw; + for (;p < h264_raw + file_size;) { + // @remark, read a frame from file buffer. + char* data = NULL; + int size = 0; + if (read_h264_frame(h264_raw, file_size, &p, fps, &data, &size, &dts, &pts) < 0) { + srs_trace("read a frame from file buffer failed."); goto rtmp_destroy; } - if (size == 0) { - srs_trace("publish h264 raw data completed."); - goto rtmp_destroy; - } - + // convert the h264 packet to rtmp packet. char* rtmp_data = NULL; int rtmp_size = 0; @@ -142,15 +174,10 @@ int main(int argc, char** argv) srs_trace("sent packet: type=%s, time=%d, size=%d, fps=%d", srs_type2string(type), timestamp, rtmp_size, fps); - // @remark, please get the dts and pts from device, - // we assume there is no B frame, and the fps can guess the fps and dts, - // while the dts and pts must read from encode lib or device. - dts += 1000 / fps; - pts = dts; - // @remark, when use encode device, it not need to sleep. usleep(1000 / fps * 1000); } + srs_trace("h264 raw data completed"); rtmp_destroy: srs_rtmp_destroy(rtmp); diff --git a/trunk/src/app/srs_app_avc_aac.cpp b/trunk/src/app/srs_app_avc_aac.cpp index 4c0f2843e..3f5ce2cb0 100644 --- a/trunk/src/app/srs_app_avc_aac.cpp +++ b/trunk/src/app/srs_app_avc_aac.cpp @@ -28,6 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include SrsCodecSampleUnit::SrsCodecSampleUnit() { diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index c11716e75..f6253747e 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -107,35 +107,6 @@ int srs_get_log_level(string level) } } -bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code) -{ - char* bytes = stream->data() + stream->pos(); - char* p = bytes; - - for (;;) { - if (!stream->require(p - bytes + 3)) { - return false; - } - - // not match - if (p[0] != 0x00 || p[1] != 0x00) { - return false; - } - - // match N[00] 00 00 01, where N>=0 - if (p[2] == 0x01) { - if (pnb_start_code) { - *pnb_start_code = (int)(p - bytes) + 3; - } - return true; - } - - p++; - } - - return false; -} - static SrsRusage _srs_system_rusage; SrsRusage::SrsRusage() diff --git a/trunk/src/app/srs_app_utility.hpp b/trunk/src/app/srs_app_utility.hpp index a310483b6..1a546fab0 100644 --- a/trunk/src/app/srs_app_utility.hpp +++ b/trunk/src/app/srs_app_utility.hpp @@ -50,15 +50,6 @@ extern int srs_socket_connect(std::string server, int port, int64_t timeout, st_ */ extern int srs_get_log_level(std::string level); -/** -* whether stream starts with the avc NALU in "AnnexB" -* from H.264-AVC-ISO_IEC_14496-10.pdf, page 211. -* start code must be "N[00] 00 00 01" where N>=0 -* @param pnb_start_code output the size of start code, must >=3. -* NULL to ignore. -*/ -extern bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code = NULL); - // current process resouce usage. // @see: man getrusage class SrsRusage diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp index 1de6c2eb3..7be8f4fb6 100644 --- a/trunk/src/libs/srs_librtmp.cpp +++ b/trunk/src/libs/srs_librtmp.cpp @@ -998,11 +998,24 @@ char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* 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_data = new char[h264_raw_size]; + memcpy(*prtmp_data, h264_raw_data, h264_raw_size); + *prtmp_size = h264_raw_size; + return 0; } +int srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code) +{ + SrsStream stream; + if (stream.initialize(h264_raw_data, h264_raw_size) != ERROR_SUCCESS) { + return false; + } + + return srs_avc_startswith_annexb(&stream, pnb_start_code); +} + #ifdef __cplusplus } #endif diff --git a/trunk/src/libs/srs_librtmp.hpp b/trunk/src/libs/srs_librtmp.hpp index f6e988fae..744d36eea 100644 --- a/trunk/src/libs/srs_librtmp.hpp +++ b/trunk/src/libs/srs_librtmp.hpp @@ -337,22 +337,37 @@ extern char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize); ************************************************************** *************************************************************/ /** -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. -@remark, user should never free the h264_raw_data. -@remark, user should free the prtmp_data if success. -@return 0, success; otherswise, failed. +* 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. +* @remark, user should free the h264_raw_data. +* @remark, user should free the prtmp_data if success. +* +* @return 0, success; otherswise, failed. */ 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 ); +/** +* whether h264 raw data starts with the annexb, +* which bytes sequence matches N[00] 00 00 01, where N>=0. +* @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 pnb_start_code output the size of start code, must >=3. +* NULL to ignore. +* +* @return 0 false; otherwise, true. +*/ +extern int srs_h264_startswith_annexb( + char* h264_raw_data, int h264_raw_size, + int* pnb_start_code +); #ifdef __cplusplus } diff --git a/trunk/src/rtmp/srs_protocol_utility.cpp b/trunk/src/rtmp/srs_protocol_utility.cpp index ccf99b8d5..a4ee30e56 100644 --- a/trunk/src/rtmp/srs_protocol_utility.cpp +++ b/trunk/src/rtmp/srs_protocol_utility.cpp @@ -28,6 +28,7 @@ using namespace std; #include #include +#include void srs_discovery_tc_url( string tcUrl, @@ -155,3 +156,32 @@ bool srs_bytes_equals(void* pa, void* pb, int size) return true; } +bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code) +{ + char* bytes = stream->data() + stream->pos(); + char* p = bytes; + + for (;;) { + if (!stream->require(p - bytes + 3)) { + return false; + } + + // not match + if (p[0] != 0x00 || p[1] != 0x00) { + return false; + } + + // match N[00] 00 00 01, where N>=0 + if (p[2] == 0x01) { + if (pnb_start_code) { + *pnb_start_code = (int)(p - bytes) + 3; + } + return true; + } + + p++; + } + + return false; +} + diff --git a/trunk/src/rtmp/srs_protocol_utility.hpp b/trunk/src/rtmp/srs_protocol_utility.hpp index 359c4f26e..b4293ab10 100644 --- a/trunk/src/rtmp/srs_protocol_utility.hpp +++ b/trunk/src/rtmp/srs_protocol_utility.hpp @@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +class SrsStream; + /** * parse the tcUrl, output the schema, host, vhost, app and port. * @param tcUrl, the input tcUrl, for example, @@ -85,5 +87,14 @@ extern std::string srs_generate_tc_url( */ extern bool srs_bytes_equals(void* pa, void* pb, int size); +/** +* whether stream starts with the avc NALU in "AnnexB" +* from H.264-AVC-ISO_IEC_14496-10.pdf, page 211. +* start code must be "N[00] 00 00 01" where N>=0 +* @param pnb_start_code output the size of start code, must >=3. +* NULL to ignore. +*/ +extern bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code = NULL); + #endif