I am trying to record my desktop screen and record the audio from microphone simentensously with the help of this python script.
Now when i run only the screen capture part the code works perfectly fine but when i try to run both sound recording and screen capture combine code as shown in below code. my video and audio both file does not open. (0 bytes) or very less size file.
How can i solve this problem.
updated Code
now i am able to record voice properly but the video file is not opening?
import datetime
import tkinter as tk
from tkinter import *
from tkinter import ttk ,FLAT
from PIL import Image, ImageTk, ImageGrab
import cv2
import numpy as np
import threading
import win32api
import pyaudio
import wave
VIDEO_SIZE = (800 , 420) #(960, 540)
p = ImageGrab.grab()
a, b = p.size
chunk = 1024
sample_format = pyaudio.paInt16
channels = 2
fs = 44100
frames = []
g = pyaudio.PyAudio()
date = datetime.datetime.now()
filename='rec_%s-%s-%s-%s-%s-%s.mp4' % (date.year, date.month, date.day,date.hour, date.minute, date.second)
#fourcc = cv2.VideoWriter_fourcc(*'XVID')
frame_rate = 24
cap = cv2.VideoCapture(0)
out = cv2.VideoWriter()
def screen_capturing():
global capturing
capturing = True
while capturing:
img = ImageGrab.grab()
frame = np.array(img)
sc = np.array(img)
_xs,_ys = win32api.GetCursorPos()
cv2.circle(frame,(_xs,_ys),20,(255,255,0), 2)
sc = cv2.resize(sc, VIDEO_SIZE)
tkimage.paste(Image.fromarray(sc))
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
out.write(frame)
def start_screen_capturing():
if not out.isOpened():
out.open(filename, 0x31637661, frame_rate,(VIDEO_SIZE))
t1=threading.Thread(target=screen_capturing, daemon=True)
t1.start()
def stop_screen_capturing():
global capturing
capturing = False
out.release()
def voice_recording():
global recording
while recording:
data = stream.read(chunk)
frames.append(data)
def start_voice_recording():
global stream
stream = g.open(format=sample_format,channels=channels,rate=fs,frames_per_buffer=chunk,input=True)
global recording
recording = True
print('capturing')
t2 = threading.Thread(target=voice_recording) # daemon=True
t2.start()
def stop_voice_recording():
#global recording
recording =False
print(' complete')
filename='test'
filename = filename+".wav"
wf = wave.open(filename,'wb')
wf.setnchannels(channels)
wf.setsampwidth(g.get_sample_size(sample_format))
wf.setframerate(fs)
wf.writeframes(b''.join(frames))
wf.close()
root = tk.Tk()
root.title('Screen Recorder')
root.geometry('+260+70')
tkimage = ImageTk.PhotoImage(Image.new('RGB', VIDEO_SIZE, (0,0,0)))
w, h = VIDEO_SIZE
vbox = tk.Label(root, image=tkimage, width=w, height=h, bg='black')
vbox.pack(pady=10,padx=25)
frame = tk.Frame(root)
frame.pack()
start_cap = tk.Button(frame, text='Start screen Recording', width=30, command=start_screen_capturing)
start_cap.grid(row=0, column=0)
stop_cap = tk.Button(frame, text='Stop screen Recording', width=30, command=stop_screen_capturing)
stop_cap.grid(row=0, column=1)
start_voice = tk.Button(frame, text='Start voice Recording', width=30, command=start_voice_recording)
start_voice.grid(row=0, column=2)
stop_voice = tk.Button(frame, text='Stop voice Recording', width=30, command=stop_voice_recording)
stop_voice.grid(row=0, column=3)
root.mainloop()
Related
I've been writing this code for a slideshow program in Linux. The problem I'm having is that when run from a windows environment it works perfectly (Full-screen resized images), however when run from a virtual Linux (Ubuntu x64) environment a blank white canvas appears with no images being displayed.
The code:
from PIL import Image, ImageTk
import tkinter as tk
import os
import glob
import random
class App(tk.Tk):
def __init__(self, image_files, delay):
tk.Tk.__init__(self)
self.w = self.winfo_screenwidth()
self.h = self.winfo_screenheight()
self.overrideredirect(1)
self.geometry("%dx%d+0+0" % (self.w, self.h))
self.delay = delay
self.pictures = []
self.track_img_ndex = 0
for img in image_files:
self.pictures.append(img)
self.picture_display = tk.Label(self)
self.picture_display.pack(expand=True, fill="both")
def show_slides(self):
if self.track_img_ndex < len(self.pictures):
x = self.pictures[self.track_img_ndex]
self.track_img_ndex +=1
original_image = Image.open(x)
resized = original_image.resize((self.w, self.h),Image.ANTIALIAS)
new_img = ImageTk.PhotoImage(resized)
self.picture_display.config(image=new_img)
self.picture_display.image = new_img
self.title(os.path.basename(x))
self.after(self.delay, self.show_slides)
else:
print("End of list!")
delay = 5000
playlist = glob.glob(r'\mnt\hgfs\E\Images\*.*')
random.shuffle(playlist)
image_files = playlist
app = App(image_files, delay)
app.show_slides()
app.mainloop()
Any help would be appreciated!
winfo_screenwidth() and winfo_screenheight() give not correct display size on Linux. Use full-screen mode to fix it.
The code:
from PIL import Image, ImageTk
import tkinter as tk
import os
import glob
import random
class App(tk.Tk):
def __init__(self, image_files, delay):
tk.Tk.__init__(self)
# start window size (any)
self.w = 500
self.h = 500
self.attributes("-fullscreen", True) # Activate full-screen mode
# Change full-screen mode bind
self.bind("<F11>", lambda event: self.attributes("-fullscreen",
not self.attributes("-fullscreen")))
# Bind full-screen mode exit
self.bind("<Escape>", lambda event: self.attributes("-fullscreen", False))
self.geometry("%dx%d+100+100" % (self.w, self.h))
self.delay = delay
self.pictures = []
self.track_img_ndex = 0
for img in image_files:
self.pictures.append(img)
self.picture_display = tk.Label(self)
self.picture_display.pack(expand=True, fill="both")
def show_slides(self):
if self.track_img_ndex < len(self.pictures):
x = self.pictures[self.track_img_ndex]
self.track_img_ndex += 1
original_image = Image.open(x)
window_size_now = (self.winfo_width(), self.winfo_height()) # Getting current window size :
resized = original_image.resize(window_size_now, Image.ANTIALIAS)
new_img = ImageTk.PhotoImage(resized)
self.picture_display.config(image=new_img)
self.picture_display.image = new_img
self.title(os.path.basename(x))
self.after(self.delay, self.show_slides)
else:
print("End of list!")
_delay = 5000
playlist = glob.glob(r'/home/yaroslav_admin/PycharmProjects/LearnPython_01/imgs/*.*')
random.shuffle(playlist)
_image_files = playlist
app = App(_image_files, _delay)
app.after(100, app.show_slides) # delayed start,
# because tkinter need some time to count full-screen window size in main loop !
app.mainloop()
The enclosed Python code for Raspberry Pi 4 runs separately each function without any problem countdown() and RunThermalCam(), but when running both functions concurrently the timers stop and camera image freeze. My understanding is camera is heavily processor usage so I used multiprocessing, but it gives the following error which I couldn't figure out. The code should first runs GUI then once "Start" button is hit, modules (PWM) runs with countdown timers for each module along with thermal camera.
XIO: fatal IO error 25 (Inappropriate ioctl for device) on X server ":0"
after 1754 requests (1754 known processed) with 38 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python3: ../../src/xcb_io.c:269: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Process ended with exit code -6.
import RPi.GPIO as GPIO
from adafruit_blinka import Enum, Lockable, agnostic
import csv, datetime
from tkinter import *
from tkinter.filedialog import asksaveasfile
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
import multiprocessing
def first():
print("first new time is up \n")
#stop module (1)
def second():
print("second new time is up \n")
#stop module (2)
def third():
print("third new time is up \n")
#stop module (3)
#Create interface#
root = Tk()
root.geometry("1024x600")
root.title("Countdown Timer")
def modules():
if (clockTime[0] == 0 or clockTime[0] == -1):
first()
if(clockTime[1] == 0 or clockTime[1] == -1):
second()
if(clockTime[2] == 0 or clockTime[2] == -1):
third()
#initialize timers lists
timers_number = 3
hrString=[0]*timers_number
minString=[0]*timers_number
secString=[0]*timers_number
totalSeconds = [0]*timers_number
totalMinutes = [0]*timers_number
totalHours = [0]*timers_number
for i in range(timers_number):
hrString[i] = StringVar()
hrString[i].set("00")
for i in range(timers_number):
minString[i] = StringVar()
minString[i].set("00")
for i in range(timers_number):
secString[i] = StringVar()
secString[i].set("00")
#Get User Input
hourTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=hrString[0]).place(x=170, y=100)
minuteTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=minString[0]).place(x=220, y=100)
secondTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=secString[0]).place(x=270, y=100)
hourTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=hrString[1]).place(x=170, y=180)
minuteTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=minString[1]).place(x=220, y=180)
secondTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=secString[1]).place(x=270, y=180)
hourTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=hrString[2]).place(x=170, y=260)
minuteTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=minString[2]).place(x=220, y=260)
secondTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=secString[2]).place(x=270, y=260)
def RunThermalCam():
thermal_mapfile = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')
thermal_mapfile = thermal_mapfile[:16] #limit thermal file name to 16 characters
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) # setup I2C
mlx = adafruit_mlx90640.MLX90640(i2c) # begin MLX90640 with I2C comm
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ # set refresh rate 2Hz
mlx_shape = (24,32)
print("Initialized")
# setup the figure for plotting
plt.ion() # enables interactive plotting
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0,vmax=60) #start plot with zeros
cbar = fig.colorbar(therm1) # setup colorbar for temps
cbar.set_label('Temperature [$^{\circ}$C]',fontsize=14) # colorbar label
#frame = np.zeros((24*32,)) # setup array for storing all 768 temperatures
t_array = []
frame = [0] * 768
while True:
t1 = time.monotonic()
try:
mlx.getFrame(frame) # read MLX temperatures into frame var
data_array = (np.reshape(frame,mlx_shape)) # reshape to 24x32
therm1.set_data(np.fliplr(data_array)) # flip left to right
therm1.set_clim(vmin=np.min(data_array),vmax=np.max(data_array)) # set bounds
cbar.update_normal(therm1) # update colorbar range
plt.title(f"Max Temp: {np.max(data_array):.1f}C")
plt.pause(0.001) # required
t_array.append(time.monotonic()-t1)
print('Sample Rate: {0:2.1f}fps'.format(len(t_array)/np.sum(t_array)))
#except AttributeError:
# continue
except ValueError:
continue # if error, just read again
for h in range(24):
for w in range(32):
t = frame[h*32 + w]
frame = list(np.around(np.array(frame),1)) #round array elements to one decimal point
with open("/home/pi/MOC/Thermal_Camera/"+thermal_mapfile+".csv","a") as thermalfile:
writer = csv.writer(thermalfile,delimiter=" ")
writer.writerow([time.time(),frame])
def countdown():
for i in range (timers_number):
if(clockTime[i] > -1):
totalMinutes[i], totalSeconds[i] = divmod(clockTime[i], 60)
if(totalMinutes[i]>60):
totalHours[i], totalMinutes[i] = divmod(totalMinutes[i], 60)
hrString[i].set("{0:2d}".format(totalHours[i]))
minString[i].set("{0:2d}".format(totalMinutes[i]))
secString[i].set("{0:2d}".format(totalSeconds[i]))
if(clockTime[i] == 0): #time is up
hrString[i].set("00")
minString[i].set("00")
secString[i].set("00")
modules()
if(clockTime[i] != -1): #timer is paused
clockTime[i] -= 1
if(clockTime[i] != -1):
root.after(1000, countdown)
p1 = multiprocessing.Process(target = RunThermalCam)
p2 = multiprocessing.Process(target = countdown)
def starttimer():
#Start_modules()
global clockTime
clockTime = [0]*timers_number
try:
#global clockTime
for i in range (timers_number):
clockTime[i] = int(hrString[i].get())*3600 + int(minString[i].get())*60 + int(secString[i].get())
except:
print("Incorrect values")
countdown()
RunThermalCam()
#p1.start()
#p2.start()
#p1.join()
#p2.join()
def stop():
for i in range (timers_number):
clockTime[i] = 0
def pause():
for i in range (timers_number):
clockTime[i] = -1
modules()
def GUI():
setTimeButton = Button(root, text='START', bd='5', command=starttimer).place(x=200, y=500)
setTimeButton = Button(root, text='STOP', bd='5', command=stop).place(x=350, y=500)
setTimeButton = Button(root, text='PAUSE', bd='5', command=pause).place(x=500, y=500)
root.mainloop()
if __name__ == '__main__':
GUI()
Your code isn't really using multiprocessing.
When you click the start button, tkinter processes the event, and calls the starttimer callback.
This in turn calls RunThermalCam in the current process.
This is a problem, because RunThermalCam has an infinite loop inside it.
So basically, since RunThermalCam runs forever, starttimer will never return. That means that tkinter's event processing grinds to a halt.
I found it is more efficient to use PyQt library instead of tkinter. Timers and other peripherals are running smoothly in parallel with the Thermal Camera Moreover, no need to multiprocessing or multithreading.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication
import RPi.GPIO as GPIO
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
from adafruit_blinka import Enum, Lockable, agnostic
import csv
import datetime
font_1 = "color: blue; font: bold 12px;"
font_2 = "color: blue; font:14px;"
line0 = 0
line1 = 20
line2 = 70
line3 = 120
line4 = 170
line12 = 500
def run_thermal_cam():
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) # setup I2C for thermal camera
thermal_mapfile = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')
thermal_mapfile = thermal_mapfile[:16] #limit thermal file name to 16 characters
print("Thermal cam is ON")
mlx = adafruit_mlx90640.MLX90640(i2c) # begin MLX90640 with I2C comm
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ # set refresh rate 2Hz
mlx_shape = (24,32)
print("Initialized")
# setup the figure for plotting
plt.ion() # enables interactive plotting
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0,vmax=60) #start plot with zeros
cbar = fig.colorbar(therm1) # setup colorbar for temps
cbar.set_label('Temperature [$^{\circ}$C]',fontsize=14) # colorbar label
t_array = []
frame = [0] * 768
t1 = time.monotonic()
while True:
try:
mlx.getFrame(frame) # read MLX temperatures into frame var
data_array = (np.reshape(frame,mlx_shape)) # reshape to 24x32
therm1.set_data(np.fliplr(data_array)) # flip left to right
therm1.set_clim(vmin=np.min(data_array),vmax=np.max(data_array)) # set bounds
cbar.update_normal(therm1) # update colorbar range
plt.title(f"Max Temp: {np.max(data_array):.1f}C")
plt.pause(0.001) # required
t_array.append(time.monotonic()-t1)
except ValueError:
continue # if error, just read again
for h in range(24):
for w in range(32):
t = frame[h*32 + w]
frame = list(np.around(np.array(frame),1)) #round array elements to one decimal point
with open("/home/pi/Thermal_Camera/"+thermal_mapfile+".csv","a") as thermalfile:
writer = csv.writer(thermalfile,delimiter=" ")
unix_time = time.time()
formatted_time = datetime.datetime.fromtimestamp(unix_time).strftime('%H:%M:%S')
writer.writerow([formatted_time,frame])
class TimerApp(QtWidgets.QWidget):
def __init__(self):
super().__init__()
# Create layout
self.setGeometry(0, 0, 1024, 600)
self.setWindowTitle("Thermal Camera")
self.setStyleSheet(font_2) #control timers color & font
# Create countdown timers
self.timer1 = QtWidgets.QTimeEdit(self)
self.timer1.setDisplayFormat("HH:mm:ss")
self.timer1.setGeometry(QtCore.QRect(920, line2-10, 85, 25))
self.timer1.setTime(QtCore.QTime(0, 0, 0))
self.timer2 = QtWidgets.QTimeEdit(self)
self.timer2.setDisplayFormat("HH:mm:ss")
self.timer2.setGeometry(QtCore.QRect(920, line3-10, 85, 25))
self.timer2.setTime(QtCore.QTime(0, 0, 0))
self.timer3 = QtWidgets.QTimeEdit(self)
self.timer3.setDisplayFormat("HH:mm:ss")
self.timer3.setGeometry(QtCore.QRect(920, line4-10, 85, 25))
self.timer3.setTime(QtCore.QTime(0, 0, 0))
# Create start button
self.start_button = QtWidgets.QPushButton("Start", self)
self.start_button.setGeometry(250, line12, 55, 55)
self.start_button.clicked.connect(self.start)
# Connect start button to start function
self.start_button.clicked.connect(self.start)
# Create timer
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.countdown)
def start(self):
self.timer.start(1000) # start all timers #
run_thermal_cam()
def countdown(self):
if self.timer1.time() > QtCore.QTime(0, 0, 0):
new_time = self.timer1.time().addSecs(-1)
self.timer1.setTime(new_time)
if self.timer2.time() > QtCore.QTime(0, 0, 0):
new_time = self.timer2.time().addSecs(-1)
self.timer2.setTime(new_time)
if self.timer3.time() > QtCore.QTime(0, 0, 0):
new_time = self.timer3.time().addSecs(-1)
self.timer3.setTime(new_time)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
timer_app = TimerApp()
timer_app.show()
sys.exit(app.exec_())
I'm having some problems making my gif work in this code.
its a kind of media player with a graphic equalizer :)
I'm trying to make gif play inside the "pantalla" label. I'm having an attribute error with the frame variable. I've been looking around but cannot solve the problem.
sorry for my mistakes I'm a newbie.
any help will be appreciated.
here the code:
import os
from tkinter import *
from vlc import Instance
import time
app = Tk()
app.title("JlMultimedia")
app.iconbitmap("C:/Users/Thunder/Documents/Projects/Python/auricular.ico")
app.geometry("340x250")
app.config(bg="blue")
frames = [PhotoImage(file='C:/Users/Thunder/Documents/Projects/Python/imagenes/equalizer1.gif', format = 'gif -index %i' %(i)) for i in range(5)]
def update(self, ind):
self.frame = frames[ind]
ind += 1
print(ind)
if ind>4: #With this condition it will play gif infinitely
ind = 0
app.after(100, update, ind)
class Jlmultimedia:
def __init__(self):
self.Player = Instance('--loop')
capa = Frame(app)
capa.config(bg="#ffffff")
capa.pack(expand="1")
capa1 = Frame(capa, bg="#0000ff")
capa1.config()
capa1.pack(expand="1")
pantalla = Label(capa1, image=self.frame)
pantalla.grid(row="0", columnspan="3")
self.playimage = PhotoImage(file="C:/Users/Thunder/Documents/Projects/Python/imagenes/play4.png")
self.stopimage = PhotoImage(file="C:/Users/Thunder/Documents/Projects/Python/imagenes/stop4.png")
self.pauseimage = PhotoImage(file="C:/Users/Thunder/Documents/Projects/Python/imagenes/pause4.png")
self.nextimage = PhotoImage(file="C:/Users/Thunder/Documents/Projects/Python/imagenes/forw4.png")
self.backimage = PhotoImage(file="C:/Users/Thunder/Documents/Projects/Python/imagenes/rew4.png")
capa2 = LabelFrame(capa)
capa2.config(bg="#ffffff")
capa2.pack(expand="1")
playboton = Button(capa2, image=self.playimage, bd="0", command=self.play)
playboton.grid(row="1", column="1")
self.volVar = IntVar()
volboton = Scale(capa2, from_=100, to=0, resolution=1, length=90,
label="Vol", variable=self.volVar, command=self.set_volume)
volboton.grid(row="1", column="6")
stopboton = Button(capa2, image=self.stopimage, bd="0", command=self.stop)
stopboton.grid(row="1", column="2")
pauseboton = Button(capa2, image=self.pauseimage, bd="0", command=self.pause)
pauseboton.grid(row="1", column="4")
nextboton = Button(capa2, image=self.nextimage, bd="0", command=self.next)
nextboton.grid(row="1", column="3")
preboton = Button(capa2, image=self.backimage, bd="0", command=self.previous)
preboton.grid(row="1", column="5")
# panel to hold player time slider
self.timeVar = DoubleVar()
self.timeSliderLast = 0
self.timeSlider = Scale(capa1, variable=self.timeVar, command=self.OnTime,
from_=0, to=1000, orient=HORIZONTAL, length=328, showvalue=0) # label='Time',
#self.timeSlider.pack(side=BOTTOM, fill=X, expand=1)
self.timeSliderUpdate = time.time()
self.timeSlider.grid(row="1", columnspan="5")
def addPlaylist(self):
self.mediaList = self.Player.media_list_new()
path = r"C:/Users/Thunder/Documents/Projects/Python/musica"
songs = os.listdir(path)
for s in songs:
self.mediaList.add_media(self.Player.media_new(os.path.join(path,s)))
self.listPlayer = self.Player.media_list_player_new()
self.listPlayer.set_media_list(self.mediaList)
def set_volume(self, *unuse):
vol = min(self.volVar.get(), 100)
self.listPlayer.get_media_player().audio_set_volume(vol)
def play(self):
self.listPlayer.play()
def next(self):
self.listPlayer.next()
def pause(self):
self.listPlayer.pause()
def previous(self):
self.listPlayer.previous()
def stop(self):
self.listPlayer.stop()
def OnTime(self, *unused):
if self.listPlayer:
t = self.timeVar.get()
if self.timeSliderLast != int(t):
self.listPlayer.get_media_player().set_time(int(t * 1e3)) # milliseconds
self.timeSliderUpdate = time.time()
myPlayer = Jlmultimedia()
myPlayer.addPlaylist()
app = mainloop()
There are several issues:
update() has never been executed
image option of label pantalla should be update as well inside update()
pantalla is a local variable inside Jlmultimedia.__init__(), you should make it instance variable self.pantalla
self.frame is undefined
app = mainloop() should be app.mainloop()
Below is a modified update():
def update(ind=0):
myPlayer.pantalla.config(image=frames[ind%len(frames)])
app.after(100, update, ind+1)
And changing pantalla to instance variable inside __init__():
class Jlmultimedia:
def __init__(self):
...
self.pantalla = Label(capa1)
self.pantalla(row=0, columnspan=3)
...
Then call update() before app.mainloop():
...
update()
app.mainloop()
i am trying to record sound from pyaudio in python and making a gui for the same.
my code run fine when i use datetime library and give the filename eg.sound_2020_21_04_03_40.wav which is current date,time but when i try to take the filename from user with tkinter (from tkinter.filedialog import asksaveasfile) it is saving the sound file but its empty with 0 bytes.
can any on e help me in this. this is my coding part of stop button which terminate the code and save the file.
import tkinter as tk
import threading
import pyaudio
import wave
from tkinter import *
import tkinter.font as font
from tkinter.filedialog import asksaveasfile
class App():
chunk = 1024
sample_format = pyaudio.paInt16
channels = 2
fs = 44100
frames = []
def __init__(self, master):
self.isrecording = False
myFont = font.Font(weight="bold")
self.button1 = tk.Button(main, text='Record',command=self.startrecording,height=2,width=20,bg='#0052cc', fg='#ffffff')
self.button2 = tk.Button(main, text='stop',command=self.stoprecording,height=2,width=20,bg='#0052cc', fg='#ffffff')
self.button1['font'] = myFont
self.button2['font'] = myFont
self.button1.place(x=30, y=30)
self.button2.place(x=280, y=30)
def startrecording(self):
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=self.sample_format,channels=self.channels,rate=self.fs,frames_per_buffer=self.chunk,input=True)
self.isrecording = True
print('Recording')
t = threading.Thread(target=self.record)
t.start()
def stoprecording(self):
self.isrecording = False
print('recording complete')
self.filename = asksaveasfile(initialdir = "/",title = "Save as",mode='w',filetypes = (("audio file","*.wav"),("all files","*.*")),defaultextension=".wav")
wf = wave.open(self.filename, 'wb')
wf.setnchannels(self.channels)
wf.setsampwidth(self.p.get_sample_size(self.sample_format))
wf.setframerate(self.fs)
wf.writeframes(b''.join(self.frames))
wf.close()
main.destroy()
def record(self):
while self.isrecording:
data = self.stream.read(self.chunk)
self.frames.append(data)
main = tk.Tk()
main.title('recorder')
main.geometry('520x120')
app = App(main)
main.mainloop()
image is here
It's strange that no exceptions were risen, because when you call askopenfile(...) it returns a file object (and opens an empty file for reading - that file you have seen), but wave.open(...) expects a filename. To get it, you need to use askopenfilename(...) instead of askopenfile(...). And don't forget to import askopenfilename in the top of your code.
Here is the full code (I have refactored it according to PEP8):
import tkinter as tk
import threading
import pyaudio
import wave
from tkinter import *
import tkinter.font as font
from tkinter.filedialog import asksaveasfilename
class App():
chunk = 1024
sample_format = pyaudio.paInt16
channels = 2
fs = 44100
frames = []
def __init__(self, master):
self.isrecording = False
myFont = font.Font(weight="bold")
self.button1 = tk.Button(main, text='Record', command=self.startrecording,
height=2, width=20, bg='#0052cc', fg='#ffffff')
self.button2 = tk.Button(main, text='stop', command=self.stoprecording,
height=2, width=20, bg='#0052cc', fg='#ffffff')
self.button1['font'] = myFont
self.button2['font'] = myFont
self.button1.place(x=30, y=30)
self.button2.place(x=280, y=30)
def startrecording(self):
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=self.sample_format, channels=self.channels,
rate=self.fs, frames_per_buffer=self.chunk, input=True)
self.isrecording = True
print('Recording')
t = threading.Thread(target=self.record)
t.start()
def stoprecording(self):
self.isrecording = False
print('recording complete')
self.filename = asksaveasfilename(initialdir="/", title="Save as",
filetypes=(("audio file", "*.wav"), ("all files", "*.*")),
defaultextension=".wav")
wf = wave.open(self.filename, 'wb')
wf.setnchannels(self.channels)
wf.setsampwidth(self.p.get_sample_size(self.sample_format))
wf.setframerate(self.fs)
wf.writeframes(b''.join(self.frames))
wf.close()
main.destroy()
def record(self):
while self.isrecording:
data = self.stream.read(self.chunk)
self.frames.append(data)
print("does it")
main = tk.Tk()
main.title('recorder')
main.geometry('520x120')
app = App(main)
main.mainloop()
I am trying to make a simple play/pause application in tkinter. Basically I want to show a video and have a play/pause button underneath.
So, after some research I found this suitable post to show a video using tkinter and opencv:
to show video streaming inside frame in tkinter
When using the code, given in the accepted answer to show a video, there is no problem and I don't see any flickering. Here is the code:
# import the necessary packages
from __future__ import print_function
import tkinter as tk
from PIL import ImageTk, Image
import cv2
root = tk.Tk()
# Create a frame
app = tk.Frame(root, bg="white")
app.grid()
# Create a label in the frame
lmain = tk.Label(app)
lmain.grid()
# Capture from camera
cap = cv2.VideoCapture(r'PATH_TO_VIDEO_FILE')
# function for video streaming
frame_number = 0
def video_stream():
global frame_number
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)
success, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(1, video_stream)
frame_number += 1
video_stream()
root.mainloop()
Now, I slightly altered the code to be able to use the grid manager and add a play button:
# import the necessary packages
from __future__ import print_function
import tkinter as tk
from PIL import ImageTk, Image
import cv2
class PhotoBoothApp:
def __init__(self, path_to_video):
# initialize the root window
self.window = tk.Tk()
self.window.title("Video_Player")
self.videocap = cv2.VideoCapture(path_to_video)
self.frame_number = 0
# Initalize
self.videocap.set(cv2.CAP_PROP_POS_FRAMES, self.frame_number)
success, self.frame = self.videocap.read()
cv2image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGBA)
self.img = Image.fromarray(cv2image)
self.imgtk = ImageTk.PhotoImage(image=self.img)
# Show frames
self.picture_label = tk.Label(self.window, image=self.imgtk, relief=tk.RIDGE).grid(row=0, column=0)
self.btn_next_image=tk.Button(self.window, text="Play", width=50, bg ="green",command=self.video_stream).grid(row=1,column=0)
self.window.mainloop()
def video_stream(self):
self.videocap.set(cv2.CAP_PROP_POS_FRAMES, self.frame_number)
sucess, frame = self.videocap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
self.imgtk = ImageTk.PhotoImage(image=img)
self.picture_label = tk.Label(self.window, image=self.imgtk, relief=tk.RIDGE).grid(row=0, column=0)
# Update Frame Number to display
self.frame_number = self.frame_number + 1
self.window.after(1, self.video_stream)
ph = PhotoBoothApp(r'PATH_TO_FILE')
The problem is that when I execute the above code, the video flickers as if tkinter need to reload something in-between frames. I have no clue why this happens.
P.S. This post here Flickering video in opencv-tkinter integration did not help me.
You need to make two changes: split your self.picture_label line to create a proper reference to your Label object, and then use self.picure_label.config(...) to change the image.
class PhotoBoothApp:
def __init__(self, path_to_video):
# initialize the root window
...
self.picture_label = tk.Label(self.window, image=self.imgtk, relief=tk.RIDGE)
self.picture_label.grid(row=0, column=0)
...
def video_stream(self):
...
img = Image.fromarray(cv2image)
self.imgtk = ImageTk.PhotoImage(image=img)
self.picture_label.config(image=self.imgtk)
# Update Frame Number to display
self.frame_number = self.frame_number + 1
self.window.after(1, self.video_stream)
ph = PhotoBoothApp(r'PATH_TO_FILE')