diff --git a/src/waylandrecord/avoutputstream.cpp b/src/waylandrecord/avoutputstream.cpp index 567ebd0c3..574d37e71 100644 --- a/src/waylandrecord/avoutputstream.cpp +++ b/src/waylandrecord/avoutputstream.cpp @@ -131,6 +131,13 @@ void CAVOutputStream::SetVideoCodecProp(AVCodecID codec_id, int framerate, int b m_gopsize = gopsize; } +bool CAVOutputStream::shouldUseSingleThread(int width, int height) +{ + const qint64 pixelCount = static_cast(width) * height; + const qint64 fullHdPixelCount = static_cast(1920) * 1080; + return m_boardVendorType != 0 && width > 0 && height > 0 && pixelCount <= fullHdPixelCount; +} + //初始化音频编码器 void CAVOutputStream::SetAudioCodecProp(AVCodecID codec_id, int samplerate, int channels, int layout, int bitrate) { @@ -502,7 +509,10 @@ bool CAVOutputStream::open(QString path) // Set H264 preset and tune avlibInterface::m_av_dict_set(¶m, "preset", "ultrafast", 0); avlibInterface::m_av_dict_set(¶m, "tune", "zerolatency", 0); - avlibInterface::m_av_dict_set(¶m, "crf", "30", 0); // 质量较低,文件较大但编码更快 + avlibInterface::m_av_dict_set(¶m, "crf", "30", 0); + if (shouldUseSingleThread(pCodecCtx->width, pCodecCtx->height)) { + avlibInterface::m_av_dict_set(¶m, "threads", "1", 0); + } } if (avlibInterface::m_avcodec_open2(pCodecCtx, pCodec, ¶m) < 0) { @@ -734,16 +744,11 @@ int CAVOutputStream::writeVideoFrame(WaylandIntegration::WaylandIntegrationPriva //qDebug() << "stride-src: " << pRgbFrame->linesize[0] << pRgbFrame->width*4 << pRgbFrame->linesize[2] << // "stride-dst: " << pFrameYUV->linesize[0] << pFrameYUV->linesize[1] << pFrameYUV->linesize[2]; //qDebug() << "pYUVFrame -w h" << pFrameYUV->width << pFrameYUV->height ; - qint64 time2 = QDateTime::currentMSecsSinceEpoch(); avlibInterface::m_sws_scale(m_pVideoSwsContext, pRgbFrame->data, pRgbFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); - - qint64 time3 = QDateTime::currentMSecsSinceEpoch(); - qDebug() << "time3 - time2: sws_scale : " << time3-time2; if (pRgbFrame->height != pCodecCtx->height && pRgbFrame->width != pCodecCtx->width) { pFrameYUV->width = pCodecCtx->width; pFrameYUV->height = pCodecCtx->height; - qDebug() << "the frame maybe cropped. the frame mybe not be encode. use the codectx as encode frame size"; } else { pFrameYUV->width = pRgbFrame->width; pFrameYUV->height = pRgbFrame->height; @@ -753,8 +758,6 @@ int CAVOutputStream::writeVideoFrame(WaylandIntegration::WaylandIntegrationPriva pFrameYUV->width = pCodecCtx->width; pFrameYUV->height = pCodecCtx->height; - qint64 time2 = QDateTime::currentMSecsSinceEpoch(); - convertARGB2YUV420(pCodecCtx->width, pCodecCtx->height, frame._frame + (m_top * frame._stride + m_left * 4), @@ -791,10 +794,8 @@ int CAVOutputStream::writeVideoFrame(WaylandIntegration::WaylandIntegrationPriva return ret; } } - qint64 time4 = QDateTime::currentMSecsSinceEpoch(); // qDebug() << "time4 - time1: writeVideoFrame : " << time4-time1; avlibInterface::m_av_free_packet(&packet); - fflush(stdout); return 0; } @@ -1205,7 +1206,6 @@ void CAVOutputStream::writeMixAudio() printf("Mixer: failed to call av_buffersink_get_frame_flags ret : %d \n", ret); break; } - fflush(stdout); if (pFrame_out->data[0] != nullptr) { AVPacket packet_out; avlibInterface::m_av_init_packet(&packet_out); diff --git a/src/waylandrecord/avoutputstream.h b/src/waylandrecord/avoutputstream.h index 24c8ff3fe..9caf8cfe3 100644 --- a/src/waylandrecord/avoutputstream.h +++ b/src/waylandrecord/avoutputstream.h @@ -127,6 +127,8 @@ class CAVOutputStream */ bool isNotAudioFifoEmty(); private: + bool shouldUseSingleThread(int width, int height); + /** * @brief 电脑类型 */ diff --git a/src/waylandrecord/waylandintegration.cpp b/src/waylandrecord/waylandintegration.cpp index 438a61e92..3b99d0ada 100644 --- a/src/waylandrecord/waylandintegration.cpp +++ b/src/waylandrecord/waylandintegration.cpp @@ -505,8 +505,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::onDeviceChanged(quint32 name void WaylandIntegration::WaylandIntegrationPrivate::processBuffer(const KWayland::Client::RemoteBuffer *rbuf, const QRect rect) { - qInfo() << __FUNCTION__ << __LINE__ << "开始处理buffer..."; - qDebug() << ">>>>>> open fd!" << rbuf->fd(); // QScopedPointer guard(rbuf); auto dma_fd = rbuf->fd(); quint32 width = rbuf->width(); @@ -562,8 +560,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::processBuffer(const KWayland void WaylandIntegration::WaylandIntegrationPrivate::processBufferHw(const KWayland::Client::RemoteBuffer *rbuf, const QRect rect, int screenId) { - qInfo() << __FUNCTION__ << __LINE__ << "开始处理buffer..."; - qDebug() << ">>>>>> open fd!" << rbuf->fd(); // QScopedPointer guard(rbuf); auto dma_fd = rbuf->fd(); quint32 width = rbuf->width(); @@ -714,7 +710,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::processBufferHw(const KWayla } #endif munmap(mapData, stride * height); - qInfo() << __FUNCTION__ << __LINE__ << "已处理buffer"; } //拷贝数据,当远程buffer没有数据传过来时,调用此接口,将上一次的屏幕数据做为当前的屏幕数据 @@ -765,28 +760,20 @@ QImage::Format WaylandIntegration::WaylandIntegrationPrivate::getImageFormat(qui { switch (format) { case GBM_FORMAT_XRGB8888: //GBM_FORMAT_XRGB8888 = 875713112 - qDebug() << "fd 图片格式: XRGB" << GBM_FORMAT_XRGB8888 << " -> " << "QImage::Format_RGB32"; return QImage::Format_RGB32; case GBM_FORMAT_XBGR8888: //GBM_FORMAT_XBGR8888 = 875709016 - qDebug() << "fd 图片格式: XBGR" << GBM_FORMAT_XBGR8888 << " -> " << "QImage::Format_RGB32"; return QImage::Format_RGB32; case GBM_FORMAT_RGBX8888: //GBM_FORMAT_RGBX8888 = 875714642 - qDebug() << "fd 图片格式: RGBX" << GBM_FORMAT_RGBX8888 << " -> " << "QImage::Format_RGBX8888"; return QImage::Format_RGBX8888; case GBM_FORMAT_BGRX8888: //GBM_FORMAT_BGRX8888 = 875714626 - qDebug() << "fd 图片格式: BGRX" << GBM_FORMAT_BGRX8888 << " -> " << "QImage::Format_BGR30"; return QImage::Format_BGR30; case GBM_FORMAT_ARGB8888: //GBM_FORMAT_ARGB8888 = 875713089 - qDebug() << "fd 图片格式: ARGB" << GBM_FORMAT_ARGB8888 << " -> " << "QImage::Format_ARGB32"; return QImage::Format_ARGB32; case GBM_FORMAT_ABGR8888: //GBM_FORMAT_ABGR8888 = 875708993 - qDebug() << "fd 图片格式: ABGR" << GBM_FORMAT_ABGR8888 << " -> " << "QImage::Format_ARGB32"; return QImage::Format_ARGB32; case GBM_FORMAT_RGBA8888: //GBM_FORMAT_RGBA8888 = 875708754 - qDebug() << "fd 图片格式: RGBA" << GBM_FORMAT_RGBA8888 << " -> " << "QImage::Format_RGBA8888"; return QImage::Format_RGBA8888; case GBM_FORMAT_BGRA8888: //GBM_FORMAT_BGRA8888 = 875708738 - qDebug() << "fd 图片格式: BGRA" << GBM_FORMAT_BGRA8888 << " -> " << "QImage::Format_BGR30"; return QImage::Format_BGR30; default: qDebug() << "fd 图片格式未知: " << format << " -> " << "QImage::Format_RGB32"; @@ -796,8 +783,6 @@ QImage::Format WaylandIntegration::WaylandIntegrationPrivate::getImageFormat(qui void WaylandIntegration::WaylandIntegrationPrivate::processBufferX86(const KWayland::Client::RemoteBuffer *rbuf, const QRect rect) { - qInfo() << __FUNCTION__ << __LINE__ << "开始处理buffer..."; - qDebug() << ">>>>>> open fd!" << rbuf->fd(); //QScopedPointer guard(rbuf); auto dma_fd = rbuf->fd(); quint32 width = rbuf->width(); @@ -901,25 +886,42 @@ void WaylandIntegration::WaylandIntegrationPrivate::appendFrameToList() #else QVector> tempImageVec; + bool frameReady = false; { QMutexLocker locker(&m_bGetScreenImageMutex); if (m_boardVendorType) { - if (!m_curNewImageScreenFrames[0]._flag || !m_curNewImageScreenFrames[1]._flag) continue; - for (int i = 0 ; i < 2 ; i++) { - QImage tempImage = QImage(m_curNewImageScreenFrames[i]._frame, - static_cast(m_curNewImageScreenFrames[i]._width), - static_cast(m_curNewImageScreenFrames[i]._height), - m_curNewImageScreenFrames[i]._format).copy(); - tempImageVec.append(QPair(m_curNewImageScreenFrames[i]._rect, tempImage)); - m_curNewImageScreenFrames[i]._flag = false; + frameReady = isScreenFrameReady(true, + m_screenCount, + m_curNewImageScreenFrames[0]._flag, + m_curNewImageScreenFrames[1]._flag, + m_curNewImageScreen.size()); + if (frameReady) { + for (int i = 0 ; i < 2 ; i++) { + QImage tempImage = QImage(m_curNewImageScreenFrames[i]._frame, + static_cast(m_curNewImageScreenFrames[i]._width), + static_cast(m_curNewImageScreenFrames[i]._height), + m_curNewImageScreenFrames[i]._format).copy(); + tempImageVec.append(QPair(m_curNewImageScreenFrames[i]._rect, tempImage)); + m_curNewImageScreenFrames[i]._flag = false; + } } } else { - if (m_curNewImageScreen.size() != m_screenCount) continue; - for (auto itr = m_curNewImageScreen.begin(); itr != m_curNewImageScreen.end(); ++itr) { - tempImageVec.append(*itr); + frameReady = isScreenFrameReady(false, + m_screenCount, + false, + false, + m_curNewImageScreen.size()); + if (frameReady) { + for (auto itr = m_curNewImageScreen.begin(); itr != m_curNewImageScreen.end(); ++itr) { + tempImageVec.append(*itr); + } } } } + if (!frameReady) { + QThread::msleep(static_cast(delayTime)); + continue; + } QImage img(m_screenSize, QImage::Format_RGBA8888); if (m_boardVendorType) { img = img.convertToFormat(QImage::Format_RGB32); @@ -1055,7 +1057,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::setupRegistry() //qDebug() << "screenGeometry: " << screenGeometry; //qDebug() << "rbuf->isValid(): " << rbuf->isValid(); connect(rbuf, &KWayland::Client::RemoteBuffer::parametersObtained, this, [this, rbuf, screenGeometry] { - qDebug() << "正在处理buffer..." << "fd:" << rbuf->fd() << "frameCount: " << frameCount ; if(frameCount == 0) { qDebug() << "Current number of screens: " << m_screenCount; @@ -1071,7 +1072,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::setupRegistry() } #ifdef KWAYLAND_REMOTE_BUFFER_RELEASE_FLAGE_ON - qDebug()<< "m_screenCount: "<< m_screenCount << "m_isScreenExtension: " << m_isScreenExtension << screenGeometry << "m_currentScreenBufs[0]->" << (m_currentScreenBufs[0] ? "true":"false") << "m_currentScreenBufs[1]->" << (m_currentScreenBufs[1] ? "true":"false");; if (m_screenCount == 1 || !m_isScreenExtension) { if(m_currentScreenBufs[0] == nullptr) @@ -1193,7 +1193,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::setupRegistry() rbuf->release(); #endif } - qDebug() << "buffer已处理" << "fd:" << rbuf->fd() << "frameCount: " << frameCount; }); //qDebug() << "buffer已接收"; }); @@ -1256,13 +1255,9 @@ void WaylandIntegration::WaylandIntegrationPrivate::initEgl() } void WaylandIntegration::WaylandIntegrationPrivate::appendBuffer(unsigned char *frame, int width, int height, int stride, int64_t time) { - static int f_count = 0; - bool res = false; - if (res = !bGetFrame() || nullptr == frame || width <= 0 || height <= 0) { - qDebug() << "drop ...." << res << frame << width << height; + if (!bGetFrame() || nullptr == frame || width <= 0 || height <= 0) { return; } - qDebug() << "append frame index:" << ++f_count; int size = height * stride; unsigned char *ch = nullptr; if (m_bInit) { @@ -1282,7 +1277,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::appendBuffer(unsigned char * //先进先出 //取队首 waylandFrame wFrame = m_waylandList.first(); - memset(wFrame._frame, 0, static_cast(size)); //拷贝当前帧 memcpy(wFrame._frame, frame, static_cast(size)); wFrame._time = time; @@ -1306,7 +1300,6 @@ void WaylandIntegration::WaylandIntegrationPrivate::appendBuffer(unsigned char * wFrame._index = 0; //分配空闲内存 wFrame._frame = m_freeList.first(); - memset(wFrame._frame, 0, static_cast(size)); //拷贝wayland推送的视频帧 memcpy(wFrame._frame, frame, static_cast(size)); m_waylandList.append(wFrame); @@ -1367,6 +1360,10 @@ void WaylandIntegration::WaylandIntegrationPrivate::appendRemoteBuffer() copyScreenData(1); } } + if (m_currentScreenBufs[0] == nullptr + && (m_screenCount != 2 || !m_isScreenExtension || m_currentScreenBufs[1] == nullptr)) { + QThread::msleep(2); + } } qInfo() << "Stop append remote buffer" ; } @@ -1453,14 +1450,10 @@ int WaylandIntegration::WaylandIntegrationPrivate::getPadStride(int width, int d void WaylandIntegration::WaylandIntegrationPrivate::copyBuffer(unsigned char *tmpDst, unsigned char * tmpSrc, const KWayland::Client::RemoteBuffer *rbuf) { - unsigned char *dst = tmpDst; - unsigned char *buf = tmpSrc; - int srcStride = getPadStride(rbuf->width(),4,32); - qDebug()<<"current strade"<height(); i++) { - memcpy(dst, buf, srcStride); - buf += rbuf->stride(); - dst += srcStride; - } + const int rowBytes = getPadStride(rbuf->width(), 4, 32); + copyImageRows(tmpDst, + tmpSrc, + rowBytes, + static_cast(rbuf->height()), + static_cast(rbuf->stride())); } diff --git a/src/waylandrecord/waylandintegration_p.h b/src/waylandrecord/waylandintegration_p.h index 8b21cc54c..2ad371eac 100644 --- a/src/waylandrecord/waylandintegration_p.h +++ b/src/waylandrecord/waylandintegration_p.h @@ -16,6 +16,7 @@ #include #include #include +#include enum audioType { //麦克风 @@ -214,6 +215,35 @@ protected Q_SLOTS: * @brief appendRemoteBuffer 在线程中拷贝远程buffer(remoteaccess传过来的屏幕buffer)的数据 */ void appendRemoteBuffer(); + + static void copyImageRows(unsigned char *destination, + const unsigned char *source, + int rowBytes, + int height, + int sourceStride) + { + if (sourceStride == rowBytes) { + std::memcpy(destination, source, static_cast(rowBytes) * height); + return; + } + + for (int row = 0; row < height; ++row) { + std::memcpy(destination, source, static_cast(rowBytes)); + source += sourceStride; + destination += rowBytes; + } + } + + static bool isScreenFrameReady(bool boardVendorType, + int screenCount, + bool firstScreenReady, + bool secondScreenReady, + int availableImageCount) + { + return boardVendorType + ? firstScreenReady && secondScreenReady + : availableImageCount == screenCount; + } public: /** * @ 内存由getFrame函数内部申请 @@ -367,4 +397,3 @@ protected Q_SLOTS: #endif // XDG_DESKTOP_PORTAL_KDE_WAYLAND_INTEGRATION_P_H - diff --git a/src/waylandrecord/writeframethread.cpp b/src/waylandrecord/writeframethread.cpp index bfa553294..703438d12 100755 --- a/src/waylandrecord/writeframethread.cpp +++ b/src/waylandrecord/writeframethread.cpp @@ -27,6 +27,8 @@ void WriteFrameThread::run() while (m_context->isWriteVideo()) { if (m_context->getFrame(frame)) { m_context->m_recordAdmin->m_pOutputStream->writeVideoFrame(frame); + } else { + QThread::msleep(5); } } m_context->m_recordAdmin->m_cacheMutex.unlock(); diff --git a/tests/ut_screen_shot_recorder/waylandrecord/ut_avoutputstream.h b/tests/ut_screen_shot_recorder/waylandrecord/ut_avoutputstream.h index 780961672..116c02202 100644 --- a/tests/ut_screen_shot_recorder/waylandrecord/ut_avoutputstream.h +++ b/tests/ut_screen_shot_recorder/waylandrecord/ut_avoutputstream.h @@ -333,6 +333,35 @@ ACCESS_PRIVATE_FIELD(CAVOutputStream, uint8_t *, m_out_buffer); ACCESS_PRIVATE_FIELD(CAVOutputStream, AVFilterGraph *, filter_graph); ACCESS_PRIVATE_FIELD(CAVOutputStream, AVFrame *, mMic_frame); ACCESS_PRIVATE_FIELD(CAVOutputStream, AVFrame *, mSpeaker_frame); +ACCESS_PRIVATE_FUN(CAVOutputStream, bool(int, int), shouldUseSingleThread); + +TEST_F(CAVOutputStreamTest, shouldUseSingleThreadForHuaweiFullHD) +{ + m_avOutputStream->setBoardVendor(1); + + EXPECT_TRUE(call_private_fun::CAVOutputStreamshouldUseSingleThread(*m_avOutputStream, 1920, 1080)); +} + +TEST_F(CAVOutputStreamTest, shouldNotUseSingleThreadForHuawei4K) +{ + m_avOutputStream->setBoardVendor(1); + + EXPECT_FALSE(call_private_fun::CAVOutputStreamshouldUseSingleThread(*m_avOutputStream, 3840, 2160)); +} + +TEST_F(CAVOutputStreamTest, shouldNotUseSingleThreadForOtherVendors) +{ + m_avOutputStream->setBoardVendor(0); + + EXPECT_FALSE(call_private_fun::CAVOutputStreamshouldUseSingleThread(*m_avOutputStream, 1920, 1080)); +} + +TEST_F(CAVOutputStreamTest, shouldNotUseSingleThreadForInvalidSize) +{ + m_avOutputStream->setBoardVendor(1); + + EXPECT_FALSE(call_private_fun::CAVOutputStreamshouldUseSingleThread(*m_avOutputStream, 0, 1080)); +} TEST_F(CAVOutputStreamTest, SetVideoCodecProp) { diff --git a/tests/ut_screen_shot_recorder/waylandrecord/ut_waylandintegration_p.h b/tests/ut_screen_shot_recorder/waylandrecord/ut_waylandintegration_p.h index cf754dc40..4564024dc 100644 --- a/tests/ut_screen_shot_recorder/waylandrecord/ut_waylandintegration_p.h +++ b/tests/ut_screen_shot_recorder/waylandrecord/ut_waylandintegration_p.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "stub.h" #include "addr_pri.h" @@ -35,6 +36,53 @@ #include using namespace testing; using namespace WaylandIntegration; + +ACCESS_PRIVATE_STATIC_FUN(WaylandIntegrationPrivate, + void(unsigned char *, const unsigned char *, int, int, int), + copyImageRows); +ACCESS_PRIVATE_STATIC_FUN(WaylandIntegrationPrivate, + bool(bool, int, bool, bool, int), + isScreenFrameReady); + +TEST(WaylandFramePipelineTest, copyImageRowsCopiesContiguousBuffer) +{ + const unsigned char source[] = {1, 2, 3, 4, 5, 6, 7, 8}; + unsigned char destination[sizeof(source)] = {}; + + call_private_static_fun::WaylandIntegrationPrivate::WaylandIntegrationPrivatecopyImageRows( + destination, source, 4, 2, 4); + + EXPECT_EQ(0, std::memcmp(destination, source, sizeof(source))); +} + +TEST(WaylandFramePipelineTest, copyImageRowsSkipsSourcePadding) +{ + const unsigned char source[] = {1, 2, 3, 4, 99, 99, 5, 6, 7, 8, 99, 99}; + const unsigned char expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + unsigned char destination[sizeof(expected)] = {}; + + call_private_static_fun::WaylandIntegrationPrivate::WaylandIntegrationPrivatecopyImageRows( + destination, source, 4, 2, 6); + + EXPECT_EQ(0, std::memcmp(destination, expected, sizeof(expected))); +} + +TEST(WaylandFramePipelineTest, screenFrameIsNotReadyUntilAllVendorBuffersArrive) +{ + EXPECT_FALSE(call_private_static_fun::WaylandIntegrationPrivate::WaylandIntegrationPrivateisScreenFrameReady( + true, 2, true, false, 0)); + EXPECT_TRUE(call_private_static_fun::WaylandIntegrationPrivate::WaylandIntegrationPrivateisScreenFrameReady( + true, 2, true, true, 0)); +} + +TEST(WaylandFramePipelineTest, screenFrameIsNotReadyUntilAllImagesArrive) +{ + EXPECT_FALSE(call_private_static_fun::WaylandIntegrationPrivate::WaylandIntegrationPrivateisScreenFrameReady( + false, 2, false, false, 1)); + EXPECT_TRUE(call_private_static_fun::WaylandIntegrationPrivate::WaylandIntegrationPrivateisScreenFrameReady( + false, 2, false, false, 2)); +} + class WaylandIntegrationPrivateTest: public testing::Test { public: @@ -363,4 +411,3 @@ TEST_F(WaylandIntegrationPrivateTest, appendFrameToList) access_private_field::WaylandIntegrationPrivatem_appendFrameToListFlag(*m_waylandIntegrationPrivate) = false; call_private_fun::WaylandIntegrationPrivateappendFrameToList(*m_waylandIntegrationPrivate); } -