本篇主要學習如何Python自定義模塊並調用該模塊,並重點介紹Python正則表達式的強大的文本處理能力。python
案例故事: 任何一款終端產品只要涉及音頻輸出,就確定涉及音頻的解碼,
做爲一名專業的AV (Audio & Video)測試人員,咱們須要一堆的規範化標準的的音頻測試文件,
可是發現音頻資源名字命名的很隨意好比:青藏高原.wma,
以上命名不能看出音頻文件的具體編碼規格,
測試經理要求我進行批量重命名工做,模板以下,
音頻編碼格式_音頻採樣率_聲道數_比特率_容器.容器, 例如:
wma_44.1KHz_stereo_192Kbps_wma.wmaandroid
將聲音存儲爲音頻文件的時候,須要通過如下幾個步驟:正則表達式
主要涉及如下技術參數:編程
音頻參數 | 參數釋義 | 舉例 |
---|---|---|
音頻編碼格式 (壓縮技術) |
即將音頻數據壓縮的一類技術, 不一樣的編碼格式, 其壓縮率與壓縮效果不同。 主要分紅2類: 有損壓縮(會致使失真,壓縮率高) 無損壓縮(儘可能保真,壓縮率低) |
有損壓縮: Mpeg1 Level3(即咱們常說的Mp3); WMA;LCACC; LTPAAC; HE-AAC, HE-AACV2; AMR-WB, AMN-NB; Vorbis;MiDi; 無損壓縮: Flac;PCM;APE |
音頻採樣率 (單位:Khz) |
將聲音記錄成數據文件的時候, 須要對聲音進行採樣, 每秒鐘對聲音信號的採樣次數即採樣率。 採樣率越高,越能還原現場音質。 |
好比44.1Khz表明每秒採樣44100次 8Khz, 11.025Khz, 22.5Khz, 32Khz, 44.1Khz, 48Khz,96Khz |
音頻位深度 (單位:bit) |
每次採樣,採集數據量的大小 | 8bit, 16bit |
音頻聲道數 (單位:channel) |
通常有雙聲道即2個聲道, 錄音的時候確定是須要2個麥克風同時錄製的, 即同時採集了2個音頻流。 5聲道,則須要有5個麥克風同時錄製 |
單聲道:1 channel, Mono 雙聲道:2 channels, Stereo 5聲道:5 channels |
音頻比特率 (單位:Kbps) |
每秒鐘的音頻流的數據量, 其大小是直接取決於: 音頻編碼格式(壓縮率), 採樣率,位深度,聲道數乘積 |
48Kbps, 96Kbps, 128Kbps,256Kbps |
音頻容器 | 文件後綴,將音頻流封裝的一種文件格式 | .mp3; .wma; .aac; .3gp; .mp4; .flac ; .ape;.pcm; .raw; .mid; .ogg; .wav; .mkv; .m4a |
咱們碰到的任何音頻文件,都是數據的集合,
通常數據越大,其音頻播放質量越好。
微信
+---Input_Audio #批量放入待命名的音頻 | 1.mp3 | 青藏高原.wma | +---Output_Video #批量輸出已命名的音頻 | Mpeg3L1_44.1KHz_stereo_128Kbps_mp3.mp3 | wma_44.1Khz_stereo_96Kbps_wma.wma | \audio_info.py # 獲取音頻文件info信息的模塊, \rename_audio.py #調用audio_info.py並實現重名,可雙擊運行
因爲涉及較複雜的代碼,建議直接用面向對象類的編程方式實現:架構
# coding=utf-8 import os import re class AudioInfoGetter(): '''獲取音頻文件的codec, sample_rate, channels, bitrate''' def __init__(self, audio_file): '''判斷文件是否存在,若是存在獲取其mediainfo信息''' if os.path.exists(audio_file): self.audio_file = audio_file self.info = os.popen("mediainfo %s" % self.audio_file).read() else: raise FileNotFoundError("Not this File!") # 若是多媒體文件路徑不存在,必須中斷 def get_audio_codec(self): '''獲取音頻的編碼格式,好比Mepg3L1就是咱們常說的Mp3, 還有AAC系列,AMR系列,Flac等等''' try: audio_codec = re.findall(r"Format\s+:\s(.*)", self.info)[-1] # 取第最後一個Format字段 if (audio_codec == "MPEG Audio"): audio_codec = self.__format_mpeg_audio() elif (audio_codec == "AMR"): audio_codec = self.__format_amr_audio() elif (audio_codec == "AAC"): audio_codec = self.__format_aac_audio() elif ("PCM" in audio_codec): audio_codec = "PCM" else: pass except: audio_codec = "undef" # 防止程序由於異常而中斷 return audio_codec def get_audio_channel(self): '''獲取聲道數,若是是雙聲道是stereo, 若是是單聲道是mono,還存在5聲道的狀況''' try: audio_channel = re.findall(r"Channel\(s\)\s+:\s(.*)\schannel.*", self.info)[-1] if audio_channel == "2": audio_channel = "stereo" elif audio_channel == "1": audio_channel = "mono" elif audio_channel == "5": audio_channel = "5-channels" else: audio_channel = "undef" # 設置爲undef,表示特殊異常規格,建議人工驗證並考慮手動重命名 except: audio_channel = "undef" # 防止程序由於異常而中斷 return audio_channel def get_audio_sample_rate(self): '''獲取音頻採樣率,好比常見的48Khz, 44.1Khz等''' try: audio_sample_rate = re.findall(r"Sampling rate\s+:\s(.*)", self.info)[-1] audio_sample_rate = audio_sample_rate.replace(" ", "") # 去1 536 這個數字裏的空格 if "K" not in audio_sample_rate: audio_sample_rate = audio_sample_rate.replace("Hz", "") # 先去掉「Hz" audio_sample_rate = str(int(int(audio_sample_rate) / 1000)) audio_sample_rate = audio_sample_rate + "Khz" # 再添上KHz的單位 elif audio_sample_rate.endswith(".0Khz"): audio_sample_rate = audio_sample_rate.replace(".0", "") elif "/" in audio_sample_rate: # 偶爾會有多個採樣率的狀況 48.0 Khz / 44.1 KHz 這種 audio_sample_rate = "undef" # # 設置爲undef,表示特殊異常規格,建議人工驗證並考慮手動重命名 else: pass except: audio_sample_rate = "undef" # 防止程序由於異常而中斷 return audio_sample_rate def get_audio_bitrate(self): '''獲取音頻比特率,好比96Kbps, 128Kbps''' try: audio_bitrate = re.findall(r"Bit rate\s+:\s(.*)", self.info)[-1] audio_bitrate = audio_bitrate.replace(" ", "") # 去掉1 536 這個數字裏的空格 if "K" not in audio_bitrate: audio_bitrate = audio_bitrate.replace("bps", "") # 先去掉「bps" audio_bitrate = str(int(audio_bitrate) / 1000) audio_bitrate = audio_bitrate + "Kbps" # 再添上KHz的單位 except: audio_bitrate = "undef" # 防止程序由於異常而中斷 return audio_bitrate def get_audio_container(self): '''獲取音頻容器,即文件後綴名''' _, audio_container = os.path.splitext(self.audio_file) if not audio_container: raise NameError("This file no extension") audio_container = audio_container.replace(".", "") return audio_container def __format_mpeg_audio(self): '''若是是Mpeg Auido的音頻格式(常見的好比Mp3(Mpeg1 Level3)),進行格式化''' try: mpeg_audio_version = re.findall(r"Format version\s+:\sVersion\s(.*)", self.info)[-1] mpeg_audio_profile = re.findall(r"Format profile\s+:\sLayer\s(.*)", self.info)[-1] mpeg_audio_profile = "Mpeg%sL%s" % (mpeg_audio_version, mpeg_audio_profile) except: mpeg_audio_profile = "undef" return mpeg_audio_profile def __format_amr_audio(self): '''若是是amr的音頻格式(常見的好比amr-nb amr-wb),進行格式化''' try: amr_profile = re.findall(r"Format profile\s+:\s(.*)", self.info)[-1] if amr_profile == "Wide band": amr_profile = "AMR-WB" elif amr_profile == "Narrow band": amr_profile = "AMR-NB" else: amr_profile = "undef" # 設置爲undef,表示特殊異常規格,建議人工驗證並考慮手動重命名 except: amr_profile = "undef" return amr_profile def __format_aac_audio(self): '''若是是acc的音頻格式(常見的好比AAC-LC, AAC-LTP, HE-AAC, HE-AACV2),進行格式化''' try: amr_profile = re.findall(r"Format profile\s+:\s(.*)", self.info)[-1] if amr_profile == "LC": aac_profile = "AAC-LC" elif amr_profile == "LTP": aac_profile = "AAC-LTP" elif amr_profile.startswith("HE-AACv2"): aac_profile = "HE-AACV2" elif amr_profile.startswith("HE-AAC"): aac_profile = "HE-AAC" else: aac_profile = "undef" # 設置爲undef,表示特殊異常規格,建議人工驗證並考慮手動重命名 except: aac_profile = "undef" return aac_profile if __name__ == '__main__': # 如下代碼塊,只是用來測試本模塊的,通常不建議直接在這裏大面積調用本模塊''' a_obj = AudioInfoGetter("C:\\j.3gp") audio_codec = a_obj.get_audio_codec() print(audio_codec)
# coding=utf-8 import os import audio_info from shutil import copyfile curdir = os.getcwd() # 輸入文件夾,放入待重命名的音頻 input_audio_path = os.path.join(curdir, "Input_Audio") filelist = os.listdir(input_audio_path) #獲取文件列表 # 輸出文件夾,已命名的視頻存放在這裏 output_audio_path = os.path.join(curdir, "Output_Audio") # 若是沒有Output_Audio這個文件夾,則建立這個文件夾 if not os.path.exists(output_audio_path): os.mkdir(output_audio_path) if filelist: # 若是文件列表不爲空 for i in filelist: # 變量文件列表 audio_file = os.path.join(input_audio_path, i) a_obj = audio_info.AudioInfoGetter(audio_file) audio_codec = a_obj.get_audio_codec() audio_sample_rate = a_obj.get_audio_sample_rate() audio_channel = a_obj.get_audio_channel() audio_bitrate = a_obj.get_audio_bitrate() audio_container = a_obj.get_audio_container() new_audio_name = audio_codec + "_" + audio_sample_rate + "_" + audio_channel + "_" \ + audio_bitrate + "_" + audio_container + "." + audio_container print(new_audio_name) new_audio_file = os.path.join(output_audio_path, new_audio_name) copyfile(audio_file, new_audio_file) # 複製文件 else: print("It's a Empty folder, please input the audio files which need to be renamed firstly!!!") os.system("pause")
包含:mediainfo.exe(更建議丟到某個環境變量裏去),
各類編碼格式的音頻文件,audio_info.py模塊,rename_audio.py批處理腳本
調轉自拍教程官網下載
運行效果以下:
ide
小提示: 好比Android手機,Google推出了CDD(Compatibiltiy Definition Document兼容性定義文檔),
其第5部分,涉及了不少音頻編解碼格式的規定:
這就是Android最主要的音頻多媒體編解碼測試需求。工具
更多更好的原創文章,請訪問官方網站:www.zipython.com
自拍教程(自動化測試Python教程,武散人編著)
原文連接:https://www.zipython.com/#/detail?id=2c26d313cea54e8ab9ab3ecb612b986c
也可關注「武散人」微信訂閱號,隨時接受文章推送。
學習