qt_rtmp_demo/media/RtmpPusher.cpp

591 lines
16 KiB
C++
Raw Normal View History

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;
}