看了雷博的一篇关于rtmp的文章,学习记录以作备忘。
使用librtmp接收RTMP流的函数执行流程图如下图:
流程图中关键函数的作用如下所列:
InitSockets():初始化Socket
RTMP_Alloc():为结构体“RTMP”分配内存。
RTMP_Init():初始化结构体“RTMP”中的成员变量。
RTMP_SetupURL():设置输入的RTMP连接的URL。
RTMP_Connect():建立RTMP连接,创建一个RTMP协议规范中的NetConnection。
RTMP_ConnectStream():创建一个RTMP协议规范中的NetStream。
RTMP_Read():从服务器读取数据。
RTMP_Close():关闭RTMP连接。
RTMP_Free():释放结构体“RTMP”。
CleanupSockets():关闭Socket。
其中NetStream和NetConnection是RTMP协议规范中的两个逻辑结构。NetStream建立在NetConnection之上。一个NetConnection可以包含多个NetStream。它们之间的关系如下图所示:
源代码rtmp2flv.c:
#include #include #include "librtmp/rtmp_sys.h"
#include "librtmp/log.h"
#include "librtmp/rtmp.h"
int InitSockets()
{
#if 0
WORD version;
WSADATA wsaData;
version = MAKEWORD(1, 1);
return (WSAStartup(version, &wsaData) == 0);
#endif
}
void CleanupSockets()
{
#if 0
WSACleanup();
#endif
}
int main(int argc, char* argv[])
{
InitSockets();
double duration=-1;
int nRead;
//is live stream ?
char bLiveStream=1;
int bufsize=1024*1024*10;
char *buf=(char*)malloc(bufsize);
memset(buf,0,bufsize);
long countbufsize=0;
FILE *fp=fopen("receive.flv","wb");
if (!fp){
RTMP_LogPrintf("Open File Error.\n");
CleanupSockets();
return -1;
}
/* set log level */
//RTMP_LogLevel loglvl=RTMP_LOGDEBUG;
//RTMP_LogSetLevel(loglvl);
RTMP *rtmp=RTMP_Alloc();
RTMP_Init(rtmp);
//set connection timeout,default 30s
rtmp->Link.timeout=10;
// HKS's live URL
if(!RTMP_SetupURL(rtmp,"rtmp://live.hkstv.hk.lxdns.com/live/hks"))
{
RTMP_Log(RTMP_LOGERROR,"SetupURL Err\n");
RTMP_Free(rtmp);
CleanupSockets();
return -1;
}
if (bLiveStream){
rtmp->Link.lFlags|=RTMP_LF_LIVE;
}
//1hour
RTMP_SetBufferMS(rtmp, 3600*1000);
if(!RTMP_Connect(rtmp,NULL)){
RTMP_Log(RTMP_LOGERROR,"Connect Err\n");
RTMP_Free(rtmp);
CleanupSockets();
return -1;
}
if(!RTMP_ConnectStream(rtmp,0)){
RTMP_Log(RTMP_LOGERROR,"ConnectStream Err\n");
RTMP_Close(rtmp);
RTMP_Free(rtmp);
CleanupSockets();
return -1;
}
while(nRead=RTMP_Read(rtmp,buf,bufsize)){
fwrite(buf,1,nRead,fp);
countbufsize+=nRead;
RTMP_LogPrintf("Receive: %5dByte, Total: %5.2fkB\n",nRead,countbufsize*1.0/1024);
}
if(fp)
fclose(fp);
if(buf){
free(buf);
}
if(rtmp){
RTMP_Close(rtmp);
RTMP_Free(rtmp);
CleanupSockets();
rtmp=NULL;
}
return 0;
}
这里面包含rtmp的几个头文件,需要借助librtmp的库,可以随意在网上下个,我找了雷神的那个:
http://download.csdn.net/download/leixiaohua1020/8291757我只拷贝了librtmp,和顶层的Makefile,Makefile做了一点点修改来编译rtmp2flv.c
Makefile:
VERSION=v2.3
prefix=/usr/local
CC=$(CROSS_COMPILE)gcc
LD=$(CROSS_COMPILE)ld
SYS=posix
#SYS=mingw
CRYPTO=OPENSSL
#CRYPTO=POLARSSL
#CRYPTO=GNUTLS
LIB_GNUTLS=-lgnutls -lgcrypt
LIB_OPENSSL=-lssl -lcrypto
LIB_POLARSSL=-lpolarssl
CRYPTO_LIB=$(LIB_$(CRYPTO))
DEF_=-DNO_CRYPTO
CRYPTO_DEF=$(DEF_$(CRYPTO))
DEF=-DRTMPDUMP_VERSION=\"$(VERSION)\" $(CRYPTO_DEF) $(XDEF)
OPT=-O2
CFLAGS=-Wall $(XCFLAGS) $(INC) $(DEF) $(OPT)
LDFLAGS=-Wall $(XLDFLAGS)
bindir=$(prefix)/bin
sbindir=$(prefix)/sbin
mandir=$(prefix)/man
BINDIR=$(DESTDIR)$(bindir)
SBINDIR=$(DESTDIR)$(sbindir)
MANDIR=$(DESTDIR)$(mandir)
LIBS_posix=
LIBS_mingw=-lws2_32 -lwinmm -lgdi32
LIBS=$(CRYPTO_LIB) -lz $(LIBS_$(SYS)) $(XLIBS)
THREADLIB_posix=-lpthread
THREADLIB_mingw=
THREADLIB=$(THREADLIB_$(SYS))
SLIBS=$(THREADLIB) $(LIBS)
LIBRTMP=librtmp/librtmp.a
INCRTMP=librtmp/rtmp_sys.h librtmp/rtmp.h librtmp/log.h librtmp/amf.h
EXT_posix=
EXT_mingw=.exe
EXT=$(EXT_$(SYS))
all:$(LIBRTMP) progs
progs:rtmp2flv rtmpdump rtmpgw rtmpsrv rtmpsuck
install:progs
-mkdir -p $(BINDIR) $(SBINDIR) $(MANDIR)/man1 $(MANDIR)/man8
cp rtmpdump$(EXT) $(BINDIR)
cp rtmpgw$(EXT) rtmpsrv$(EXT) rtmpsuck$(EXT) $(SBINDIR)
cp rtmpdump.1 $(MANDIR)/man1
cp rtmpgw.8 $(MANDIR)/man8
@cd librtmp; $(MAKE) install
clean:
rm -f *.o rtmp2flv$(EXT) rtmpdump$(EXT) rtmpgw$(EXT) rtmpsrv$(EXT) rtmpsuck$(EXT)
@cd librtmp; $(MAKE) clean
FORCE:
$(LIBRTMP): FORCE
@cd librtmp; $(MAKE) all
# note: $^ is GNU Make's equivalent to BSD $>
# we use both since either make will ignore the one it doesn't recognize
rtmp2flv: rtmp2flv.o $(LIBRTMP)
$(CC) $(LDFLAGS) $^ $> -o $@$(EXT) $(LIBS)
rtmpdump: rtmpdump.o $(LIBRTMP)
$(CC) $(LDFLAGS) $^ $> -o $@$(EXT) $(LIBS)
rtmpsrv: rtmpsrv.o thread.o $(LIBRTMP)
$(CC) $(LDFLAGS) $^ $> -o $@$(EXT) $(SLIBS)
rtmpsuck: rtmpsuck.o thread.o $(LIBRTMP)
$(CC) $(LDFLAGS) $^ $> -o $@$(EXT) $(SLIBS)
rtmpgw: rtmpgw.o thread.o $(LIBRTMP)
$(CC) $(LDFLAGS) $^ $> -o $@$(EXT) $(SLIBS)
rtmp2flv.o: rtmp2flv.c $(INCRTMP) Makefile
rtmpgw.o: rtmpgw.c $(INCRTMP) Makefile
rtmpdump.o: rtmpdump.c $(INCRTMP) Makefile
rtmpsrv.o: rtmpsrv.c $(INCRTMP) Makefile
rtmpsuck.o: rtmpsuck.c $(INCRTMP) Makefile
thread.o: thread.c thread.h
./rtmp2flv运行程序
用smplayer receive.flv 来播放视频:
感谢雷神!