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