2023-11-12 16:13:24 +00:00
|
|
|
|
#include "RtmpPusher.h"
|
2023-12-10 17:02:28 +00:00
|
|
|
|
#include <sys/timeb.h>
|
2023-11-12 16:13:24 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>winsock
|
|
|
|
|
*
|
|
|
|
|
* @<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD>1 , ʧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
*/
|
|
|
|
|
int InitSockets()
|
|
|
|
|
{
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
WORD version;
|
|
|
|
|
WSADATA wsaData;
|
|
|
|
|
version = MAKEWORD(1, 1);
|
|
|
|
|
return (WSAStartup(version, &wsaData) == 0);
|
|
|
|
|
#else
|
|
|
|
|
return TRUE;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RtmpPusher::IfConnect()
|
|
|
|
|
{
|
|
|
|
|
return mIfConnected;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int RtmpPusher::RTMP264_Connect(const char* url)
|
|
|
|
|
{
|
|
|
|
|
InitSockets();
|
|
|
|
|
m_pRtmp = RTMP_Alloc();
|
|
|
|
|
RTMP_Init(m_pRtmp);
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD>URL*/
|
|
|
|
|
if (RTMP_SetupURL(m_pRtmp, (char*)url) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
RTMP_Free(m_pRtmp);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
/*<2A><><EFBFBD>ÿ<EFBFBD>д,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰʹ<C7B0><CAB9>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч*/
|
|
|
|
|
RTMP_EnableWrite(m_pRtmp);
|
|
|
|
|
/*<2A><><EFBFBD>ӷ<EFBFBD><D3B7><EFBFBD><EFBFBD><EFBFBD>*/
|
|
|
|
|
if (RTMP_Connect(m_pRtmp, NULL) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
RTMP_Free(m_pRtmp);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
|
|
|
if (RTMP_ConnectStream(m_pRtmp, 0) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
RTMP_Close(m_pRtmp);
|
|
|
|
|
RTMP_Free(m_pRtmp);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->mUrl = string(url);
|
|
|
|
|
this->mIfConnected = true;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* <EFBFBD>ͷ<EFBFBD>winsock
|
|
|
|
|
*
|
|
|
|
|
* @<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD>0 , ʧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
*/
|
|
|
|
|
inline void CleanupSockets()
|
|
|
|
|
{
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
WSACleanup();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtmpPusher::RTMP264_Close()
|
|
|
|
|
{
|
|
|
|
|
mMux.lock();
|
|
|
|
|
if (m_pRtmp)
|
|
|
|
|
{
|
|
|
|
|
RTMP_Close(m_pRtmp);
|
|
|
|
|
RTMP_Free(m_pRtmp);
|
|
|
|
|
m_pRtmp = NULL;
|
|
|
|
|
}
|
|
|
|
|
mMux.unlock();
|
|
|
|
|
CleanupSockets();
|
|
|
|
|
}
|
|
|
|
|
RTMPPacket* gPacket = nullptr;
|
|
|
|
|
|
|
|
|
|
int RtmpPusher::SendPacket(unsigned int nPacketType, unsigned char * data,
|
|
|
|
|
unsigned int size, unsigned int nTimestamp)
|
|
|
|
|
{
|
|
|
|
|
static bool once = true;
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4>ͳ<EFBFBD>ʼ<EFBFBD><CABC>,lenΪ<6E><CEAA><EFBFBD>峤<EFBFBD><E5B3A4>*/
|
|
|
|
|
if(nullptr == gPacket)
|
|
|
|
|
gPacket = (RTMPPacket *)malloc(640*720*3 + size);
|
|
|
|
|
memset(gPacket, 0, RTMP_HEAD_SIZE);
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>*/
|
|
|
|
|
|
|
|
|
|
gPacket->m_body = (char *)gPacket + RTMP_HEAD_SIZE;
|
|
|
|
|
gPacket->m_nBodySize = size;
|
|
|
|
|
memcpy(gPacket->m_body, data, size);
|
|
|
|
|
|
|
|
|
|
gPacket->m_hasAbsTimestamp = 0;
|
|
|
|
|
gPacket->m_packetType = nPacketType; /*<2A>˴<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ,һ<><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ*/
|
|
|
|
|
gPacket->m_nInfoField2 = m_pRtmp->m_stream_id;
|
|
|
|
|
gPacket->m_nChannel = 0x04;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gPacket->m_headerType = RTMP_PACKET_SIZE_LARGE;
|
|
|
|
|
if (RTMP_PACKET_TYPE_AUDIO == nPacketType && size != 4)
|
|
|
|
|
{
|
|
|
|
|
gPacket->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gPacket->m_nTimeStamp = nTimestamp;
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD>*/
|
|
|
|
|
int nRet = 0;
|
|
|
|
|
if (RTMP_IsConnected(m_pRtmp))
|
|
|
|
|
{
|
|
|
|
|
nRet = RTMP_SendPacket(m_pRtmp, gPacket, FALSE); /*TRUEΪ<45>Ž<EFBFBD><C5BD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD>,FALSE<53>Dz<EFBFBD><C7B2>Ž<EFBFBD><C5BD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD>,ֱ<>ӷ<EFBFBD><D3B7><EFBFBD>*/
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (once) {
|
|
|
|
|
once = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*<2A>ͷ<EFBFBD><CDB7>ڴ<EFBFBD>*/
|
|
|
|
|
//free(gPacket);
|
|
|
|
|
return nRet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int RtmpPusher::SendVideoPacket(unsigned int nPacketType,
|
|
|
|
|
unsigned char * data, unsigned int size, unsigned int nTimestamp)
|
|
|
|
|
{
|
2023-12-10 17:02:28 +00:00
|
|
|
|
SYSTEMTIME st;
|
|
|
|
|
GetSystemTime(&st);
|
|
|
|
|
qDebug()<<QString::asprintf("send tps%ld\n", st.wMilliseconds);
|
2023-11-12 16:13:24 +00:00
|
|
|
|
|
|
|
|
|
RTMPPacket* packet;
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4>ͳ<EFBFBD>ʼ<EFBFBD><CABC>,lenΪ<6E><CEAA><EFBFBD>峤<EFBFBD><E5B3A4>*/
|
|
|
|
|
packet = (RTMPPacket *)malloc(RTMP_HEAD_SIZE + size);
|
|
|
|
|
memset(packet, 0, RTMP_HEAD_SIZE);
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>*/
|
|
|
|
|
packet->m_body = (char *)packet + RTMP_HEAD_SIZE;
|
|
|
|
|
packet->m_nBodySize = size;
|
|
|
|
|
memcpy(packet->m_body, data, size);
|
|
|
|
|
packet->m_hasAbsTimestamp = 0;
|
|
|
|
|
packet->m_packetType = nPacketType; /*<2A>˴<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ,һ<><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ*/
|
|
|
|
|
packet->m_nInfoField2 = m_pRtmp->m_stream_id;
|
|
|
|
|
packet->m_nChannel = 0x04;
|
|
|
|
|
packet->m_nTimeStamp += 33;
|
|
|
|
|
|
|
|
|
|
packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
|
|
|
|
|
if (RTMP_PACKET_TYPE_AUDIO == nPacketType && size != 4)
|
|
|
|
|
{
|
|
|
|
|
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
|
|
|
|
|
}
|
|
|
|
|
packet->m_nTimeStamp = nTimestamp;
|
|
|
|
|
/*<2A><><EFBFBD><EFBFBD>*/
|
|
|
|
|
int nRet = 0;
|
|
|
|
|
if (RTMP_IsConnected(m_pRtmp))
|
|
|
|
|
{
|
|
|
|
|
nRet = RTMP_SendPacket(m_pRtmp, packet, TRUE); /*TRUEΪ<45>Ž<EFBFBD><C5BD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD>,FALSE<53>Dz<EFBFBD><C7B2>Ž<EFBFBD><C5BD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD>,ֱ<>ӷ<EFBFBD><D3B7><EFBFBD>*/
|
|
|
|
|
}
|
|
|
|
|
/*<2A>ͷ<EFBFBD><CDB7>ڴ<EFBFBD>*/
|
|
|
|
|
free(packet);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtmpPusher::RtmpPusher()
|
|
|
|
|
:mThread(nullptr),
|
|
|
|
|
mIfConnected(false)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RtmpPusher::~RtmpPusher()
|
|
|
|
|
{
|
|
|
|
|
if (m_pRtmp)
|
|
|
|
|
{
|
|
|
|
|
RTMP_Close(m_pRtmp);
|
|
|
|
|
RTMP_Free(m_pRtmp);
|
|
|
|
|
m_pRtmp = NULL;
|
|
|
|
|
}
|
|
|
|
|
CleanupSockets();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void H264RtmpPuser::OnAudioEncode(const void * frameaddress, uint32_t framelen,uint16_t pts)
|
|
|
|
|
{
|
|
|
|
|
uint8_t *pack = (uint8_t*)malloc(framelen);
|
|
|
|
|
memcpy(pack, frameaddress, framelen);
|
|
|
|
|
|
|
|
|
|
mMux.lock();
|
|
|
|
|
Buffer buf;
|
|
|
|
|
buf.buf = (uint8_t *)pack;
|
|
|
|
|
buf.len = framelen;
|
|
|
|
|
buf.type = PAYLOAD_TYPE_AUDIO;
|
|
|
|
|
this->mPack.push(buf);
|
|
|
|
|
mMux.unlock();
|
|
|
|
|
this->mAudioPts = pts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
H264RtmpPuser::H264RtmpPuser()
|
|
|
|
|
{
|
|
|
|
|
this->metaData.Pps = nullptr;
|
|
|
|
|
this->metaData.Sps = nullptr;
|
|
|
|
|
this->metaData.nPpsLen = 0;
|
|
|
|
|
this->metaData.nSpsLen = 0;
|
|
|
|
|
this->mStartTime = 0;
|
|
|
|
|
mFirtACC = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int H264RtmpPuser::sortAndSendNal(uint8_t * data, int len)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
uint8_t * nalhead = nullptr;
|
|
|
|
|
uint8_t * naltail = nullptr;
|
|
|
|
|
uint32_t size = 0;
|
2023-11-29 16:22:43 +00:00
|
|
|
|
static uint32_t time = 0;
|
|
|
|
|
|
2023-12-10 17:02:28 +00:00
|
|
|
|
SYSTEMTIME st;
|
|
|
|
|
GetSystemTime(&st);
|
|
|
|
|
struct timeb t1;
|
|
|
|
|
ftime(&t1);
|
|
|
|
|
//t1.time<6D>Ǵ<EFBFBD>UTCʱ<43><CAB1>1970<37><30>1<EFBFBD><31>1<EFBFBD><31><EFBFBD><EFBFBD>ҹ(00:00:00)<29><><EFBFBD>ۼƵ<DBBC><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>t1.millitm<74><6D>һ<EFBFBD><D2BB><EFBFBD>ڵĺ<DAB5><C4BA><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
time_t ttt= t1.millitm+t1.time*1000;
|
|
|
|
|
// qDebug()<<QString::asprintf("send tps%ld \n",ttt);
|
|
|
|
|
|
2023-11-12 16:13:24 +00:00
|
|
|
|
if(0 == mStartTime){
|
2023-12-10 17:02:28 +00:00
|
|
|
|
mStartTime = ttt;
|
2023-11-12 16:13:24 +00:00
|
|
|
|
}
|
|
|
|
|
if (nullptr == data) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
while (i < len)
|
|
|
|
|
{
|
|
|
|
|
// sps pps p frame
|
|
|
|
|
if ((data[i] == 0x00) && (data[i + 1] == 0x00)
|
|
|
|
|
&& ((data[i + 2] == 0x00) && (data[i + 3] == 0x01) || (data[i + 2] == 0x01))) {
|
|
|
|
|
if ((nalhead == nullptr) && (i == 0) ) {
|
|
|
|
|
if ((data[i + 3] == 0x01) && (data[i + 4] == 0x41)) { //p ֱ֡<D6A1>ӷ<EFBFBD>
|
2023-12-10 17:02:28 +00:00
|
|
|
|
time += 60;
|
2023-11-12 16:13:24 +00:00
|
|
|
|
|
|
|
|
|
nalhead = data;
|
|
|
|
|
naltail = data + (len);
|
|
|
|
|
size = naltail - nalhead;
|
2023-12-10 17:02:28 +00:00
|
|
|
|
this->SendH264Packet(nalhead, size, 0, ttt - mStartTime);
|
2023-11-12 16:13:24 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
//sps ֡<><D6A1><EFBFBD>н<EFBFBD><D0BD><EFBFBD>
|
|
|
|
|
if ((data[i + 3] == 0x01) && (data[i + 4] == 0x67)) { // sps or pps or sei
|
|
|
|
|
nalhead = data;
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
//sei
|
|
|
|
|
if ((data[i + 2] == 0x01) && (data[i + 3] == 0x06)) {
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// i frame
|
|
|
|
|
if ((data[i + 2] == 0x01) && (data[i + 3] == 0x65)) {
|
2023-12-10 17:02:28 +00:00
|
|
|
|
time += 60;
|
2023-11-12 16:13:24 +00:00
|
|
|
|
|
|
|
|
|
naltail = data + i;
|
|
|
|
|
size = naltail - nalhead;
|
2023-12-10 17:02:28 +00:00
|
|
|
|
this->SendH264Packet(nalhead, size, 0, ttt - mStartTime);
|
2023-11-12 16:13:24 +00:00
|
|
|
|
nalhead = data + i;
|
|
|
|
|
naltail = data + (len);
|
|
|
|
|
size = naltail - nalhead;
|
2023-12-10 17:02:28 +00:00
|
|
|
|
this->SendH264Packet(nalhead, size, 0, ttt - mStartTime);
|
2023-11-12 16:13:24 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
//pps
|
|
|
|
|
if ((data[i + 3] == 0x01) && (data[i + 4] == 0x68)) { // sps or pps or sei
|
|
|
|
|
naltail = data + i;
|
|
|
|
|
size = naltail - nalhead;
|
2023-12-10 17:02:28 +00:00
|
|
|
|
this->SendH264Packet(nalhead, size, 0, ttt - mStartTime);
|
2023-11-12 16:13:24 +00:00
|
|
|
|
nalhead = data + i;
|
|
|
|
|
i += 3;
|
|
|
|
|
}//sps
|
|
|
|
|
if ((data[i + 3] == 0x01) && (data[i + 4] == 0x67)) { // sps or pps or sei
|
|
|
|
|
nalhead = data + i;
|
|
|
|
|
i += 3;
|
|
|
|
|
}
|
|
|
|
|
//sei
|
|
|
|
|
if ((data[i + 3] == 0x01) && (data[i + 4] == 0x06)) { // sps or pps or sei
|
|
|
|
|
naltail = data + i;
|
|
|
|
|
size = naltail - nalhead;
|
2023-12-10 17:02:28 +00:00
|
|
|
|
this->SendH264Packet(nalhead, size, 0, ttt - mStartTime);
|
2023-11-12 16:13:24 +00:00
|
|
|
|
nalhead = data + i;
|
|
|
|
|
i += 3;
|
|
|
|
|
}
|
|
|
|
|
// sps pps or sei
|
|
|
|
|
}
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>00 00 00 00 01<30><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>Ƶͬ<C6B5><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD>https://blog.csdn.net/liwf616/article/details/51596373
|
|
|
|
|
int H264RtmpPuser::SendVideoSpsPps(unsigned char * pps,
|
|
|
|
|
int pps_len, unsigned char * sps,
|
|
|
|
|
int sps_len,unsigned int nTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
RTMPPacket * packet = NULL;//rtmp<6D><70><EFBFBD>ṹ
|
|
|
|
|
unsigned char * body = NULL;
|
|
|
|
|
int i;
|
|
|
|
|
packet = (RTMPPacket *)malloc(RTMP_HEAD_SIZE + 1024);
|
|
|
|
|
//RTMPPacket_Reset(packet);//<2F><><EFBFBD><EFBFBD>packet״̬
|
|
|
|
|
memset(packet, 0, RTMP_HEAD_SIZE + 1024);
|
|
|
|
|
packet->m_body = (char *)packet + RTMP_HEAD_SIZE;
|
|
|
|
|
body = (unsigned char *)packet->m_body;
|
|
|
|
|
i = 0;
|
|
|
|
|
// FrameType == 1<><31>CodecID == 7<><37>
|
|
|
|
|
body[i++] = 0x17;
|
|
|
|
|
//AVCPacketType
|
|
|
|
|
body[i++] = 0x00;
|
|
|
|
|
|
|
|
|
|
//CompositionTime
|
|
|
|
|
body[i++] = 0x00;
|
|
|
|
|
body[i++] = 0x00;
|
|
|
|
|
body[i++] = 0x00;
|
|
|
|
|
|
|
|
|
|
/*AVCDecoderConfigurationRecord*/
|
|
|
|
|
body[i++] = 0x01;
|
|
|
|
|
body[i++] = sps[1];
|
|
|
|
|
body[i++] = sps[2];
|
|
|
|
|
body[i++] = sps[3];
|
|
|
|
|
body[i++] = 0xff;
|
|
|
|
|
|
|
|
|
|
/*sps*/
|
|
|
|
|
body[i++] = 0xe1;
|
|
|
|
|
body[i++] = (sps_len >> 8) & 0xff;
|
|
|
|
|
body[i++] = sps_len & 0xff;
|
|
|
|
|
memcpy(&body[i], sps, sps_len);
|
|
|
|
|
i += sps_len;
|
|
|
|
|
|
|
|
|
|
/*pps*/
|
|
|
|
|
body[i++] = 0x01;
|
|
|
|
|
body[i++] = (pps_len >> 8) & 0xff;
|
|
|
|
|
body[i++] = (pps_len) & 0xff;
|
|
|
|
|
memcpy(&body[i], pps, pps_len);
|
|
|
|
|
i += pps_len;
|
|
|
|
|
|
|
|
|
|
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
|
|
|
|
|
packet->m_nBodySize = i;
|
|
|
|
|
packet->m_nChannel = 0x04;
|
|
|
|
|
packet->m_nTimeStamp = nTimeStamp;
|
|
|
|
|
packet->m_hasAbsTimestamp = 0;
|
|
|
|
|
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
|
|
|
|
|
packet->m_nInfoField2 = m_pRtmp->m_stream_id;
|
|
|
|
|
|
|
|
|
|
/*<2A><><EFBFBD>÷<EFBFBD><C3B7>ͽӿ<CDBD>*/
|
|
|
|
|
int nRet = RTMP_SendPacket(m_pRtmp, packet, TRUE);
|
|
|
|
|
free(packet); //<2F>ͷ<EFBFBD><CDB7>ڴ<EFBFBD>
|
|
|
|
|
return nRet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int H264RtmpPuser::SendAudioData(unsigned char * dat,
|
|
|
|
|
unsigned int size, unsigned int nTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int H264RtmpPuser::SendH264Packet(unsigned char * data,
|
|
|
|
|
unsigned int size, int bIsKeyFrame, unsigned int nTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
if(data == NULL){
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
unsigned int nal_type = 0;
|
|
|
|
|
// С֡Ӧ<D6A1><D3A6><EFBFBD><EFBFBD>PPS<50><53><EFBFBD><EFBFBD>SPS
|
|
|
|
|
if ((data[0] != 0x00) || (data[1] != 0x00)
|
|
|
|
|
|| ((data[2] != 0x00)&&data[2]!= 0x01)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
//Debuger::Debug(L"%02x %02x %02x %02x %02x %02d\r\n",
|
|
|
|
|
// data[0],data[1],data[2],data[3],data[4],size);
|
|
|
|
|
if (data[2] == 0x01) {
|
|
|
|
|
nal_type = data[3];
|
|
|
|
|
}
|
|
|
|
|
if (data[3] == 0x01) {
|
|
|
|
|
nal_type = data[4];
|
|
|
|
|
}
|
|
|
|
|
switch (nal_type)
|
|
|
|
|
{
|
|
|
|
|
case 0x67: //just update sps and pps
|
|
|
|
|
if (NULL == metaData.Sps)
|
|
|
|
|
metaData.Sps = (unsigned char *)malloc(size - 4);
|
|
|
|
|
h264_decode_sps(data + 4, size - 4, metaData.nWidth, metaData.nHeight, metaData.nFrameRate);
|
|
|
|
|
metaData.nSpsLen = size - 4;
|
|
|
|
|
memcpy(this->metaData.Sps, data + 4, size - 4);
|
|
|
|
|
break;
|
|
|
|
|
case 0x68: //just update sps and pps
|
|
|
|
|
this->metaData.nPpsLen = size - 4;
|
|
|
|
|
if (NULL == metaData.Pps) metaData.Pps = (unsigned char *)malloc(size - 4);
|
|
|
|
|
memcpy(this->metaData.Pps, data + 4, size - 4);
|
|
|
|
|
break;
|
|
|
|
|
case 0x41: //p frame
|
|
|
|
|
this->sendDataPackH264(data + 4, size - 4, 0, nTimeStamp);
|
|
|
|
|
break;
|
|
|
|
|
case 0x65: //i frame
|
|
|
|
|
this->sendDataPackH264(data + 3, size - 3, 1, nTimeStamp);
|
|
|
|
|
break;
|
|
|
|
|
case 0x06:
|
|
|
|
|
size = size;
|
|
|
|
|
//this->sendDataPack(data + 4, size - 4, 0, nTimeStamp);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
unsigned char *gBody = nullptr;
|
|
|
|
|
int H264RtmpPuser::sendDataPackH264(unsigned char * data,
|
|
|
|
|
unsigned int size, int bIsKeyFrame, unsigned int nTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
if (gBody == nullptr) {
|
|
|
|
|
gBody = new unsigned char[640*720*3 + 9];
|
|
|
|
|
}
|
|
|
|
|
if (size < 0) {
|
|
|
|
|
gBody = gBody;
|
|
|
|
|
}
|
|
|
|
|
memset(gBody, 0, size + 9);
|
|
|
|
|
int i = 0;
|
|
|
|
|
if (1 == bIsKeyFrame) {
|
|
|
|
|
gBody[i++] = 0x17;// 1:Iframe 7:AVC
|
|
|
|
|
gBody[i++] = 0x01;// AVC NALU
|
|
|
|
|
gBody[i++] = 0x00;
|
|
|
|
|
gBody[i++] = 0x00;
|
|
|
|
|
gBody[i++] = 0x00;
|
|
|
|
|
|
|
|
|
|
// NALU size
|
|
|
|
|
gBody[i++] = size >> 24 & 0xff;
|
|
|
|
|
gBody[i++] = size >> 16 & 0xff;
|
|
|
|
|
gBody[i++] = size >> 8 & 0xff;
|
|
|
|
|
gBody[i++] = size & 0xff;
|
|
|
|
|
// NALU data
|
|
|
|
|
memcpy(&gBody[i], data, size);
|
|
|
|
|
if(metaData.Sps != nullptr)
|
|
|
|
|
SendVideoSpsPps(metaData.Pps, metaData.nPpsLen, metaData.Sps,
|
|
|
|
|
metaData.nSpsLen, 0);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
gBody[i++] = 0x27;// 2:Pframe 7:AVC
|
|
|
|
|
gBody[i++] = 0x01;// AVC NALU
|
|
|
|
|
gBody[i++] = 0x00;
|
|
|
|
|
gBody[i++] = 0x00;
|
|
|
|
|
gBody[i++] = 0x00;
|
|
|
|
|
// NALU size
|
|
|
|
|
gBody[i++] = size >> 24 & 0xff;
|
|
|
|
|
gBody[i++] = size >> 16 & 0xff;
|
|
|
|
|
gBody[i++] = size >> 8 & 0xff;
|
|
|
|
|
gBody[i++] = size & 0xff;
|
|
|
|
|
// NALU data
|
|
|
|
|
|
|
|
|
|
memcpy(&gBody[i], data, size);
|
|
|
|
|
}
|
|
|
|
|
int bRet = SendPacket(RTMP_PACKET_TYPE_VIDEO, gBody, i + size, nTimeStamp);
|
|
|
|
|
return bRet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int H264RtmpPuser::SendAudioSync(int audioType,
|
|
|
|
|
int sampleIndex, int channel, unsigned int nTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
RTMPPacket * packet = NULL;//rtmp<6D><70><EFBFBD>ṹ
|
|
|
|
|
unsigned char * body = NULL;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
packet = (RTMPPacket *)malloc(RTMP_HEAD_SIZE + 1024);
|
|
|
|
|
//RTMPPacket_Reset(packet);//<2F><><EFBFBD><EFBFBD>packet״̬
|
|
|
|
|
memset(packet, 0, RTMP_HEAD_SIZE + 1024);
|
|
|
|
|
packet->m_body = (char *)packet + RTMP_HEAD_SIZE;
|
|
|
|
|
body = (unsigned char *)packet->m_body;
|
|
|
|
|
|
|
|
|
|
body[0] = 0xaf;
|
|
|
|
|
body[1] = 0x00;
|
|
|
|
|
|
|
|
|
|
uint16_t audioSpecConf = 0;
|
|
|
|
|
audioSpecConf |= ((2 << 11) & 0xf800); //2: AACLC
|
|
|
|
|
audioSpecConf |= ((4 << 7) & 0x0780); //4: 44khz
|
|
|
|
|
audioSpecConf |= ((2 << 3) & 0x78); //4: 2:stero
|
|
|
|
|
audioSpecConf |= 0 & 0x07; //4: 0 padding
|
|
|
|
|
body[2] = (audioSpecConf >> 8) & 0xff;
|
|
|
|
|
body[3] = audioSpecConf & 0xff;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
|
|
|
|
|
packet->m_nBodySize = 4;
|
|
|
|
|
packet->m_nChannel = 0x04;
|
|
|
|
|
packet->m_nTimeStamp = nTimeStamp;
|
|
|
|
|
packet->m_hasAbsTimestamp = 0;
|
|
|
|
|
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
|
|
|
|
|
packet->m_nInfoField2 = m_pRtmp->m_stream_id;
|
|
|
|
|
|
|
|
|
|
/*<2A><><EFBFBD>÷<EFBFBD><C3B7>ͽӿ<CDBD>*/
|
|
|
|
|
int nRet = RTMP_SendPacket(m_pRtmp, packet, TRUE);
|
|
|
|
|
free(packet); //<2F>ͷ<EFBFBD><CDB7>ڴ<EFBFBD>
|
|
|
|
|
return nRet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int H264RtmpPuser::sendDataPackAAC(unsigned char * data,
|
|
|
|
|
unsigned int size, unsigned int nTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *gBody = nullptr;
|
|
|
|
|
static int timestamp = 0;
|
|
|
|
|
timestamp += 20;
|
|
|
|
|
if (!mFirtACC) {
|
|
|
|
|
SendAudioSync(2,4,4, timestamp);
|
|
|
|
|
mFirtACC = 1;
|
|
|
|
|
}
|
|
|
|
|
gBody = (unsigned char*)malloc(size + 2);
|
|
|
|
|
gBody[0] = 0xAF;
|
|
|
|
|
gBody[1] = 0x01; //aac raw data
|
|
|
|
|
memcpy(gBody + 2, data + 7, size - 7);
|
|
|
|
|
int bRet = SendPacket(RTMP_PACKET_TYPE_AUDIO, gBody,
|
|
|
|
|
size - 7 + 2, timestamp);
|
|
|
|
|
free(gBody);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void H264RtmpPuser::OnGetCodeFrame(uint8_t * data, int len)
|
|
|
|
|
{
|
|
|
|
|
static int timetamp = 0;
|
|
|
|
|
timetamp += this->mTick;
|
|
|
|
|
uint8_t *pack = (uint8_t*)malloc(len);
|
|
|
|
|
memcpy(pack, data, len);
|
|
|
|
|
mMux.lock();
|
|
|
|
|
Buffer buf;
|
|
|
|
|
buf.buf = pack;
|
|
|
|
|
buf.len = len;
|
|
|
|
|
buf.type = PAYLOAD_TYPE_VIDEO;
|
|
|
|
|
this->mPack.push(buf);
|
|
|
|
|
mMux.unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void H264RtmpPuser::ProcessSend()
|
|
|
|
|
{
|
|
|
|
|
while (this->mIfStart) {
|
|
|
|
|
int len = mPack.size();
|
2023-12-10 17:02:28 +00:00
|
|
|
|
qDebug()<<"unsend size"<<len;
|
2023-11-12 16:13:24 +00:00
|
|
|
|
if (!mPack.empty()) {
|
|
|
|
|
mMux.lock();
|
|
|
|
|
Buffer buf = mPack.front();
|
|
|
|
|
mPack.pop();
|
|
|
|
|
mMux.unlock();
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ֡
|
|
|
|
|
if (buf.type == PAYLOAD_TYPE_VIDEO) {
|
|
|
|
|
this->sortAndSendNal(buf.buf, buf.len);
|
|
|
|
|
|
|
|
|
|
}// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ֡
|
|
|
|
|
if (buf.type == PAYLOAD_TYPE_AUDIO) {
|
|
|
|
|
this->sendDataPackAAC(buf.buf, buf.len, this->mAudioPts);
|
|
|
|
|
}
|
|
|
|
|
free(buf.buf);
|
|
|
|
|
}
|
2023-12-10 17:02:28 +00:00
|
|
|
|
msleep(5);
|
2023-11-12 16:13:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ThreadEncode(H264RtmpPuser * p)
|
|
|
|
|
{
|
|
|
|
|
Debuger::Debug(L"thread started\r\n");
|
|
|
|
|
if (nullptr == p)
|
|
|
|
|
return -1;
|
|
|
|
|
p->ProcessSend();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int H264RtmpPuser::StartPush()
|
|
|
|
|
{
|
|
|
|
|
mIfStart = true;
|
|
|
|
|
this->mThread = new std::thread(ThreadEncode,this);
|
|
|
|
|
mThreadId = this->mThread->get_id();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int H264RtmpPuser::StopPush()
|
|
|
|
|
{
|
|
|
|
|
mIfConnected = false;
|
|
|
|
|
mIfStart = false;
|
|
|
|
|
if(mThread != nullptr)
|
|
|
|
|
this->mThread->join();
|
|
|
|
|
this->RTMP264_Close();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|