转自:http://blog.163.com/zhujiatc@126/blog/static/183463820132135378895/
rtmp协议与flv封包格式基本相同(本来就是一家公司的嘛) 将flv文件解析出类型,时间戳,数据大小,数据区 对应写的rtmp包的位置进行发送即可
rtmpdump官网: http://rtmpdump.mplayerhq.hu/
这里是以flv文件做源,可以自己采集视频音频进行实时发送 库版本 2.4
下图,左边发送到服务器,右侧可正常观看(模拟的是实时流,发完该流也就结束了)
#include#include#include
#pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"lib/librtmp.lib")
#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))
bool Read8(int &i8,FILE*fp);
bool Read16(int &i16,FILE*fp);
bool Read24(int &i24,FILE*fp);
bool Read32(int &i32,FILE*fp);
bool Peek8(int &i8,FILE*fp);
bool ReadTime(int &itime,FILE*fp);
//RTMP_XXX()返回0表示失败,1表示成功
RTMP*rtmp=NULL;
//rtmp应用指针 RTMPPacket*packet=NULL;
//rtmp包结构 char* rtmpurl="rtmp://127.0.0.1:1935/live/test";
//连接的URL char* flvfile="test.flv";
//读取的flv文件
bool ZINIT();
//初始化相关 void ZCLEAR();
//清除相关
int main() { if (!ZINIT()) { printf("init socket err\n");
return -1;
} /初始化// //
RTMP_debuglevel=RTMP_LOGINFO;
//信息等级(0-6)
限
2.3版以前使用
RTMP_LogLevel lvl=RTMP_LOGINFO;
RTMP_LogSetLevel(lvl);
//设置信息等级 //RTMP_LogSetOutput(FILE*fp);
//设置信息输出文件
rtmp=RTMP_Alloc();
//申请rtmp空间 RTMP_Init(rtmp);
//初始化rtmp设置 rtmp->Link.timeout=5;
//设置连接超时,单位秒,默认30秒 packet=new RTMPPacket();
//创建包 RTMPPacket_Alloc(packet,1024*64);
//给packet分配数据空间,
要满足最长的帧,不知道可设大些 RTMPPacket_Reset(packet);
//重置packet状态 连接// RTMP_SetupURL(rtmp,rtmpurl);
//设置url RTMP_EnableWrite(rtmp);
//设置可写状态 if (!RTMP_Connect(rtmp,NULL))//连接服务器 { printf("connect err\n");
ZCLEAR();
return -1;
} if (!RTMP_ConnectStream(rtmp,0))//创建并发布流(取决于rtmp->Link.lFlags) { printf("ConnectStreamerr\n");
ZCLEAR();
return -1;
} packet->m_hasAbsTimestamp = 0;
//绝对时间戳 packet->m_nChannel = 0x04;
//通道 packet->m_nInfoField2 = rtmp->m_stream_id;
FILE*fp=fopen(flvfile,"rb");
if (fp==NULL) { printf("open file:%s err\n",flvfile);
ZCLEAR();
return -1;
}
printf("rtmpurl:%s\nflvfile:%s\nsend data ...\n",rtmpurl,flvfile);
发送数据// fseek(fp,9,SEEK_SET);
//跳过前9个字节 fseek(fp,4,SEEK_CUR);
//跳过4字节长度 long start=clock()-1000;
long perframetime=0;
//上一帧时间戳 while(TRUE) { if((clock()-start){ Sleep(500);
continue;
} int type=0;
//类型 int datalength=0;
//数据长度 int time=0;
//时间戳 int streamid=0;
//流ID if(!Read8(type,fp)) break;
if(!Read24(datalength,fp)) break;
if(!ReadTime(time,fp)) break;
if(!Read24(streamid,fp)) break;
if (type!=0x08&&type!=0x09) { fseek(fp,datalength+4,SEEK_CUR);
continue;
}
if(fread(packet->m_body,1,datalength,fp)!=datalength) break;
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
packet->m_nTimeStamp = time;
packet->m_packetType=type;
packet->m_nBodySize=datalength;
if (!RTMP_IsConnected(rtmp)) { printf("rtmp is not connect\n");
break;
} if (!RTMP_SendPacket(rtmp,packet,0)) { printf("send err\n");
break;
} int alldatalength=0;
//该帧总长度 if(!Read32(alldatalength,fp)) break;
perframetime=time;
} printf("send data over\n");
fclose(fp);
ZCLEAR();
return 0;
}
bool ZINIT() { WORD version;
WSADATA wsaData;
version=MAKEWORD(2,2);
if(WSAStartup(version,&wsaData)!=0) { return FALSE;
} return TRUE;
} void ZCLEAR() { //释放/ if (rtmp!=NULL) { RTMP_Close(rtmp);
//断开连接 RTMP_Free(rtmp);
//释放内存 rtmp=NULL;
} if (packet!=NULL) { RTMPPacket_Free(packet);
//释放内存 delete packet;
packet=NULL;
} /// WSACleanup();
}
bool Read8(int &i8,FILE*fp) { if(fread(&i8,1,1,fp)!=1) return false;
return true;
} bool Read16(int &i16,FILE*fp) { if(fread(&i16,2,1,fp)!=1) return false;
i16=HTON16(i16);
return true;
} bool Read24(int &i24,FILE*fp) { if(fread(&i24,3,1,fp)!=1) return false;
i24=HTON24(i24);
return true;
} bool Read32(int &i32,FILE*fp) { if(fread(&i32,4,1,fp)!=1) return false;
i32=HTON32(i32);
return true;
} bool Peek8(int &i8,FILE*fp) { if(fread(&i8,1,1,fp)!=1) return false;
fseek(fp,-1,SEEK_CUR);
return true;
} bool ReadTime(int &itime,FILE*fp) { int temp=0;
if(fread(&temp,4,1,fp)!=1) return false;
itime=HTON24(temp);
itime|=(temp&0xff000000);
return true;
}
源码下载:(包含所需第三方库和播放器,
需自己开启rtmp服务器)
http://vdisk.weibo.com/s/unhDlwQMVR3Fv
【使用librtmp库发布直播流】