我使用了python和c++的组合来创建一个屏幕区域的快照,并将该快照作为视频源的一部分(标签PyQt5中的pixmap),以及将该快照保存为. bmp.,当前的速度为30fps,以便稍后创建视频文件。代码到目前为止工作得很好,除了内存泄漏之外。
cpp,放入libccreator.so
#include "contextcreator.h"
#include <cstring>
#include <stdio.h>
#include <shlwapi.h>
#include <typeinfo>
BYTE* createContext(int x, int y, int width, int height){
HDC hdesktop = GetDC(NULL);
HDC memDC = CreateCompatibleDC(hdesktop);
HBITMAP hbitmap = CreateCompatibleBitmap(hdesktop, width, height);
HGDIOBJ hbitmapOld = (HBITMAP)SelectObject(memDC, hbitmap);
BitBlt(memDC, 0, 0, width, height, hdesktop, x, y, SRCCOPY|CAPTUREBLT);
SelectObject(memDC, hbitmapOld);
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
GetDIBits(hdesktop, hbitmap, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
BYTE* stream = new BYTE[bmi.bmiHeader.biSizeImage];
bmi.bmiHeader.biCompression = BI_RGB;
GetDIBits(hdesktop, hbitmap, 0, bmi.bmiHeader.biHeight, (LPVOID)stream, &bmi, DIB_RGB_COLORS);
BYTE* data = new BYTE[14 + sizeof(bmi) + bmi.bmiHeader.biSizeImage];
memcpy(data + 14, &bmi, sizeof(bmi));
memcpy(&data[0] + sizeof(bmi) + 14, stream, bmi.bmiHeader.biSizeImage);
for(int i = 0; i < 14; i++){
data[i] = 0; }
delete[] stream;
ReleaseDC(NULL, hdesktop);
DeleteDC(memDC);
return data;
}
void releaseData(BYTE* stream){
delete[] stream;
}
利用www.example.com的python代码libccreator.so
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from ctypes import *
import ctypes.wintypes as wintypes
import time
import os
os.add_dll_directory("C:/msys64/mingw64/bin")
mylib = cdll.LoadLibrary('C:/Users/amish_ac2c1jm/OneDrive/Documents/blahblah/libccreator.so')
create_context = mylib.createContext
create_context.argtypes = [c_int, c_int, c_int, c_int]
create_context.restype = POINTER(wintypes.BYTE)
release_stream = mylib.releaseData
release_stream.argtypes = [POINTER(wintypes.BYTE)]
release_stream.restype = None
class CaptureThread(QObject):
finished = pyqtSignal()
update_image = pyqtSignal([bytearray])
def __init__(self, x, y, w, h, parent=None):
super().__init__(parent)
self.x = x
self.y = y
self.w = w
self.h = h
self.stopthread = False
self.framenumber = 0
def run(self):
test_timer = time.time()
while not self.stopthread:
if time.time() - test_timer >= 1000/30/1000:
test_timer = time.time()
self.capture()
self.finished.emit()
def capture(self):
bmpptr = create_context(self.x, self.y, self.w, self.h)
data = bytearray(string_at(addressof(bmpptr.contents) + 0x22, 0x4))
size = int.from_bytes(data, byteorder='little', signed=False) + 0x36
data = bytearray(string_at(bmpptr, size))
release_stream(bmpptr)
data[0:2] = b'BM'
value = int.from_bytes(data[0x22:0x26], byteorder='little', signed=False)
data[2:6] = (value + 0x36).to_bytes(4, byteorder='little', signed=False)
data[6:10] = b'\x00\x00\x00\x00'
data[10:14] = b'\x36\x00\x00\x00'
with open(f"images/frame{self.framenumber}.bmp", "wb") as f:
f.write(data)
self.framenumber += 1
self.update_image.emit(data)
最初我没有删除用new关键字创建的字节数组,导致了一些内存泄漏,当我的显示器开始 Flink ,chrome和pycharm沿着崩溃时,这种内存泄漏问题很快就显现出来了。我最初也没有在[hardware?] DC上使用ReleaseDC,而是使用DeleteDC作为DC和内存DC。我能够在任务管理器中直观地看到内存泄漏,因为我的项目很快就克服了chrome和pycharm的内存使用(这些bmp根本没有压缩......我稍后会研究)。尽管如此,内存泄漏仍然存在,但没有在任务管理器中显示我的应用程序,只是显示我的整体内存使用量逐渐增加,直到我用完内存。大约需要7分钟左右(我有16gb的RAM)。
我觉得这和DC的有些关系,但我不完全确定。我以前有一些使用c的经验,但一旦我学会了python,我就不会错过编译器和链接的问题,至少可以说,哈哈。我在python IDE中使用PyCharm,在c中使用Qt Creator。提前感谢任何帮助:)
1条答案
按热度按时间nom7f22z1#
根据Igor Tandetnik的评论回复,泄漏是由于未删除从CreateCompatibleBitmap函数返回的对象。