问题描述
在我们的一个项目中,客户发现我们的设备产生的MP3文件再使用 ffprobe 分析帧的时候会会出现错误,于是我们想将他们测试方式增加到我们测试工具小面,效果如下:
在点击语音分析的时候,需要完成此次设备录制的mp3语音分析并结果输出到UI上,供测试人员查看,以防以后出现类似的问题:
'''
* Class Name : tab_check
* Description : voc_tab 增量检查
* Input : table_ui
'''
def tab_check(tab_ui, dtq_dict, uID):
global voc_cnt
global line_dict
if uID not in line_dict:
line_dict[uID] = voc_cnt
tab_ui.setRowCount(voc_cnt + 1)
tab_ui.setRowHeight(voc_cnt, TAB_ROW_HIGHT)
# 行数自增
voc_cnt = voc_cnt + 1
dtq_dict[uID].upos = voc_cnt
# 增加按键条目
for col in range(0, len(name_list)):
if col < 5:
tab_ui.setItem(dtq_dict[uID].upos-1, col, QTableWidgetItem())
if col >= 5:
tmp_btn = QPushButton(tab_ui)
tmp_btn.setText(name_list[col])
tab_ui.setCellWidget(dtq_dict[uID].upos-1, col, tmp_btn)
# 播放按键函件注册
if col == 5:
tmp_btn.clicked.connect(dtq_dict[uID].btn_ans_cb)
# 分析按键函件注册
if col == 6:
tmp_btn.clicked.connect(dtq_dict[uID].btn_paly_cb)
# 分析按键函件注册
if col == 7:
tmp_btn.clicked.connect(dtq_dict[uID].btn_show_cb)
在代码中看到我们为每个答题器创建3个按键,每个按键都注册到答题器类自身的函数中,此处就主要分析语音分析的方法实现:
dtq_dict[uID].btn_ans_cb
语音分析在答题器自身类的方法如下:
'''
* Class Name : btn_ans_cb
* Description : 分析特定语音数据包的分析结果
* Input : table_ui
'''
def btn_ans_cb(self):
if self.mp3_path:
self.btn_ans_ret = ""
cur_path = u"%s" % os.path.abspath("./")
command = cur_path + u'\\tools\\ffprobe.exe -show_frames ' + u"%s" % self.mp3_path
command += u" > ans_ret_tmp.txt"
command.encode('gb2312')
ret = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True)
# 此处异步的精髓就是此处的 communicate 方法
for info in ret.communicate():
if info:
line_list = info.split('\r\n')
for line in line_list:
if line[0:4] == '[mp3':
ll = line.split()
if ll[3] != 'overread,':
print line
self.btn_ans_ret += line + "\r\n"
self.btn_ans_tick = self.get_cur_tick()
网上找到 此 communicate 的语法如下:
官方文档里推荐使用 Popen.communicate()。这个方法会把输出放在内存,而不是管道里,所以这时候上限就和内存大小有关了,一般不会有问题。而且如果要获得程序返回值,可以在调用 Popen.communicate() 之后取 Popen.returncode 的值。
结论
如果使用 subprocess.Popen,就不使用 Popen.wait(),而使用 Popen.communicate() 来等待外部程序执行结束。