diff --git a/flv/FLV.go b/flv/FLV.go index 4e40b7ec..a3fd8640 100644 --- a/flv/FLV.go +++ b/flv/FLV.go @@ -18,6 +18,7 @@ const ( H264 = 7 AVCNALU = 1 DataHeaderLength = 5 + NoTimestampExtension = 0 ) type Header struct { diff --git a/generator/FLVGenerator.go b/generator/FLVGenerator.go index ea367ecd..c1d77c77 100644 --- a/generator/FLVGenerator.go +++ b/generator/FLVGenerator.go @@ -72,7 +72,7 @@ func (g *flvGenerator) generate() { TagType: uint8(flv.VideoTagType), DataSize: uint32(len(videoFrame)) + flv.DataHeaderLength, Timestamp: g.getNextTimestamp(), - TimestampExtended: 0, + TimestampExtended: flv.NoTimestampExtension, FrameType: flv.KeyFrameType, Codec: flv.H264, PacketType: flv.AVCNALU, diff --git a/rtmp/RTMP.go b/rtmp/RTMP.go new file mode 100644 index 00000000..e8f11cde --- /dev/null +++ b/rtmp/RTMP.go @@ -0,0 +1,16 @@ +package rtmp + +// #include "libRTMPWrapper.h" +import "C" + +type rtmpSession struct { + +} + +type RTMPSession interface { + +} + +func NewRTMPSession() (session *rtmpSession){ + +} diff --git a/rtmp/RTMPWrapper.c b/rtmp/RTMPWrapper.c new file mode 100644 index 00000000..260d9581 --- /dev/null +++ b/rtmp/RTMPWrapper.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include + +#include "rtmp_c/librtmp/rtmp_sys.h" +#include "rtmp_c/librtmp/log.h" +#include "lwlog/lwlog.h" + +#define HTON16(x) ((x>>8&0xff)|(x<<8&0xff00)) +#define HTON24(x) ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00)) +#define HTON32(x) ((x>>24&0xff)|(x>>8&0xff00)|\ + (x<<8&0xff0000)|(x<<24&0xff000000)) +#define HTONTIME(x) ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00)|(x&0xff000000)) + +/*read 1 byte*/ +int ReadU8(uint32_t *u8, FILE *fp) { + if (fread(u8, 1, 1, fp) != 1) { + return 0; + } + return 1; +} + +/*read 2 byte*/ +int ReadU16(uint32_t *u16, FILE *fp) { + if (fread(u16, 2, 1, fp) != 1) { + return 0; + } + *u16 = HTON16(*u16); + return 1; +} + +/*read 3 byte*/ +int ReadU24(uint32_t *u24, FILE *fp) { + if (fread(u24, 3, 1, fp) != 1) { + return 0; + } + *u24 = HTON24(*u24); + return 1; +} + +/*read 4 byte*/ +int ReadU32(uint32_t *u32, FILE *fp) { + if (fread(u32, 4, 1, fp) != 1) { + return 0; + } + *u32 = HTON32(*u32); + return 1; +} + +/*read 1 byte,and loopback 1 byte at once*/ +int PeekU8(uint32_t *u8, FILE *fp) { + if (fread(u8, 1, 1, fp) != 1) { + return 0; + } + fseek(fp, -1, SEEK_CUR); + return 1; +} + +/*read 4 byte and convert to time format*/ +int ReadTime(uint32_t *utime, FILE *fp) { + if (fread(utime, 4, 1, fp) != 1) { + return 0; + } + *utime = HTONTIME(*utime); + return 1; +} + +//Publish using RTMP_Write() +int publish_using_write() { + uint32_t start_time = 0; + uint32_t now_time = 0; + uint32_t pre_frame_time = 0; + uint32_t lasttime = 0; + int b_next_is_key = 0; + char *p_file_buf = NULL; + + //read from tag header + uint32_t type = 0; + uint32_t datalength = 0; + uint32_t timestamp = 0; + + RTMP *rtmp = NULL; + + FILE *fp = NULL; + fp = fopen("../cuc_ieschool.flv", "rb"); + if (NULL == fp) { + RTMP_LogPrintf("Open File Error.\n"); + return -1; + } + + /* set log level */ + //RTMP_LogLevel loglvl=RTMP_LOGDEBUG; + //RTMP_LogSetLevel(loglvl); + + rtmp = RTMP_Alloc(); + RTMP_Init(rtmp); + //set connection timeout,default 30s + rtmp->Link.timeout = 5; + if (!RTMP_SetupURL(rtmp, "rtmp://localhost/live/inrtmp")) { + RTMP_Log(RTMP_LOGERROR, "SetupURL Err\n"); + RTMP_Free(rtmp); + return -1; + } + + RTMP_EnableWrite(rtmp); + //1hour + RTMP_SetBufferMS(rtmp, 3600 * 1000); + if (!RTMP_Connect(rtmp, NULL)) { + RTMP_Log(RTMP_LOGERROR, "Connect Err\n"); + RTMP_Free(rtmp); + return -1; + } + + if (!RTMP_ConnectStream(rtmp, 0)) { + RTMP_Log(RTMP_LOGERROR, "ConnectStream Err\n"); + RTMP_Close(rtmp); + RTMP_Free(rtmp); + return -1; + } + + lwlog_info("Start to send data ..."); + + //jump over FLV Header + fseek(fp, 9, SEEK_SET); + //jump over previousTagSizen + fseek(fp, 4, SEEK_CUR); + start_time = RTMP_GetTime(); + while (1) { + if ((((now_time = RTMP_GetTime()) - start_time) + < (pre_frame_time)) && b_next_is_key) { + //wait for 1 sec if the send process is too fast + //this mechanism is not very good,need some improvement + if (pre_frame_time > lasttime) { + RTMP_LogPrintf("TimeStamp:%8u ms\n", pre_frame_time); + lasttime = pre_frame_time; + } + sleep(1); + continue; + } + + //jump over type + fseek(fp, 1, SEEK_CUR); + if (!ReadU24(&datalength, fp)) { + break; + } + if (!ReadTime(×tamp, fp)) { + break; + } + //jump back + fseek(fp, -8, SEEK_CUR); + + p_file_buf = (char *) malloc(11 + datalength + 4); + memset(p_file_buf, 0, 11 + datalength + 4); + if (fread(p_file_buf, 1, 11 + datalength + 4, fp) != (11 + datalength + 4)) { + break; + } + + pre_frame_time = timestamp; + + if (!RTMP_IsConnected(rtmp)) { + RTMP_Log(RTMP_LOGERROR, "rtmp is not connect\n"); + break; + } + if (!RTMP_Write(rtmp, p_file_buf, 11 + datalength + 4)) { + RTMP_Log(RTMP_LOGERROR, "Rtmp Write Error\n"); + break; + } + + free(p_file_buf); + p_file_buf = NULL; + + if (!PeekU8(&type, fp)) { + break; + } + if (0x09 == type) { + if (fseek(fp, 11, SEEK_CUR) != 0) { + break; + } + if (!PeekU8(&type, fp)) { + break; + } + if (type == 0x17) { + b_next_is_key = 1; + } else { + b_next_is_key = 0; + } + fseek(fp, -11, SEEK_CUR); + } + } + + RTMP_LogPrintf("\nSend Data Over\n"); + + if (fp != NULL) { + fclose(fp); + fp = NULL; + } + + if (rtmp != NULL) { + RTMP_Close(rtmp); + RTMP_Free(rtmp); + rtmp = NULL; + } + + if (p_file_buf != NULL) { + free(p_file_buf); + p_file_buf = NULL; + } + + return 0; +} diff --git a/rtmp/RTMPWrapper.h b/rtmp/RTMPWrapper.h new file mode 100644 index 00000000..e69de29b