基于DirectShow的虚拟摄像头RTP接收后卡顿问题求助
DirectShow虚拟摄像头卡顿问题排查求助
基于DirectShow开发的虚拟摄像头,原本运行正常。集成uvgRTP库后,通过独立线程接收H264格式的RTP帧,将帧数据存入自定义FrameBuffer队列,再由FillBuffer方法从队列取帧处理。目前前6秒视频播放正常,但之后会出现严重卡顿。已测试确认RTP接收的帧无问题,推测可能是FillBuffer处理速度不足,但无法确定具体原因,寻求有DirectShow虚拟摄像头开发经验的开发者协助排查。
调试发现队列大小在5-12之间波动,未超过20帧,但FillBuffer处理速度未达到理想状态(理想队列大小为1)。
RTP接收及入队代码
void CVCamStream::rtpThreadProc(CVCamStream* obj) { constexpr uint16_t LOCAL_PORT = 12480; constexpr char LOCAL_ADDRESS[] = "::"; uvgrtp::context ctx; uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS); int flags = RCE_RECEIVE_ONLY; uvgrtp::media_stream* receiver = sess->create_stream(LOCAL_PORT, RTP_FORMAT_H264, flags); if (receiver) { while (!obj->m_quit_thread) { uvgrtp::frame::rtp_frame* frame = receiver->pull_frame(); if (frame) { std::vector<uint8_t> newFrame(frame->payload, frame->payload + frame->payload_len); obj->frameBuffer_.Push(newFrame); uvgrtp::frame::dealloc_frame(frame); } } } if (sess) { ctx.destroy_session(sess); } }
FrameBuffer队列实现
class FrameBuffer { public: // Push a new frame onto the queue void Push(const std::vector<uint8_t>& frame) { // Locks the queue with a mutex to prevent concurrent access issues std::unique_lock<std::mutex> lock(mutex_); // Adds the new frame to the end of the queue queue_.push(frame); condVar_.notify_one(); // Notify one waiting thread // Debugging: Logs the addition of a new frame and the current queue size std::wstringstream wss; wss << L"Pushed a frame. Queue size: " << queue_.size() << L"\n"; OutputDebugString(wss.str().c_str()); } // Pop a frame from the queue bool Pop(std::vector<uint8_t>& frame) { std::unique_lock<std::mutex> lock(mutex_); while (queue_.empty()) { condVar_.wait(lock); // Wait until there's a frame // Optional: Return false or break if shutting down } // Once there are at least 100 frames, proceed to pop a frame frame = std::move(queue_.front()); queue_.pop(); return true; } };
FillBuffer处理代码
HRESULT CVCamStream::FillBuffer(IMediaSample* pms) { std::vector<uint8_t> frameData; frameBuffer_.Pop(frameData); long bufferSize = pms->GetSize(); if (bufferSize < frameData.size()) { return E_FAIL; } BYTE* pData = nullptr; pms->GetPointer(&pData); memcpy(pData, frameData.data(), frameData.size()); pms->SetActualDataLength(frameData.size()); return NOERROR; }
媒体类型配置代码
HRESULT CVCamStream::GetMediaType(CMediaType* pMediaType) { pMediaType->InitMediaType(); pMediaType->SetType(&MEDIATYPE_Video); pMediaType->SetSubtype(&MEDIASUBTYPE_AVC1); pMediaType->SetFormatType(&FORMAT_MPEG2_VIDEO); pMediaType->bFixedSizeSamples = FALSE; pMediaType->bTemporalCompression = TRUE; // Our H.264 codec only supports baseline, we can't extract // width and height for other .264 sources. In this case // the value will still be 0. Hence just set any value. unsigned uiWidth = 1080; unsigned uiHeight = 2280; MPEG2VIDEOINFO* mpeg2 = (MPEG2VIDEOINFO*)pMediaType->AllocFormatBuffer(sizeof(MPEG2VIDEOINFO) + 80); ZeroMemory(mpeg2, sizeof(MPEG2VIDEOINFO) + 80); mpeg2->dwProfile = 66; mpeg2->dwLevel = 51; mpeg2->dwFlags = 4; /* byte sps[] = { 103, 66, 128, 10, 218, 1, 12, 4, 118, 128, 109, 10, 19, 80 };*/ byte pps[] = { 104, 206, 6, 242, 1, 2, 3, 4 }; byte parameters[] = { // SPS length and data (unchanged) 0, 14, 103, 66, 128, 10, 218, 1, 12, 4, 118, 128, 109, 10, 19, 80, // Updated PPS length and new data 0, 8, // Note the length change here to 8 because of the new PPS size 104, 206, 6, 242, 1, 2, 3, 4 // New PPS data }; mpeg2->cbSequenceHeader = sizeof(parameters); memcpy(mpeg2->dwSequenceHeader, parameters, sizeof(parameters)); VIDEOINFOHEADER2* pvi2 = &mpeg2->hdr; pvi2->bmiHeader.biBitCount = 12; pvi2->bmiHeader.biPlanes = 3; pvi2->bmiHeader.biWidth = uiWidth; pvi2->bmiHeader.biHeight = uiHeight; pvi2->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pvi2->bmiHeader.biSizeImage = DIBSIZE(pvi2->bmiHeader); pvi2->bmiHeader.biCompression = FOURCC("lvca"); //pvi2->AvgTimePerFrame = m_tFrame; // pvi2->AvgTimePerFrame = 100000; //pvi2->AvgTimePerFrame = 10000000 / 30; //SetRect(&pvi2->rcSource, 0, 0, m_cx, m_cy); SetRect(&pvi2->rcSource, 0, 0, uiWidth, uiHeight); pvi2->rcTarget = pvi2->rcSource; pvi2->dwPictAspectRatioX = uiWidth; pvi2->dwPictAspectRatioY = uiHeight; //pvi2->dwBitRate = 1500000; return NOERROR; } // GetMediaType
内容的提问来源于stack exchange,提问作者Ajdin Jusic
相关产品推荐
相关产品推荐

