最近嘴的一个项目是VC++提供websocket推送flv服务 以供web端点播。该方案的优点是无需下载控件,也不用flash播放器。之前实现过rtmp协议,但是flash到2020年之后停止技术支持。websocket推送flv流,可以在html5上直播播放。在pc端和Android 和ios上都可播放。
获取到的流是H264需要转为flv格式。下面贴出主要代码后期会上传工程供大家参考
BOOL CFlvStream::InitFlvHead()
{
FLV_FILE_HEAD flvHead;
memset(&flvHead, 0, sizeof(flvHead));
memcpy(flvHead.sign_flag, "FLV", 3);
flvHead.version = 0x01;
flvHead.flvflag = 0x01;
flvHead.dataoff[3] = 0x09;
memcpy(m_pFlvStream+m_dwStreamLen,&flvHead,sizeof(flvHead));
m_dwStreamLen += sizeof(flvHead);
m_dwStreamLen += 4; //上一个tag长度,此处为0
return TRUE;
}
BOOL CFlvStream::write_metadata(DWORD dwWith, DWORD dwHeight)
{
int SLen = 0;
FLV_TAG_HEAD tagHead = { 0 };
tagHead.tagtype = 0x12; //脚本数据
BYTE byData[1024] = { 0 };
BYTE* pPos = byData;
avio_w8(pPos, 0x02);
put_amf_string(pPos, "onMetaData");
avio_w8(pPos, 0x08);
avio_wb32(pPos, 8);
put_amf_string(pPos, "duration");
put_amf_double(pPos, 0);
put_amf_string(pPos, "width");
put_amf_double(pPos, dwWith);
put_amf_string(pPos, "height");
put_amf_double(pPos, dwHeight);
put_amf_string(pPos, "videodatarate");
put_amf_double(pPos, 4096);
put_amf_string(pPos, "framerate");
put_amf_double(pPos, 25.00);
put_amf_string(pPos, "videocodecid");
put_amf_double(pPos, 7.0);
put_amf_string(pPos, "encoder");
put_amf_string(pPos, "Lavf55.49.100");
put_amf_string(pPos, "filesize");
put_amf_double(pPos, 0);
put_amf_string(pPos, "");
avio_w8(pPos, 0x09);
int nLen = pPos - byData;
tagHead.data_size[0] = (uint8_t)(nLen >> 16);
tagHead.data_size[1] = (uint8_t)(nLen >> 8);
tagHead.data_size[2] = (uint8_t)nLen;
memcpy(m_pFlvStream + m_dwStreamLen, &tagHead, sizeof(tagHead));
m_dwStreamLen += sizeof(tagHead);
memcpy(m_pFlvStream + m_dwStreamLen, byData, pPos - byData);
m_dwStreamLen += (pPos - byData);
pPos = m_pFlvStream + m_dwStreamLen;
avio_wb32(pPos, nLen + 11);
m_dwStreamLen += 4;
return TRUE;
}
BOOL CFlvStream::write_avcconfig(BYTE* pData, DWORD dwSize)
{
FLV_TAG_HEAD tagHead = { 0 };
tagHead.tagtype = 0x09; //脚本数据
BYTE byData[1024] = { 0 };
BYTE* pPos = byData;
avio_w8(pPos, 0x17);
avio_wb32(pPos, 0);
avio_w8(pPos, 0x01);
int nPos = GetFirstPosbyType(pData,dwSize,7);
int nType = 0;
if (nPos >= 0)
{
avio_write(pPos, (const char*)pData+nPos+5, 3);
avio_w8(pPos, 0xFF);
avio_w8(pPos, 0xE1);
int nLen = GetFirstPos(pData + nPos + 4, dwSize - nPos - 4, nType);
if (nLen == -1)
{
nLen = dwSize - nPos - 4;
}
avio_wb16(pPos, nLen); //sps长度
avio_write(pPos, (const char*)pData + nPos + 4, nLen); //sps数据
avio_w8(pPos, 0x01); //pps个数
nPos = GetFirstPosbyType(pData, dwSize, 8);
nLen = GetFirstPos(pData + nPos + 4, dwSize - nPos - 4, nType);
if (nLen == -1)
{
nLen = dwSize - nPos - 4;
}
avio_wb16(pPos, nLen); //pps长度
avio_write(pPos, (const char*)pData + nPos + 4, nLen); //pps数据
nLen = pPos - byData;
tagHead.data_size[0] = (uint8_t)(nLen >> 16);
tagHead.data_size[1] = (uint8_t)(nLen >> 8);
tagHead.data_size[2] = (uint8_t)nLen;
memcpy(m_pFlvStream + m_dwStreamLen, &tagHead, sizeof(tagHead));
m_dwStreamLen += sizeof(tagHead);
memcpy(m_pFlvStream + m_dwStreamLen, byData, pPos - byData);
m_dwStreamLen += (pPos - byData);
pPos = m_pFlvStream + m_dwStreamLen;
avio_wb32(pPos, nLen + 11);
m_dwStreamLen += 4;
}
else{
return FALSE;
}
}
BOOL CFlvStream::write_videodata(BYTE* pData, DWORD dwSize, DWORD dwTime, BOOL bKey)
{
BYTE* pPos = m_pFlvStream + m_dwStreamLen;
avio_w8(pPos, 0x09);
avio_wb24(pPos, dwSize + 5);
avio_wb24(pPos, dwTime & 0xFFFFFF);
avio_w8(pPos, (dwTime >> 24) & 0x7F); // timestamps are 32 bits _signed_
avio_wb24(pPos, 0);
if (bKey)
{
avio_w8(pPos, 0x17);
}
else
{
avio_w8(pPos, 0x27);
}
avio_w8(pPos, 0x01);
avio_wb24(pPos, 0);
replaceStartCode(pData,dwSize);
avio_write(pPos,(const char*)pData,dwSize);
m_dwStreamLen += (pPos - m_pFlvStream);
avio_wb32(pPos, pPos - m_pFlvStream);
m_dwStreamLen += 4;
return 0;
}