用Python來做一個(gè)屏幕錄制工具
↑?關(guān)注 + 星標(biāo)?,每天學(xué)Python新技能
后臺(tái)回復(fù)【大禮包】送你Python自學(xué)大禮包
女朋友是一個(gè)軟件測試人員,在工作中經(jīng)常會(huì)遇到需要錄屏記錄自己操作,方便后續(xù)開發(fā)同學(xué)定位。因?yàn)殇浧淋浖?dòng)不動(dòng)就開始收費(fèi),所以她經(jīng)常更換錄屏軟件。閑暇之余,我就覺得手癢,感覺可以用萬能的 Python 來解決她的煩惱。

思路
我上網(wǎng)搜尋了一下相關(guān)知識(shí),錄制視頻基本上都用的圖像處理庫 PIL 的 ImageGrab 模塊。這個(gè)模塊可以用于將當(dāng)前屏幕的內(nèi)容或者剪貼板上的內(nèi)容拷貝到 PIL 圖像內(nèi)存。
既然這個(gè)模塊可以獲取當(dāng)前屏幕上的內(nèi)容,那么我一直不間斷地獲取,然后把這些獲取的內(nèi)容拼起來,那不就是視頻了嗎?
實(shí)現(xiàn)
錄制
整體思路是 PIL 模塊中的 ImageGrab 不停的獲得當(dāng)前屏幕,利用 opencv 寫入視頻流。
def?video_record(sttime):
????global?name
????#?當(dāng)前的時(shí)間(當(dāng)文件名)
????name?=?datetime.now().strftime('%Y-%m-%d?%H-%M-%S')
????#?獲取當(dāng)前屏幕
????screen?=?ImageGrab.grab()
????#?獲取當(dāng)前屏幕的大小
????width,?high?=?screen.size
????#?MPEG-4編碼,文件后綴可為.avi?.asf?.mov等
????fourcc?=?VideoWriter_fourcc('X',?'V',?'I',?'D')
????#?(文件名,編碼器,幀率,視頻寬高)
????video?=?VideoWriter('%s.avi'?%?name,?fourcc,?15,?(width,?high))
????print(str(sttime)?+?'秒后開始錄制----')
????time.sleep(int(sttime))
????print('開始錄制!')
????global?start_time
????start_time?=?time.time()
????while?True:
????????if?flag:
????????????print("錄制結(jié)束!")
????????????global?final_time
????????????final_time?=?time.time()
????????????#?釋放
????????????video.release()
????????????break
????????#?圖片為RGB模式
????????im?=?ImageGrab.grab()
????????#?轉(zhuǎn)為opencv的BGR模式
????????imm?=?cvtColor(np.array(im),?COLOR_RGB2BGR)
????????#?寫入
????????video.write(imm)
錄制視頻的主要代碼只需幾行即可,但是我們需要對錄制操作進(jìn)行控制,例如開始錄制、結(jié)束錄制等。以及獲取屏幕內(nèi)容之后,需要對內(nèi)容進(jìn)行轉(zhuǎn)碼,然后寫入視頻流。
監(jiān)聽鍵盤事件
錄制視頻我們是使用的一個(gè) while 循環(huán)來獲取屏幕信息,開始之后會(huì)一直進(jìn)行。但是我們需要監(jiān)聽鍵盤事件,來終止這個(gè)循環(huán),從而終止錄制視頻。這個(gè)監(jiān)聽事件就顯得很重要了,這里采用的是 pynput 這個(gè)強(qiáng)大的三方庫,可以全局監(jiān)聽鍵盤、鼠標(biāo)事件。
我們設(shè)定的是用戶在按下鍵盤的 ESC 按鍵后,終止 while 循環(huán),從而終止視頻錄制。
#?監(jiān)聽按鍵
def?on_press(key):
????global?flag
????if?key?==?keyboard.Key.esc:
????????flag?=?True
????????#?返回False,鍵盤監(jiān)聽結(jié)束!
????????return?False
主體控制
因?yàn)槲覀冃枰粩嗟孬@取屏幕內(nèi)容,所以我們最好啟動(dòng)一個(gè)線程來干這個(gè)事情。
th?=?threading.Thread(target=video_record,?args=sstime)
????th.start()
????with?keyboard.Listener(on_press=on_press)?as?listener:
????????listener.join()
視頻信息
錄制視頻結(jié)束之后,我們也可以獲取視頻的一些相關(guān)信息,例如時(shí)長、幀率、分辨率等。
#?視頻信息
def?video_info():
????#?記得文件名加格式不要錯(cuò)!
????video?=?VideoCapture('%s.avi'?%?name)
????fps?=?video.get(CAP_PROP_FPS)
????count?=?video.get(CAP_PROP_FRAME_COUNT)
????size?=?(int(video.get(CAP_PROP_FRAME_WIDTH)),?int(video.get(CAP_PROP_FRAME_HEIGHT)))
????print('幀率=%.1f'?%?fps)
????print('幀數(shù)=%.1f'?%?count)
????print('分辨率',?size)
????print('視頻時(shí)間=%.3f秒'?%?(int(count)?/?fps))
????print('錄制時(shí)間=%.3f秒'?%?(final_time?-?start_time))
????print('推薦幀率=%.2f'?%?(fps?*?((int(count)?/?fps)?/?(final_time?-?start_time))))
效果
最后,我啟兩個(gè)程序,第一個(gè)程序啟動(dòng)錄制之后,我再來操作第二個(gè)程序,這樣大家就可以看到這個(gè)程序的運(yùn)行過程:
總結(jié)
這里的程序只是一個(gè)初版,剛剛實(shí)現(xiàn)了錄制屏幕的想法。后續(xù)還需要對其進(jìn)行改進(jìn),支持 GUI 界面操作,支持框選特定區(qū)域錄制等等。


