| | |
| | | #include "PreAllocBufferQueue.h"
|
| | | #include "MediaHelper.h"
|
| | |
|
| | | typedef enum {
|
| | | NALU_TYPE_SLICE = 1,
|
| | | NALU_TYPE_DPA = 2,
|
| | | NALU_TYPE_DPB = 3,
|
| | | NALU_TYPE_DPC = 4,
|
| | | NALU_TYPE_IDR = 5,
|
| | | NALU_TYPE_SEI = 6,
|
| | | NALU_TYPE_SPS = 7,
|
| | | NALU_TYPE_PPS = 8,
|
| | | NALU_TYPE_AUD = 9,
|
| | | NALU_TYPE_EOSEQ = 10,
|
| | | NALU_TYPE_EOSTREAM = 11,
|
| | | NALU_TYPE_FILL = 12,
|
| | | } NaluType;
|
| | |
|
| | | typedef struct
|
| | | {
|
| | | int startcodeprefix_len; //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
|
| | | unsigned len; //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
|
| | | unsigned max_size; //! Nal Unit Buffer size
|
| | | int forbidden_bit; //! should be always FALSE
|
| | | int nal_reference_idc; //! NALU_PRIORITY_xxxx
|
| | | int nal_unit_type; //! NALU_TYPE_xxxx
|
| | | char *buf; //! contains the first byte followed by the EBSP
|
| | | } NALU_t;
|
| | |
|
| | | struct RTSPServer2_Internal
|
| | | {
|
| | | RTSPServer2Config config;
|
| | |
| | | PreAllocBufferQueue* frameQueue;
|
| | | pthread_mutex_t* queue_mutex;
|
| | | pthread_mutex_t* queue_empty_mutex;
|
| | | pthread_mutex_t* queue_full_mutex;
|
| | |
|
| | | bool auxLineSet;
|
| | |
|
| | | uint8_t lastSps[50];
|
| | | uint8_t lastPps[50];
|
| | | uint8_t lastSpsPps[100];
|
| | |
|
| | | size_t lastSpsSize;
|
| | | size_t lastPpsSize;
|
| | |
|
| | | RTSPServer2_Internal() :
|
| | | config(),
|
| | | live_daemon_thid(0), live_daemon_running(false),
|
| | | server(nullptr),
|
| | | frameQueue(nullptr), queue_mutex(new pthread_mutex_t), queue_empty_mutex(new pthread_mutex_t), //#todo from config
|
| | | auxLineSet(false)
|
| | | frameQueue(nullptr), queue_mutex(nullptr), queue_empty_mutex(nullptr), queue_full_mutex(nullptr), //#todo from config
|
| | | auxLineSet(false),
|
| | | lastSps(), lastPps(),lastSpsPps(),lastSpsSize(0),lastPpsSize(0)
|
| | | {
|
| | | pthread_mutex_init(queue_mutex, NULL);
|
| | | }
|
| | |
|
| | | ~RTSPServer2_Internal()
|
| | |
| | | delete queue_mutex;
|
| | | queue_mutex = nullptr;
|
| | | }
|
| | | |
| | | queue_mutex = new pthread_mutex_t;
|
| | | pthread_mutex_init(queue_mutex, NULL);
|
| | |
|
| | |
| | | delete queue_empty_mutex;
|
| | | queue_empty_mutex = nullptr;
|
| | | }
|
| | |
|
| | | queue_empty_mutex = new pthread_mutex_t;
|
| | | pthread_mutex_init(queue_empty_mutex, NULL);
|
| | |
|
| | | if (queue_full_mutex != nullptr)
|
| | | {
|
| | | pthread_mutex_destroy(queue_full_mutex);
|
| | | delete queue_full_mutex;
|
| | | queue_full_mutex = nullptr;
|
| | | }
|
| | | queue_full_mutex = new pthread_mutex_t;
|
| | | pthread_mutex_init(queue_full_mutex, NULL);
|
| | |
|
| | | live_daemon_thid = 0;
|
| | | live_daemon_running = false;
|
| | |
| | | server = nullptr; //#todo delete
|
| | |
|
| | | auxLineSet = false;
|
| | | lastSpsSize = 0;
|
| | | lastPpsSize = 0;
|
| | | }
|
| | | };
|
| | |
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | static int get_nalu_info(NALU_t* _p_nalu_info,const uint8_t* _pbuffer,const size_t _len)
|
| | | {
|
| | | if((nullptr==_pbuffer)||(_len<=4))
|
| | | {
|
| | | return -1;
|
| | | }
|
| | | _p_nalu_info->forbidden_bit = _pbuffer[4] & 0x80; //1 bit
|
| | | _p_nalu_info->nal_reference_idc = _pbuffer[4] & 0x60; // 2 bit
|
| | | _p_nalu_info->nal_unit_type = _pbuffer[4] & 0x1f;// 5 bit
|
| | | return 0;
|
| | | }
|
| | |
|
| | | static bool deliverFrame(void* args, uint8_t*& buffer, size_t& buffSize, timeval& pts)
|
| | | {
|
| | | DeliverFrameCallback* _this = (DeliverFrameCallback*)args;
|
| | |
|
| | | if (_this->in->config.payBlockFullQueue && !_this->in->frameQueue->Full())
|
| | | {
|
| | | int ret = pthread_mutex_unlock(_this->in->queue_full_mutex);
|
| | | if (ret != 0)
|
| | | {
|
| | | LOG_WARN << "pthread_mutex_unlock queue_full_mutex, ret=" << ret << LOG_ENDL;
|
| | | }
|
| | | }
|
| | |
|
| | | if (_this->in->frameQueue->Empty())
|
| | | {
|
| | | int ret = pthread_mutex_lock(_this->in->queue_empty_mutex);
|
| | | if (ret != 0)
|
| | | {
|
| | | LOG_WARN << "pthread_mutex_lock queue_empty_mutex, ret=" << ret << std::endl;
|
| | | LOG_WARN << "pthread_mutex_lock queue_empty_mutex, ret=" << ret << LOG_ENDL;
|
| | | }
|
| | | }
|
| | |
|
| | | int ret = pthread_mutex_lock(_this->in->queue_empty_mutex);
|
| | | if (ret != 0)
|
| | | {
|
| | | LOG_WARN << "pthread_mutex_lock queue_empty_mutex, ret=" << ret << std::endl;
|
| | | LOG_WARN << "pthread_mutex_lock queue_empty_mutex, ret=" << ret << LOG_ENDL;
|
| | | }
|
| | |
|
| | | ScopeLocker<pthread_mutex_t>(_this->in->queue_mutex);
|
| | |
| | | _this->lastBuffer = nullptr;
|
| | | }
|
| | |
|
| | | //#todo
|
| | | #if 0
|
| | | //find frameQueue->Seek is pps/sps
|
| | | PreAllocBufferQueue::Buffer* _p_Buffer = _this->in->frameQueue->Seek();
|
| | | // if not: send bufferred pps , return;
|
| | |
|
| | | NALU_t _obj_NALU_t;
|
| | | get_nalu_info(&_obj_NALU_t,_p_Buffer->buffer,_p_Buffer->buffSize);
|
| | | if(NALU_TYPE_PPS!=_obj_NALU_t.nal_unit_type)
|
| | | {
|
| | | memcpy(_this->in->lastSpsPps,_this->in->lastSps,_this->in->lastSpsSize);
|
| | | memcpy(_this->in->lastSpsPps+_this->in->lastSpsSize,_this->in->lastPps,_this->in->lastPpsSize);
|
| | | buffer = _this->in->lastSpsPps;
|
| | | buffSize = _this->in->lastSpsSize+_this->in->lastPpsSize;
|
| | | gettimeofday(&pts, NULL);
|
| | | return true;
|
| | | }
|
| | | #endif
|
| | |
|
| | |
|
| | | _this->lastBuffer = _this->in->frameQueue->Dequeue();
|
| | | if (_this->lastBuffer == nullptr)
|
| | | return false;
|
| | |
|
| | | buffer = _this->lastBuffer->buffer;
|
| | | buffSize = _this->lastBuffer->buffSize;
|
| | | buffer = _this->lastBuffer->buffer + 4; // #todo send nalu
|
| | | buffSize = _this->lastBuffer->buffSize - 4;
|
| | | //LOG_WARN << "sizeS=" << buffSize << LOG_ENDL;
|
| | |
|
| | | //LOG_INFO << "DeliverFrameCallback buffSize=" << buffSize << LOG_ENDL;
|
| | | //static size_t f = 0;
|
| | | //static FILE *pFile = fopen("/data/bb.264", "wb");
|
| | | //fwrite(buffer, sizeof(char), buffSize, pFile);
|
| | | //fflush(pFile);
|
| | | //if (++f > 30){
|
| | | // fclose(pFile);
|
| | | // exit(0);
|
| | |
| | | qcfg.multithreadSafe = false;
|
| | | qcfg.fullQueueDropFront = true;
|
| | | qcfg.fullQueueSync = false;
|
| | | qcfg.count = 32;
|
| | | qcfg.maxBuffSize = 200000;
|
| | | qcfg.count = 20;
|
| | | qcfg.maxBuffSize = 524288; // 512KB
|
| | | in->frameQueue = new PreAllocBufferQueue(qcfg);
|
| | |
|
| | | int ret = pthread_create(&(in->live_daemon_thid), NULL, live_daemon_thd, in);
|
| | | if(ret != 0)
|
| | | {
|
| | | LOG_ERROR << "pthread_create: " << strerror(ret) << std::endl;
|
| | | LOG_ERROR << "pthread_create: " << strerror(ret) << LOG_ENDL;
|
| | | return false;
|
| | | }
|
| | |
|
| | |
| | |
|
| | | if (pm.type != PipeMaterial::PMT_FRAME)
|
| | | {
|
| | | LOG_ERROR << "PL_RTSPServer2::pay only support PMT_FRAME" << std::endl;
|
| | | LOG_ERROR << "PL_RTSPServer2::pay only support PMT_FRAME" << LOG_ENDL;
|
| | | return false;
|
| | | }
|
| | |
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | MB_Frame* frame = (MB_Frame*)pm.buffer;
|
| | | if (frame->buffer == nullptr || frame->buffSize == 0)
|
| | | return false;
|
| | | MB_Frame* frame = (MB_Frame*)pm.buffer;
|
| | | if (frame->buffer == nullptr || frame->buffSize == 0)
|
| | | return false;
|
| | | //LOG_WARN << "sizeR=" << frame->buffSize << LOG_ENDL;
|
| | |
|
| | |
|
| | |
|
| | | //#todo
|
| | | #if 0
|
| | | // find if is pps/
|
| | | // buffer the frame into spsRTSPServer2_Internal
|
| | |
|
| | | if(frame->type==MB_Frame::MBFT_H264_NALU)
|
| | | {
|
| | | NALU_t objNALU_t;
|
| | | DeliverFrameCallback::get_nalu_info(&objNALU_t,(const uint8_t*)(frame->buffer),frame->buffSize);
|
| | | if(NALU_TYPE_PPS!=objNALU_t.nal_unit_type)
|
| | | {
|
| | | memcpy(in->lastPps,frame->buffer,frame->buffSize);
|
| | | }
|
| | | else if(NALU_TYPE_SPS!=objNALU_t.nal_unit_type)
|
| | | {
|
| | | memcpy(in->lastSps,frame->buffer,frame->buffSize);
|
| | | }
|
| | | }
|
| | | #endif
|
| | |
|
| | | while (in->config.payBlockFullQueue && in->frameQueue->Full())
|
| | | {
|
| | | int ret = pthread_mutex_lock(in->queue_full_mutex);
|
| | | if (ret != 0)
|
| | | {
|
| | | LOG_WARN << "pthread_mutex_lock queue_full_mutex, ret=" << ret << LOG_ENDL;
|
| | | }
|
| | |
|
| | | //if (in->frameQueue->Full())
|
| | | //{
|
| | | // LOG_WARN << "frameQueue wakeup while full" << LOG_ENDL;
|
| | | // return false;
|
| | | //}
|
| | | }
|
| | |
|
| | | ScopeLocker<pthread_mutex_t>(in->queue_mutex);
|
| | | //if (in->frameQueue->Full())
|
| | | // LOG_WARN << "PL_RTSPServer2::pay may lost data" << std::endl;
|
| | | // LOG_WARN << "PL_RTSPServer2::pay may lost data" << LOG_ENDL;
|
| | |
|
| | | PreAllocBufferQueue::Buffer* qbuff = in->frameQueue->Enqueue();
|
| | | if (qbuff == nullptr)
|
| | | {
|
| | | LOG_WARN << "PL_RTSPServer2::pay may lost data size=" << frame->buffSize << std::endl;
|
| | | LOG_WARN << "PL_RTSPServer2::pay may lost data size=" << frame->buffSize << LOG_ENDL;
|
| | | int ret = pthread_mutex_unlock(in->queue_empty_mutex);
|
| | | if (ret != 0)
|
| | | {
|
| | | LOG_WARN << "pthread_mutex_unlock queue_empty_mutex, ret=" << ret << std::endl;
|
| | | LOG_WARN << "pthread_mutex_unlock queue_empty_mutex, ret=" << ret << LOG_ENDL;
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
|
| | | memcpy(qbuff->buffer, frame->buffer, frame->buffSize);//#todo size min
|
| | | qbuff->buffSize = frame->buffSize;
|
| | | const PreAllocBufferQueue::Config& qcfg(in->frameQueue->GetConfig());
|
| | | size_t copySize = std::min(qcfg.maxBuffSize, frame->buffSize);
|
| | |
|
| | | memcpy(qbuff->buffer, frame->buffer, copySize);//#todo size min
|
| | | qbuff->buffSize = copySize;
|
| | |
|
| | | //static size_t f = 0;
|
| | | //static FILE *pFile = fopen("/data/aa.264", "wb");
|
| | | //fwrite(qbuff->buffer, sizeof(char), frame->buffSize, pFile);
|
| | | //fwrite(qbuff->buffer, sizeof(char), qbuff->buffSize, pFile);
|
| | | //fflush(pFile);
|
| | | //if (++f > 400){
|
| | | // fclose(pFile);
|
| | | // exit(0);
|
| | |
| | | int ret = pthread_mutex_unlock(in->queue_empty_mutex);
|
| | | if (ret != 0)
|
| | | {
|
| | | LOG_WARN << "pthread_mutex_unlock queue_empty_mutex, ret=" << ret << std::endl;
|
| | | LOG_WARN << "pthread_mutex_unlock queue_empty_mutex, ret=" << ret << LOG_ENDL;
|
| | | }
|
| | |
|
| | | if (copySize < frame->buffSize)
|
| | | {
|
| | | LOG_WARN << "copy frame truncated" << LOG_ENDL;
|
| | | }
|
| | |
|
| | | return true;
|
| | | }
|
| | |
|
| | |
| | | pm.buffer = nullptr;
|
| | | pm.buffSize = 0;
|
| | | pm.former = this;
|
| | | return true;
|
| | | return false;
|
| | | }
|