Skip to content

feat(ext-image-capture): Enhance screen recording with DMA Buffer sup…#764

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:develop/snipefrom
dengzhongyuan365-dev:treelandcommit1
Nov 27, 2025
Merged

feat(ext-image-capture): Enhance screen recording with DMA Buffer sup…#764
deepin-bot[bot] merged 1 commit into
linuxdeepin:develop/snipefrom
dengzhongyuan365-dev:treelandcommit1

Conversation

@dengzhongyuan365-dev

Copy link
Copy Markdown
Member

…port

  • Introduced a new reset method in ExtCaptureFrameBuffer to prepare for new recording sessions.
  • Updated ExtCaptureRecorder to handle DMA Buffer frames, including new signal dmaFrameReady for processing DMA Buffer data.
  • Enhanced frame handling in ExtCaptureFrame to support DMA Buffer creation and management.
  • Improved logging for recording state changes and frame processing, providing better insights during screen recording sessions.

特性(ext-image-capture): 增强屏幕录制功能,支持DMA缓冲区

  • ExtCaptureFrameBuffer中引入新的reset方法,以准备新的录制会话。
  • 更新ExtCaptureRecorder以处理DMA缓冲区帧,包括新的信号dmaFrameReady用于处理DMA缓冲区数据。
  • 增强ExtCaptureFrame中的帧处理,以支持DMA缓冲区的创建和管理。

…port

- Introduced a new `reset` method in `ExtCaptureFrameBuffer` to prepare for new recording sessions.
- Updated `ExtCaptureRecorder` to handle DMA Buffer frames, including new signal `dmaFrameReady` for processing DMA Buffer data.
- Enhanced frame handling in `ExtCaptureFrame` to support DMA Buffer creation and management.
- Improved logging for recording state changes and frame processing, providing better insights during screen recording sessions.

特性(ext-image-capture): 增强屏幕录制功能,支持DMA缓冲区

- 在`ExtCaptureFrameBuffer`中引入新的`reset`方法,以准备新的录制会话。
- 更新`ExtCaptureRecorder`以处理DMA缓冲区帧,包括新的信号`dmaFrameReady`用于处理DMA缓冲区数据。
- 增强`ExtCaptureFrame`中的帧处理,以支持DMA缓冲区的创建和管理。
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

我来对这段代码进行详细的审查:

  1. 代码结构和逻辑改进:
  • DMA Buffer处理逻辑分散在多个类中,建议创建专门的DMA Buffer管理类来统一处理相关操作
  • reset()函数的实现应该添加错误处理机制,确保在清理过程中出现异常时不会导致资源泄漏
  • processDmaBufferFrame()函数过于复杂,建议拆分成更小的函数
  1. 性能优化建议:
  • m_bufferSize从10增加到1000可能会显著增加内存使用,建议根据实际帧率动态调整
  • DMA Buffer的映射操作可以考虑使用异步方式,避免阻塞主线程
  • 可以添加帧缓冲区使用情况的监控机制,避免内存溢出
  1. 安全性改进:
  • DMA Buffer的文件描述符需要更严格的验证和生命周期管理
  • 内存映射操作应该添加边界检查
  • 对GBM设备的操作需要添加错误恢复机制
  1. 具体修改建议:
// 在ExtCaptureFrameBuffer类中添加
bool ExtCaptureFrameBuffer::reset() {
    QMutexLocker locker(&m_mutex);
    
    try {
        // 检查当前状态
        if (m_initialized) {
            // 保存关键参数
            int oldBufferSize = m_bufferSize;
            
            // 清理现有缓冲区
            cleanupBuffers();
            
            // 验证清理结果
            if (m_workingBuffer || !m_frameQueue.isEmpty()) {
                qWarning() << "Buffer cleanup incomplete";
                return false;
            }
            
            // 重置参数
            m_bufferSize = oldBufferSize;
            m_frameIndex = 0;
            m_frameDataSize = 0;
            m_initialized = false;
            m_getFrameEnabled = true;
            
            qDebug() << "ExtCaptureFrameBuffer::reset: Reset completed successfully";
            return true;
        }
        
        return true;
    } catch (const std::exception& e) {
        qCritical() << "ExtCaptureFrameBuffer::reset: Exception occurred:" << e.what();
        return false;
    }
}

// 添加DMA Buffer管理类
class DmaBufferManager {
public:
    static DmaBufferManager& instance() {
        static DmaBufferManager manager;
        return manager;
    }
    
    bool initialize() {
        if (m_initialized) {
            return true;
        }
        
        // 初始化DRM和GBM
        if (!initDrm()) {
            return false;
        }
        
        if (!initGbm()) {
            cleanupDrm();
            return false;
        }
        
        m_initialized = true;
        return true;
    }
    
    void cleanup() {
        if (!m_initialized) {
            return;
        }
        
        cleanupGbm();
        cleanupDrm();
        m_initialized = false;
    }
    
    gbm_bo* createBuffer(uint32_t width, uint32_t height, uint32_t format) {
        if (!m_initialized) {
            return nullptr;
        }
        
        return gbm_bo_create(m_gbmDevice, width, height, format, 
                           GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
    }
    
private:
    DmaBufferManager() = default;
    ~DmaBufferManager() {
        cleanup();
    }
    
    bool initDrm() {
        m_drmFd = open("/dev/dri/renderD128", O_RDWR);
        if (m_drmFd < 0) {
            m_drmFd = open("/dev/dri/card0", O_RDWR);
            if (m_drmFd < 0) {
                return false;
            }
        }
        return true;
    }
    
    bool initGbm() {
        m_gbmDevice = gbm_create_device(m_drmFd);
        return m_gbmDevice != nullptr;
    }
    
    void cleanupDrm() {
        if (m_drmFd >= 0) {
            close(m_drmFd);
            m_drmFd = -1;
        }
    }
    
    void cleanupGbm() {
        if (m_gbmDevice) {
            gbm_device_destroy(m_gbmDevice);
            m_gbmDevice = nullptr;
        }
    }
    
    bool m_initialized = false;
    int m_drmFd = -1;
    gbm_device* m_gbmDevice = nullptr;
};

// 修改processDmaBufferFrame函数
bool ExtCaptureRecorder::processDmaBufferFrame(int dmaBufferFd, void *gbmBo, int width, int height, int stride) {
    // 参数验证
    if (dmaBufferFd < 0 || !gbmBo || width <= 0 || height <= 0 || stride <= 0) {
        qWarning() << "Invalid parameters";
        return false;
    }
    
    // 获取DMA Buffer管理器实例
    auto& dmaManager = DmaBufferManager::instance();
    
    // 验证缓冲区大小
    size_t expectedSize = static_cast<size_t>(stride) * height;
    struct stat sb;
    if (fstat(dmaBufferFd, &sb) == 0) {
        if (sb.st_size < expectedSize) {
            qWarning() << "Buffer size mismatch: expected" << expectedSize << "got" << sb.st_size;
            return false;
        }
    }
    
    // 映射缓冲区
    void* mappedData = mmap(nullptr, expectedSize, PROT_READ, MAP_SHARED, dmaBufferFd, 0);
    if (mappedData == MAP_FAILED) {
        qWarning() << "Failed to map DMA buffer:" << strerror(errno);
        return false;
    }
    
    // 使用RAII确保资源释放
    struct BufferGuard {
        void* data;
        size_t size;
        ~BufferGuard() {
            if (data && data != MAP_FAILED) {
                munmap(data, size);
            }
        }
    } guard{mappedData, expectedSize};
    
    // 处理帧数据
    if (!m_ffmpegProcess || m_ffmpegProcess->state() != QProcess::Running) {
        qWarning() << "FFmpeg process not running";
        return false;
    }
    
    qint64 bytesWritten = m_ffmpegProcess->write(static_cast<const char*>(mappedData), expectedSize);
    if (bytesWritten != expectedSize) {
        qWarning() << "Failed to write frame data: expected" << expectedSize << "written" << bytesWritten;
        return false;
    }
    
    return true;
}
  1. 其他建议:
  • 添加更多的日志记录,便于调试和监控
  • 考虑添加性能统计功能,监控帧率、延迟等指标
  • 为关键操作添加超时机制,避免无限等待
  • 考虑添加配置选项,允许用户选择是否使用DMA Buffer
  • 添加资源使用监控,防止内存泄漏

这些修改可以提高代码的健壮性、可维护性和性能。建议逐步实施这些改进,并在每个阶段进行充分的测试。

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengzhongyuan365-dev, lzwind

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@dengzhongyuan365-dev

Copy link
Copy Markdown
Member Author

/forcemerge

@deepin-bot

deepin-bot Bot commented Nov 27, 2025

Copy link
Copy Markdown
Contributor

This pr force merged! (status: unstable)

@deepin-bot deepin-bot Bot merged commit 1b8c1f6 into linuxdeepin:develop/snipe Nov 27, 2025
7 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants