WMA文件信息格式分析及代碼 收藏
ASF文件和WMA文件格式差不多。具體請看下面我寫的代碼。文件分析根據mplayer其中的asfhead.c提供的代碼進行分析。mplayer只解除出了標準的wma頭信息,其擴展信息并沒有解析出來。代碼如下.
/*
每一個WMA文件,它的頭16個字節是固定的,為十六進制的“30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C”,用來標識這個是否為WMA文件。接下來的8個字節為一個整數,表示整個WMA文件頭部的大小,這個頭部里面包含了Tag信息等所有非音頻信息,頭部后面的是音頻信息,我們在這里就不深入了解了。那個整數接下來的6個字節還沒搞清楚是什么用的,不過不影響我們對Tag信息的讀寫。
?????? 也就是說從文件開始偏移量為31開始,里面存放了很多幀,有我們需要的標準Tag信息,擴展Tag信息,WMA文件控制信息等等。每個幀不是等長的,但是幀頭是固定的24個字節,其中前16字節是用來標識這個幀的名字,后8個字節是用來表示這個幀(包括幀頭)的大小。這一點和MP3文件的ID3V2信息比較像。
??????? 由于我們只需要讀寫Tag信息,而Tag信息又分別保存在兩個幀里,分別為標準Tag幀和擴展Tag幀,所有我們只需要處理這兩個幀,其他幀完全可以根據獲得的幀長度來跳過。
?????? 如圖2,標準Tag幀只包含歌曲標題,藝術家,版權,備注四個內容。它的幀名是十六進制的“33 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C”,在24個字節的幀頭后緊跟著5個分別為2個字節的整數,前四個分別表示歌曲標題,藝術家,版權,備注的大小,第五個還不清楚是什么用的,大部分情況下是不使用的,即它的大小為0的。
??????? 在這10個字節后,這四個信息的內容就按順序存放了。記住,在WMA文件里,所有的文字都是按Unicode寬字符的編碼方式儲存的,而且每個字符串后面都又一個0結束字符的。
??????? 再看擴展Tag幀,這里就比較麻煩了,里面包含的信息的個數是不確定的,每個信息也是按照像幀一樣的方式組織起來的。擴展Tag幀的幀名是十六進制的“40 A4 D0 D2 07 E3 D2 11 97 F0 00 A0 C9 5E A8 50”,在24字節的幀頭后先有一個兩個字節的整數表示這個幀里一共有的擴展信息個數(ExNo)。
??????? 每一個擴展信息包含擴展信息名字和對應的值。先有一個兩個字節的整數來表示擴展名字信息的大小,接著是擴展信息,然后有一個兩個字節的整數標志(Flag),這個后面再講。然后又是一個兩個字節的整數,表示值的大小。接著就是這個值。
?????? 當擴展信息名字為WMFSDKVersion時,這個值表示的是這個WMA文件的版本;當擴展信息名字為WM/AlbumTitle時,這個值代表的就是專輯名;當擴展信息名字為WM/Genre時,這個值代表的就是流派;同理,很容易從擴展信息的名字看出這個值的用途的。這些擴展信息的名字和值幾乎都是用Unicode的字符串來存儲的,到現在為止只發現對下面兩個情況例外
?????? 下面再來看看那個標志Flag,這個基本上是為沒什么用的(通常值為0),只對WM/TrackNumber和WM/Track這兩個擴展信息名字有用,當Flag為3的時候后面的值(也就是曲目信息)是以4個字節的整數的形式表示,當Flag為0的時候,曲目信息是以普通的字符串形式表示的。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<sys/mman.h>
typedef unsigned long long uint64_t;
typedef unsigned long uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
typedef long long int64_t;
typedef short int16_t;
typedef struct
{
??? uint16_t title_size;
??? uint16_t author_size;
??? uint16_t copyright_size;
??? uint16_t comment_size;
??? uint16_t rating_size;
}ASF_content_description_t;
struct asf_tags
{
??? char title[64];
??? char author[64];
??? char copyright[64];
??? char comment[64];
??? char rating[64];
??? char **ext_info;
};
const uint8_t ff_log2_tab[256]={
??????? 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
??????? 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
??????? 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
??????? 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
??????? 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
??????? 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
??????? 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
??????? 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
};
static inline int av_log2(unsigned int v)
{
??? int n;
??? n = 0;
??? if (v & 0xffff0000) {
??????? v >>= 16;
??????? n += 16;
??? }
??? if (v & 0xff00) {
??????? v >>= 8;
??????? n += 8;
??? }
??? n += ff_log2_tab[v];
??? return n;
}
#define PUT_UTF8(val, tmp, PUT_BYTE)/
??? {/
??????? int bytes, shift;/
??????? uint32_t in = val;/
??????? if (in < 0x80) {/
??????????? tmp = in;/
??????????? PUT_BYTE/
??????? } else {/
??????????? bytes = (av_log2(in) + 4) / 5;/
??????????? shift = (bytes - 1) * 6;/
??????????? tmp = (256 - (256 >> bytes)) | (in >> shift);/
??????????? PUT_BYTE/
??????????? while (shift >= 6) {/
??????????????? shift -= 6;/
??????????????? tmp = 0x80 | ((in >> shift) & 0x3f);/
??????????????? PUT_BYTE/
??????????? }/
??????? }/
??? }
const char asf_file_format_guid[16] = {0x30, 0x26, 0xB2, 0x75, 0x8E,
? 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C};/*ASF文件標志*/
const char asf_content_desc_guid[16] = {0x33, 0x26, 0xb2, 0x75,
? 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c};/*ASF 標志信息*/
const char asf_stream_ext_desc_guid[16] = {0x40, 0xA4, 0xD0, 0xD2, 0x07,
?0xE3, 0xD2, 0x11, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50};/*ASF擴展標志信息*/
?
#define AV_RL16(x)? ((((uint8_t*)(x))[1] << 8) | /
????????????????????? ((uint8_t*)(x))[0])
static char* get_ucs2str(const uint16_t* inbuf, uint16_t inlen)
{
??? char* outbuf = calloc(inlen, 2);
??? char* q;
??? int i;
??? if (!outbuf)
??? {
??????? return NULL;
??? }
??? q = outbuf;
??? for (i = 0; i < inlen / 2; i++)
??? {
??????? uint8_t tmp;
??????? PUT_UTF8(AV_RL16(&inbuf[i]), tmp, *q++ = tmp;)
??? }
??? return outbuf;
}
int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len)
{
? int i;
? for (i = cur_pos; i < buf_len - 19; i++) {
??? if (memcmp(&buf[i], guid, 16) == 0)
????? return i + 16 + 8; // point after guid + length
? }
? return -1;
}
int asf_ext_info_add(struct asf_tags* tags, const char *opt, const char *param)
{
??? char **info = tags->ext_info;
??? int n = 0;
??? for(n = 0; info && info[2*n] != NULL; n++)
??? {
??????? if(!strcasecmp(opt,info[2*n]))
??????? {
?????????????? free(info[2*n+1]);
??????????? info[2*n+1] = strdup(param);
??????????? return 0;
??????? }
??? }
??? info = tags->ext_info = (char**)realloc(info,(2*(n+2))*sizeof(char*));
??? info[2*n] = strdup(opt);
??? info[2*n+1] = strdup(param);
??? memset(&info[2*(n+1)],0,2*sizeof(char*));
??? return 1;
}
enum metadata_s
{
??? /* common info */
??? META_INFO_TITLE=0,
??? META_INFO_AUTHOR,
??? META_INFO_COPYRIGHT,
??? META_INFO_COMMENT,
??? META_INFO_WMFSDKVERSION,
??? META_INFO_WMFSDKNEEDED,
??? META_INFO_ISVBR,
??? META_INFO_WMPROMOTIONURL,
??? META_INFO_WMGENREID,
??? META_INFO_WMTRACK,
??? META_INFO_WMTRACENUMBER,
??? META_INFO_WMYEAR,
??? META_INFO_WMENCODINGTIME,
??? META_INFO_WMGENRE,
??? META_INFO_WMALBUMTITLE,
??? META_INFO_PEAKVALE,
??? META_INFO_AVERAGELEVEL
};
typedef enum metadata_s metadata_t;
static char *get_asf_info (struct asf_tags* tags,char *tag)
{
??? char **info = tags->ext_info;
??? int n;
??? if (!info || !tag)
??????? return NULL;
??? for (n = 0; info[2*n] != NULL ; n++)
??? {
??????? if (!strcmp (info[2*n], tag))
??????????? break;
??? }
??? return info[2*n+1] ? strdup (info[2*n+1]) : NULL;
}
char *get_metadata (struct asf_tags* tags,metadata_t type)
{
??? switch (type)
??? {
??????? case META_INFO_TITLE:
??????? {
??????????? return tags->title;
??????? }
??????? case META_INFO_AUTHOR:
????????? {
??????????? return tags->author;
??????? }
??????? case META_INFO_COPYRIGHT:
??????? {
??????????? return tags->copyright;
??????? }
??????? case META_INFO_COMMENT:
??????? {
??????????? return tags->comment;
??????? }
??????? case META_INFO_WMFSDKVERSION:
??????? {
??????????? return get_asf_info(tags,"WMFSDKVersion");
??????? }
??????? case META_INFO_WMFSDKNEEDED:
??????? {
??????????? return get_asf_info(tags,"WMFSDKNeeded");
??????? }
??????? case META_INFO_ISVBR:
??????? {
??????????? return get_asf_info(tags,"IsVBR");
??????? }
??????? case META_INFO_WMPROMOTIONURL:
??????? {
??????????? return get_asf_info(tags,"WM/PromotionURL");
??????? }
??????? case META_INFO_WMGENREID:
??????? {
??????????? return get_asf_info(tags,"WM/GenreID");
??????? }
??????? case META_INFO_WMTRACK:
??????? {
??????????????? return get_asf_info(tags,"WM/Track");
??????? }
??????? case META_INFO_WMTRACENUMBER:
??????? {
??????????????? return get_asf_info(tags,"WM/TrackNumber");
??????? }
??????? case META_INFO_WMYEAR:
??????? {
??????????? return get_asf_info(tags,"WM/Year");
??????? }
??????? case META_INFO_WMENCODINGTIME:
??????? {
??????????? return get_asf_info(tags,"WM/EncodingTime");
??????? }
??????? case META_INFO_WMGENRE:
??????? {
??????????? return get_asf_info(tags,"WM/Genre");
??????? }
??????? case META_INFO_WMALBUMTITLE:
??????? {
??????????? return get_asf_info(tags,"WM/AlbumTitle");
??????? }
??????? case META_INFO_PEAKVALE:
??????? {
??????????? return get_asf_info(tags,"PeakValue");
??????? }
??????? case META_INFO_AVERAGELEVEL:
??????? {
??????????? return get_asf_info(tags,"AverageLevel");
??????? }
??? }
}
int read_asf_header(char? *filename,struct asf_tags* tags)
{
??? int hdr_len;
??? char *hdr = NULL;
??? int pos;
??? int fd;
??? char buffer[16];
??? struct stat sb;
??? fd=open(filename,O_RDONLY);
??? if(fd==-1)
??? {
??????? printf("open file error/n");
??????? return 0;
??? }
??? memset(buffer,0,16);
??? fstat(fd,&sb); /*取得文件大小*/
??? hdr=mmap(NULL,sb.st_size,PROT_READ,MAP_PRIVATE,fd,0);
??? if(hdr== MAP_FAILED) /*判斷是否映射成功*/
??? {
??????? return 0;
??????? close(fd);
??? }
??? strncpy(buffer,hdr,16);
??? if(strcmp(buffer,asf_file_format_guid))/*根據ASF標志信息判斷是否為ASF文件*/
??? {
??????? printf("file not an asf file/n");
??????? close(fd);
??????? munmap(hdr,sb.st_size);
??????? return 0;
??? }
??? hdr_len=sb.st_size;
??? pos = find_asf_guid(hdr, asf_content_desc_guid, 0, hdr_len);/*找到標志信息位置*/
??? if (pos >= 0)
??? {
??????? ASF_content_description_t *contenth = (ASF_content_description_t *)&hdr[pos];
??????? unsigned char *string=NULL;
??????? uint16_t* wstring = NULL;
??????? uint16_t len;
??????? pos += sizeof(ASF_content_description_t);
??????? if (pos > hdr_len) goto len_err_out;
??????? //le2me_ASF_content_description_t(contenth);
??????? // extract the title
??????? if((len = contenth->title_size) != 0)
??????? {
??????????? wstring = (uint16_t*)&hdr[pos];
??????????? pos += len;
??????????? if (pos > hdr_len) goto len_err_out;
??????????? if ((string = get_ucs2str(wstring, len)))/*J解析成UTF8*/
??????????? {
??????????????????? strcpy(tags->title, string);
??????????????? free(string);
??????????? }
??????? }
??????? // extract the author
??????? if((len = contenth->author_size) != 0)
??????? {
??????????? wstring = (uint16_t*)&hdr[pos];
??????????? pos += len;
??????????? if (pos > hdr_len) goto len_err_out;
??????????? if ((string = get_ucs2str(wstring, len)))
??????????? {
??????????????? strcpy(tags->author, string);
??????????????? free(string);
??????????? }
??????? }
??????? if((len = contenth->copyright_size) != 0)
??????? {
??????????? wstring = (uint16_t*)&hdr[pos];
??????????? pos += len;
??????????? if (pos > hdr_len) goto len_err_out;
??????????? if ((string = get_ucs2str(wstring, len)))
??????????? {
??????????????? strcpy(tags->copyright, string);
??????????????? free(string);
??????????? }
??????? }
??????? // extract the comment
??????? if((len = contenth->comment_size) != 0)
??????? {
??????????? wstring = (uint16_t*)&hdr[pos];
??????????? pos += len;
??????????? if (pos > hdr_len) goto len_err_out;
??????????? if ((string = get_ucs2str(wstring, len)))
??????????? {
??????????????? strcpy(tags->comment, string);
??????????????? free(string);
??????????? }
??????? }
??????? // extract the rating
??????? if((len = contenth->rating_size) != 0)
??????? {
??????????? wstring = (uint16_t*)&hdr[pos];
??????????? pos += len;
??????????? if (pos > hdr_len) goto len_err_out;
??????????? if ((string = get_ucs2str(wstring, len)))
??????????? {
??????????????? strcpy(tags->rating, string);
??????????????? free(string);
??????????? }
??????? }
??? }
??? pos = find_asf_guid(hdr, asf_stream_ext_desc_guid, 0, hdr_len);/*找到擴展信息標志位置*/
??? if (pos >= 0)
??? {
??????? int i;
??????? //unsigned char *ext_desc;
??????? uint16_t flag;
??????? uint16_t ext_desc_num;
??????? unsigned char *string_name=NULL;
??????? unsigned char *string_info=NULL;
??????? uint16_t* wstring = NULL;
??????? uint16_t len;
??????? ext_desc_num=(*(uint16_t*)(&hdr[pos]));
??????? //printf("%d/n",ext_desc_num);
??????? pos += 2;???
??????? for(i=0;i<ext_desc_num;i++)
??????? {
??????????? len=(*(uint16_t*)(&hdr[pos]));/*擴展名字信息大小*/
??????????? pos+=2;
??????????? wstring=(uint16_t*)&hdr[pos];
??????????? if ((string_name = get_ucs2str(wstring, len)))
??????????? {
??????????????????????? //printf(" %d.擴展信息名字 %s/n", i,string_name);
??????????????? //free(string_name);
??????????? }
??????????? pos+=len;
??????????? flag=(*(uint16_t*)(&hdr[pos]));/*標志*/
??????????? pos+=2;
??????????? len=(*(uint16_t*)(&hdr[pos]));/*擴展名字對應值大小*/
??????????? pos+=2;
??????????? wstring=(uint16_t*)&hdr[pos];
??????????? if ((string_info = get_ucs2str(wstring, len)))
??????????? {
??????????????????????? //printf(" 擴展信息對應的值 %s/n",string_info);
??????????????? //free(string_info);
??????????? }
??????????? asf_ext_info_add(tags,string_name,string_info);
??????????? pos+=len;
??????? }
??? }
??? close(fd);
??? munmap(hdr,sb.st_size);
??? return 1;
??? len_err_out:
??? close(fd);
??? munmap(hdr,sb.st_size);
??? return 0;
}
int main(int argc,char **argv)
{
??? char *filename=argv[1];
??? int i;
??? char **info;
??? struct asf_tags tags;
??? tags.ext_info=(char**)malloc(2*sizeof(char*));
??? read_asf_header(filename,&tags);
??? char **ext_info;
??? printf("Title:%s/n",tags.title);
??? printf("Author:%s/n",tags.author);
??? printf("Copyright:%s/n",tags.copyright);
??? printf("Comment:%s/n",tags.comment);
??? printf("Rating:%s/n",tags.rating);
??? info = tags.ext_info;
??? for(i = 0; info[2*i] != NULL ; i++)
??? {
??????? printf("%s: %s/n",info[2*i],info[2*i+1]);
??? }
??? return 0;
}
這里已經做了相關信息的接口,利于擴展開發。希望這些能對那些正在進行相關開發的人員提供一點幫助。本人從事音頻視頻解碼,希望能和大家一起探討,共通進步。聯系方法QQ:263542344
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/benny5609/archive/2008/05/07/2409533.aspx
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/yueyihua/archive/2010/04/20/5508286.aspx
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/yueyihua/archive/2010/04/20/5508286.aspx
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/yueyihua/archive/2010/04/20/5508286.aspx