python制作软件封面_用python给MP3加封面图片,修改作者,专辑等信息
如何給MP3加封面呢,當然用iturns,千千靜聽當然是可以的,但是如果用程序來自動加封面呢,研究linux的ffmpeg,發現用這個加專輯信息還是容易的,但是封面始終加不上,無法,去研究mp3文件的編碼吧
用來描述MP3信息的head有兩個大版本,分別是idv2和idv3,idv2放在文件尾部,只能描述一些簡單的信息,idv3就厲害了,可以添加圖片,和其它各種信息,包括自定義信息
我們只研究 idv3,它放在文件頭
idv3也有幾個常用的版本,一個是idv3.3一個是idv3.4兩者區別不大,就是frame中的長度idv3.4 改成了sync safe integer ,其它相同,但是idv3.4只有iturns和一些比較先進的播放器能識別出來,比如windows 8 的mediaplay 就無法識別出來,這樣在windows的文件夾中,那張封面圖就木有了,所以,我們主要研究idv3.3
idv3.3分 header和frame ,header描述 整個idv3.3的長度啊,和一些常見信息 共10bytes,frame可以有多個,比如專輯名,作者名,就是兩個frame
每個frame也有它的頭,也是10個字節,下面具體描述
header 共10個字節
1-3 ?字節 字符串
ID3
4 ? ? 字節 ?整數
表示版本號 正常是03 或者 04,03就是idv3.3 ,04就是idv3.4
5 ? ?字節 整數
小版本號 不管它
6 ? ?一個flags
不管它 用0即可
7-10 字節 一個無符號整數
表示整個id3頭的長度,這里的長度是個synchsafe?integer,具體這個是啥,你可以去百度搜,我這兒只提供個算法,將該數字轉義成真正的長度(不包括這個頭的長度)
def decode(x): #如果按照正常算法得到的是synchsafe integer,解析成 真正的整數大小
a = x & 0xff;
b = (x >> 8) & 0xff;
c = (x >> 16) & 0xff;
d = (x >> 24) & 0xff;
x_final = 0x0;
x_final = x_final | a;
x_final = x_final | (b << 7);
x_final = x_final | (c << 14);
x_final = x_final | (d << 21);
return x_final
def encode(x): #和上邊相反
a = x & 0x7f;
b = (x >> 7) & 0x7f;
c = (x >> 14) & 0x7f;
d = (x >> 21) & 0x7f;
x_final = 0x0;
x_final = x_final | a;
x_final = x_final | (b << 8);
x_final = x_final | (c << 16);
x_final = x_final | (d << 24);
return x_final
首先將那個4個字節的無符號整形轉成整數n,這個整數并不是真正的長度,然后調decode(n)
如果你要將一個整數轉化成syncsafe integer 那么調encode()函數即可
一個header的例子 ? ?ID3| 0x03| 0x00 | 0x00 | 0x00000013
那么意思是idv3的版本,decode(0x00000013)的長度,全部是大端編碼 big-endian
到這兒id3的頭就說完啦
下面講frame,每個frame也有一個固定的格式,每個frame 都有一個頭
也是10個字節
1-4 字節 字符串
TPE1 ,TIT2 ,TALB 具體去查http://id3.org/id3v2.3.0
5-8字節 一個無符號整形 大端編碼
表示這個frame的長度,不包括這個10個字節的頭(v3.4的版本這兒也是sync safe integer 需要decode,v3.3就不用啦)
9-10字節 ?兩個 0 不管他
每個frame還有一個體,體也是有格式滴復雜的咱不說,只說最常用的,第一個字節表示編碼,0就是普通編碼,在win上就是gbk,在linux系列就是utf8
所以如果是在win上的能正確解析的到 linux上就是亂碼咧,如果你默認用utf8,win上是解析不出來滴,
那如果我們選擇1呢,1就是unicode,unicode是啥編碼,說是ucs-2 這個是神馬東東,其實就是utf16,所以,第一個字節,咱們用1,然后內容用utf16編碼,兩個平臺就兼容啦
例子
TPE1|0x00000012|0x0000
0x01|content
長度12的content編碼是utf16
普通的frame是這個樣子,還有我們的關鍵 frame,圖片
圖片的的frame頭和上邊一樣,也是10個字節 ,但是體 稍微不同
第一個字節還是編碼,選0就成,然后是 mime type 就是圖片格式比如 image/jpeg 或者是image/png 然后跟一個0x00 表示格式結束
然后再來個一個字節表示圖片用途,比如封面是03,但是用03 有問題,不知道為啥,所以都是用0
然后一個是描述,沒用 用0就行
然后就是圖片數據開始啦,將圖片打開,然后read數據到這兒就成了
例子
APIC|0x00001234|0x0000 ? 頭
0x00|image/jpeg0x00|0x00|0x00 content(比如一個jpg的圖片 是0xFFD8打頭)
噢了,下邊是我寫的一個讀寫mp3 idv3信息的小python代碼
# -*- coding: utf8 -*-
import struct
def decode(x): #如果按照正常算法得到的synchsafe integer,解析成 真正的整數大小
a = x & 0xff;
b = (x >> 8) & 0xff;
c = (x >> 16) & 0xff;
d = (x >> 24) & 0xff;
x_final = 0x0;
x_final = x_final | a;
x_final = x_final | (b << 7);
x_final = x_final | (c << 14);
x_final = x_final | (d << 21);
return x_final
def encode(x): #和上邊相反
a = x & 0x7f;
b = (x >> 7) & 0x7f;
c = (x >> 14) & 0x7f;
d = (x >> 21) & 0x7f;
x_final = 0x0;
x_final = x_final | a;
x_final = x_final | (b << 8);
x_final = x_final | (c << 16);
x_final = x_final | (d << 24);
return x_final
class MP3:
def __init__(self,path):
self.path = path
pass
def getInfo(self):
fp = open( self.path,'rb');
head = fp.read(10)
id3,ver,revision,flag,length = struct.unpack("!3sBBBI",head);
length = decode(length)
data = []
while True:
frame = fp.read(10)
fid,size,flag,flag2 = struct.unpack("!4sI2B",frame)
if size==0: #有時候會留1024的白 不知道為啥
break
if ver==4: #就是這一點 4和3的不同之處,4的這兒也采用synchsafe integer 了,注意啊
size = decode(size)
content = fp.read(size)
data.append((fid,content))
length-= (size+10)
print length
if length<=0:
break
fp.close()
return data
def buildItem(self,flag,content):
content = content.decode('utf8').encode("utf16")
content = struct.pack('!B',1)+content
length = len(content)
head = struct.pack('!4sI2B',flag,length,0,0);
return head + content
def addImage(self,image,data):
fp = open( self.path,'rb');
head = fp.read(10)
try:
id3,ver,revision,flag,length = struct.unpack("!3sBBBI",head);
except:
return False;
if id3 != 'ID3':
return False
#新建立個文件
fpNew = open(self.path+'.bak',"wb");
fpImage = open(image,"rb")
imageData = fpImage.read() #待用
originLength = decode(length) #真實長度
length = 0
imageDataPre = struct.pack("!B10s2BB",0,'image/jpeg',0,0,0)
imageData = imageDataPre+imageData
apicLen = len(imageData) #圖片數據區域長度
imageDataHead = struct.pack("!4sI2B",'APIC',apicLen,0,0)
imageData = imageDataHead+imageData
TPE1 = self.buildItem('TPE1', data[u'Artist'].encode("utf8"))
TIT2 = self.buildItem('TIT2', data[u'Title'].encode("utf8"))
TALB = self.buildItem('TALB', data[u'Album'].encode("utf8"))
#新長度
length += len(imageData)
length += len(TPE1)
length += len(TIT2)
length += len(TALB)
header = head[0:3]
header += struct.pack('!B',3)
header += struct.pack('!H',0)
#1字節留白
header += struct.pack("!I",encode(length+1))
fpNew.write(header)
fpNew.write(TPE1)
fpNew.write(TIT2)
fpNew.write(TALB)
fpNew.write(imageData)
fpNew.write(struct.pack('!B',0))
fp.seek(originLength,1) #跳
fpNew.write(fp.read())
fpNew.close()
fp.close()
fpImage.close()
總結
以上是生活随笔為你收集整理的python制作软件封面_用python给MP3加封面图片,修改作者,专辑等信息的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文件表单带数据一起提交spring_基于
- 下一篇: multiprocessing.mana