用python給MP3加封面圖片,修改作者,專輯等資訊

來源:互聯網
上載者:User

如何給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_finaldef 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 structdef 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_finaldef 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()

 


 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.