当前位置:   article > 正文

qt+gxdi+ffmpeg远程控制(六)

qt+gxdi+ffmpeg远程控制(六)

qt+gxdi+ffmpeg远程控制(五)

这次主要吧鼠标绘制出来,废了老劲了...

首先需要设置混合模式,不然鼠标的透明部分会呈现出纯黑色,不能直接将鼠标数据复制到抓取的桌面纹理中。

  1. // 透明
  2. ID3D11BlendState* blendState;
  3. D3D11_BLEND_DESC blendDesc = {};
  4. blendDesc.AlphaToCoverageEnable = FALSE;
  5. blendDesc.IndependentBlendEnable = FALSE;
  6. blendDesc.RenderTarget->BlendEnable = TRUE; // 是否开启混合
  7. blendDesc.RenderTarget->SrcBlend = D3D11_BLEND_SRC_ALPHA; // 将源图的 alpha 作为 src rgb 的混合因子
  8. blendDesc.RenderTarget->DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // 将源图的 1-alpha 作为 dst rgb 的混合因子
  9. blendDesc.RenderTarget->BlendOp = D3D11_BLEND_OP_ADD; // 进行相加操作
  10. blendDesc.RenderTarget->SrcBlendAlpha = D3D11_BLEND_ONE; //
  11. blendDesc.RenderTarget->DestBlendAlpha = D3D11_BLEND_ONE;
  12. blendDesc.RenderTarget->BlendOpAlpha = D3D11_BLEND_OP_ADD;
  13. blendDesc.RenderTarget->RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; // 可以写入的位置
  14. this->m_device->CreateBlendState(&blendDesc, &blendState);
  15. const FLOAT BlendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  16. this->m_context->OMSetBlendState(blendState, BlendFactor, 0xffffffff);
  17. SAFE_RELEASE(blendState);

以上是设置混合模式的代码,主要是将鼠标的透明部分正确显示。

需要将鼠标数据读取为单独的纹理,也就是每次渲染两个纹理视图,因此优化了渲染结构。

将所有可绑定到管线的组件统一封装,提供出接口。

  1. class BindAbleInterface {
  2. public:
  3. BindAbleInterface() = default;
  4. virtual void bind(ID3D11DeviceContext* _context) = 0;
  5. virtual ~BindAbleInterface() = default;
  6. };
  7. class IndexBufferBindAble : public BindAbleInterface {
  8. public:
  9. IndexBufferBindAble(ID3D11Device* _device, const UINT16* _indices, size_t _indicesSize);
  10. void bind(ID3D11DeviceContext* _context) override;
  11. ~IndexBufferBindAble() override;
  12. private:
  13. Microsoft::WRL::ComPtr<ID3D11Buffer> m_buffer = nullptr;
  14. };
  15. class VertexScalBufferBindAble: public BindAbleInterface {
  16. public:
  17. __declspec(align(16)) struct {
  18. __declspec(align(16)) struct {
  19. float x;
  20. float y;
  21. float z;
  22. } Scal;
  23. __declspec(align(16)) struct {
  24. float x;
  25. float y;
  26. } Translation;
  27. } m_psConstant;
  28. VertexScalBufferBindAble(ID3D11Device* _device, float _x_rate, float _y_rate, float _z_rate, float _x, float _y);
  29. void bind(ID3D11DeviceContext* _context) override;
  30. void changeTranslation(ID3D11DeviceContext* _context, float _x, float _y);
  31. ~VertexScalBufferBindAble();
  32. private:
  33. Microsoft::WRL::ComPtr<ID3D11Buffer> m_ps_constant_buffer = nullptr;
  34. };
  35. void VertexScalBufferBindAble::bind(ID3D11DeviceContext* _context)
  36. {
  37. _context->VSSetConstantBuffers(0, 1, this->m_ps_constant_buffer.GetAddressOf());
  38. }
  39. void VertexScalBufferBindAble::changeTranslation(ID3D11DeviceContext* _context, float _x, float _y)
  40. {
  41. m_psConstant.Translation.x = _x;
  42. m_psConstant.Translation.y = _y;
  43. D3D11_MAPPED_SUBRESOURCE mapped_resource;
  44. _context->Map(this->m_ps_constant_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource);
  45. memcpy(mapped_resource.pData, (void*)&m_psConstant, sizeof(m_psConstant));
  46. _context->Unmap(this->m_ps_constant_buffer.Get(), 0);
  47. }
  48. VertexScalBufferBindAble::~VertexScalBufferBindAble()
  49. {
  50. }

以上是VertexScalBufferBindAble的例子,给出缩放和平移矩阵,主要给鼠标纹理进行缩放和平移。

修改VertexShader,将变换矩阵乘进去

  1. struct VSOut
  2. {
  3. float2 tex: TEXCOORD;
  4. float4 pos : SV_POSITION;
  5. };
  6. struct Scal {
  7. float x;
  8. float y;
  9. float z;
  10. };
  11. struct Translation {
  12. float x;
  13. float y;
  14. };
  15. cbuffer Cbuf {
  16. Scal scal;
  17. Translation translation;
  18. };
  19. VSOut main_VS(float3 pos : POSITION, float2 tex : TEXCOORD)
  20. {
  21. VSOut vsout;
  22. vsout.pos = float4((pos.x * scal.x) + translation.x, (pos.y * scal.y) + translation.y, pos.z * scal.z, 1);
  23. vsout.tex = tex;
  24. return vsout;
  25. }

接下来,绘制鼠标,其它逻辑详细可以看源码,这里说一下怎么将鼠标转为纹理

  1. void CursorTextureDrawAble::drawCursor(MyDx11* _myDx11)
  2. {
  3. CURSORINFO ci = { 0 };
  4. ci.cbSize = sizeof(ci);
  5. if (!GetCursorInfo(&ci)) {
  6. return;
  7. }
  8. float offset_x = ci.ptScreenPos.x / this->m_base_x;
  9. float offset_y = ci.ptScreenPos.y / this->m_base_y;
  10. offset_x = offset_x * 2 - 1;
  11. offset_y = 1 - offset_y * 2;
  12. this->m_vertex_scal_buffer->changeTranslation(this->getContext(_myDx11), offset_x, offset_y);
  13. if (this->m_cache_cursor == nullptr || this->m_cache_cursor != ci.hCursor) {
  14. this->m_cache_cursor = ci.hCursor;
  15. }
  16. else {
  17. return;
  18. }
  19. }

缓存一下已经获取的鼠标句柄,如果没有变化就不需要更改纹理数据了,算一下鼠标的相对位置进行平移变换。

  1. bool CursorTextureDrawAble::copyFromColor(MyDx11* _myDx11, ICONINFO& _icon_info, BITMAP& _bmp)
  2. {
  3. uint8_t* output = nullptr;
  4. if (GetObject(_icon_info.hbmColor, sizeof(_bmp), &_bmp) == 0) {
  5. return false;
  6. }
  7. unsigned int size = _bmp.bmHeight * _bmp.bmWidthBytes;
  8. output = new uint8_t[size];
  9. GetBitmapBits(_icon_info.hbmColor, size, output);
  10. if (_bmp.bmWidth != this->m_width && _bmp.bmHeight != this->m_height) {
  11. this->changeSize(_myDx11, _bmp.bmWidth, _bmp.bmHeight, false);
  12. }
  13. this->copyData(_myDx11, output, size);
  14. delete[] output;
  15. return true;
  16. }
  17. bool CursorTextureDrawAble::copyFromMask(MyDx11* _myDx11, ICONINFO& _icon_info, BITMAP& _bmp)
  18. {
  19. long pixels;
  20. long bottom;
  21. uint8_t pix_byte;
  22. bool alpha = false;
  23. if (GetObject(_icon_info.hbmMask, sizeof(_bmp), &_bmp) == 0) {
  24. return false;
  25. }
  26. uint8_t* output;
  27. uint8_t* mask;
  28. unsigned int size = _bmp.bmHeight * _bmp.bmWidthBytes;
  29. mask = new uint8_t[size];
  30. GetBitmapBits(_icon_info.hbmMask, size, mask);
  31. _bmp.bmHeight /= 2;
  32. pixels = _bmp.bmHeight * _bmp.bmWidth;
  33. output = new uint8_t[pixels * 4];
  34. ZeroMemory(output, pixels * 4);
  35. bottom = _bmp.bmWidthBytes * _bmp.bmHeight;
  36. for (long i = 0; i < pixels; i++) {
  37. uint8_t andMask = this->bitToAlpha(mask, i);
  38. uint8_t xorMask = this->bitToAlpha(mask + bottom, i);
  39. if (!andMask) {
  40. // black in the AND mask
  41. *(uint32_t*)&output[i * 4] =
  42. !!xorMask ? 0x00FFFFFF /*always white*/
  43. : 0xFF000000 /*always black*/;
  44. }
  45. else {
  46. // white in the AND mask
  47. *(uint32_t*)&output[i * 4] =
  48. !!xorMask ? 0xFFFFFFFF /*source inverted*/
  49. : 0 /*transparent*/;
  50. }
  51. }
  52. if (_bmp.bmWidth != this->m_width && _bmp.bmHeight != this->m_height) {
  53. this->changeSize(_myDx11, _bmp.bmWidth, _bmp.bmHeight, false);
  54. }
  55. this->copyData(_myDx11, output, pixels * 4);
  56. delete[] output;
  57. delete[] mask;
  58. return true;
  59. }
  60. uint8_t CursorTextureDrawAble::bitToAlpha(uint8_t* data, long pixel)
  61. {
  62. uint8_t pix_byte = data[pixel / 8];
  63. bool alpha = (pix_byte >> (7 - pixel % 8) & 1) != 0;
  64. return alpha ? 0xFF : 0;
  65. }
  66. void TextureDrawAble::copyData(MyDx11* _myDx11, uint8_t* _buffer, size_t _size)
  67. {
  68. D3D11_MAPPED_SUBRESOURCE target_map_res;
  69. UINT sub_resource = D3D11CalcSubresource(0, 0, 0);
  70. ID3D11DeviceContext* context = this->getContext(_myDx11);
  71. HRESULT hr = context->Map(this->m_texture.Get(), sub_resource, D3D11_MAP_WRITE_DISCARD, 0, &target_map_res);
  72. if (FAILED(hr)) {
  73. return;
  74. }
  75. memcpy_s(target_map_res.pData, _size, _buffer, _size);
  76. context->Unmap(this->m_texture.Get(), sub_resource);
  77. }

以上是通过鼠标句柄获取到bitmap,再copy到纹理中,参考了obs源码。之前提到当鼠标处于选中文字形状,也就是类似I的形状时获取不到鼠标。其原因在于需要从hbmMask中获取数据。里面的处理逻辑看不太明白,直接拿的obs的源码。

关于编码器性能问题,设置编码线程数可以解决部分问题,但性能依旧不太高。

this->m_encode_pCodecCtx->thread_count = 4;

如果实在不行,考虑使用硬编码方式。

具体详情转到源码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/524972
推荐阅读
相关标签
  

闽ICP备14008679号