Excel VBAでファイル解析(WMAファイル編)

2024-01-05

■WMAファイルの概要

WMA(Windows Media Audio)はMicrosoftが開発した音声データの圧縮符号化方式で、ファイルの拡張子は「.wma」です。
WMAファイルの内部形式は、ASF(Advanced Systems Format)という規格で定められていますので、次項でASFの仕様を説明します。

なお、ASFで定められている内容は多岐に亘りますので、本稿ではタグ情報(「アルバム名」「年」「トラック番号」「アーティスト名」「曲名」「添付画像」)を取出すことに目的を絞って説明します。

WMAファイルの仕様

WMAファイルはObjectの集合体となっており、さまざまなObjectが定義されています。
Objectの基本構造は以下の通りシンプルな形式になっており、先頭にある「Object GUID」でオブジェクトを識別可能ですが、Objectの種類毎に「Object Data」の内容が異なるため、ファイルの中身を解析するためにはObjectの種類や構造を意識する必要があります。

(Objectの基本構造)

オフセット 長さ 説明
0 16 Object GUID(Globally Unique IDentifier)
16 8 Object Size
24 可変長 Object Data

ASFの規格で定められているObjectの種類は、下表の通りです。
⇒詳細はMicrosoftのサイト(ASF(Advanced Systems Format))を参照して下さい。

(Objectの種類)

Object GUID
top-level Header Object
Header Object 75B22630-668E-11CF-A6D9-00AA0062CE6C
File Properties Object 8CABDCA1-A947-11CF-8EE4-00C00C205365
Stream Properties Object B7DC0791-A9B7-11CF-8EE6-00C00C205365
Header Extension Object 5FBF03B5-A92E-11CF-8EE3-00C00C205365
Extended Stream Properties Object 14E6A5CB-C672-4332-8399-A96952065B5A
Advanced Mutual Exclusion Object A08649CF-4775-4670-8A16-6E35357566CD
Group Mutual Exclusion Object D1465A40-5A79-4338-B71B-E36B8FD6C249
Stream Prioritization Object D4FED15B-88D3-454F-81F0-ED5C45999E24
Bandwidth Sharing Object A69609E6-517B-11D2-B6AF-00C04FD908E9
Language List Object 7C4346A9-EFE0-4BFC-B229-393EDE415C85
Metadata Object C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA
Metadata Library Object 44231C94-9498-49D1-A141-1D134E457054
Index Parameters Object D6E229DF-35DA-11D1-9034-00A0C90349BE
Media Object Index Parameters Object 6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7
Timecode Index Parameters Object F55E496D-9797-4B5D-8C8B-604DFE9BFB24
Compatibility Object 75B22630-668E-11CF-A6D9-00AA0062CE6C
Advanced Content Encryption Object 43058533-6981-49E6-9B74-AD12CB86D58C
Codec List Object 86D15240-311D-11D0-A3A4-00A0C90348F6
Script Command Object 1EFB1A30-0B62-11D0-A39B-00A0C90348F6
Marker Object F487CD01-A951-11CF-8EE6-00C00C205365
Bitrate Mutual Exclusion Object D6E229DC-35DA-11D1-9034-00A0C90349BE
Error Correction Object 75B22635-668E-11CF-A6D9-00AA0062CE6C
Content Description Object 75B22633-668E-11CF-A6D9-00AA0062CE6C
Extended Content Description Object D2D0A440-E307-11D2-97F0-00A0C95EA850
Stream Bitrate Properties Object 7BF875CE-468D-11D1-8D82-006097C9A2B2
Content Branding Object 2211B3FA-BD23-11D2-B4B7-00A0C955FC6E
Content Encryption Object 2211B3FB-BD23-11D2-B4B7-00A0C955FC6E
Extended Content Encryption Object 298AE614-2622-4C17-B935-DAE07EE9289C
Digital Signature Object 2211B3FC-BD23-11D2-B4B7-00A0C955FC6E
Padding Object 1806D474-CADF-4509-A4BA-9AABCB96AAE8
top-level Data Object
Data Object 75B22636-668E-11CF-A6D9-00AA0062CE6C
top-level index objects
top-level Simple Index Object 33000890-E5B1-11CF-89F4-00A0C90349CB
top-level Index Object D6E229D3-35DA-11D1-9034-00A0C90349BE
top-level Media Object Index Object FEB103F8-12AD-4C64-840F-2A1D2F7AD48C
top-level Timecode Index Object 3CB73FD0-0C4A-4803-953D-EDF7B6228F0C

タグ情報は「Content Description Object」と「Extended Content Description Object」の中に保有していますので、次項で詳細を説明します。

Content Description Objectのフォーマット

Content Description Objectのフォーマットは、下表の通りです。

数値項目はリトル・エンディアンで格納されているため、エンディアン変換が必要になります。
「Object ID(GUID)」は16バイトですが、「Int32, Int16, Int16, Byte, Byte, Byte, Byte, Byte, Byte, Byte, Byte」という内訳になっているため、最初の4バイト、次の2バイト、その次の2バイトはエンディアン変換が必要ですが、残りの8バイトはエンディアン変換を行ってはいけません。
「Title」「Author」「Copyright」「Description」「Rating」はテキスト・データですが、ASFの仕様書には以下の記載がありますので、サンプル・プログラムではUTF-16として処理しています。

  • WCHARの配列を指定します。
    この文字列にnul-terminatorを含めることを強くお勧めしますが、
    nul-terminatorが存在しない場合があります。

(Content Description Objectのフォーマット)

オフセット 長さ 説明
0 16 Object ID
16 8 Object Size
24 4 Title Length(Titleの長さ)
28 4 Author Length(Authorの長さ)
32 4 Copyright Length(Copyrightの長さ)
36 4 Description Length(Descriptionの長さ)
40 4 Rating Length(Ratingの長さ)
可変 可変長 Title(「曲名」)
可変 可変長 Author(「アーティスト名」)
可変 可変長 Copyright
可変 可変長 Description
可変 可変長 Rating

Extended Content Description Objectのフォーマット

Extended Content Description Objectのフォーマットは、下表の通りです。

(Extended Content Description Objectのフォーマット)

オフセット 長さ 説明
0 16 Object ID
16 8 Object Size
24 2 Content Descriptors Count
(Content Descriptorの個数)
26 可変長 Content Descriptors(下表参照)

(Content Descriptorsのフォーマット)

オフセット 長さ 説明
0 2 Descriptor Name Length
(Descriptor Nameの長さ)
2 可変長 Descriptor Name
可変 2 Descriptor Value Data Type(下表参照)
可変 2 Descriptor Value Length
(Descriptor Valueの長さ)
可変 可変長 Descriptor Value

(Descriptor Value Data Type)

長さ タイプ
0x0000 可変 Unicode string
0x0001 可変長 BYTE array
0x0002 4 BOOL
0x0003 4 DWORD
0x0004 8 QWORD
0x0005 2 WORD

■WMAファイルのタグ情報をExcelシートに表示する処理

WMAファイルのタグ情報を読み込み、Excelシートに表示するプログラムです。
⇒サンプル・プログラムで使用している、Binary Fileクラスの詳細については、Excel VBAでファイル解析(事前準備編)を参照して下さい。

処理の概要

処理の流れは以下の通りです。
①Binary Fileオブジェクトをインスタンス化し、WMAファイルを読み込み
②WMAファイルのタグ情報を解析し、必要な情報を取得してExcelシートにセット
③使用済のオブジェクトを破棄

サンプル・プログラム

行番号15でBinary Fileオブジェクトをインスタンス化し、行番号16でWMAファイルを読み込んでいます。
行番号19~74の繰返し処理のうち、行番号27はHeader Object、行番号30~41はContent Description Object、行番号44~70はExtended Content Encryption Object、行番号72はそれ以外のObjectの処理です。
タグ情報の表示については、行番号35~37で「曲名」、行番号38~40で「アーティスト名」、行番号50~54で「アルバム名」「年」「トラック番号」、行番号57~62で「添付画像」に関する処理を行っています。

(注)以下のプログラムは、テキスト情報がUTF-16で格納されているものとして処理を記述していますが、UTF-8で格納されている場合は、GetDataUTF16メソッドをGetDataUTF8メソッドに置換えて下さい。

  1. Dim sht, bf As Object
  2. Dim wLoc, wLen, wGUID, DescriptorName As String
  3. Dim EntNum, lcnt, i As Long
  4. Dim TitleLength As Long
  5. Dim AuthorLength As Long
  6. Dim CopyrightLength As Long
  7. Dim DescriptionLength As Long
  8. Dim DescriptorValueLength As Long
  9. Dim RatingLength As Long
  10. Dim DescriptorNameLength As Long
  11. Dim JpegLength As Long
  12. Private Sub Sample1()
  13.     Set sht = ActiveSheet
  14.     Set bf = New BinaryFile
  15.     bf.InputFile (“C:\work\xxx.wma")
  16.     lcnt = 0
  17.     Do While bf.CurrentPosition < bf.FileSize
  18.         wLoc = bf.GetPositionHex
  19.         wGUID = bf.ConvertEndian(bf.GetDataHex(4)) & “-" & bf.ConvertEndian(bf.GetDataHex(2)) & “-" & bf.ConvertEndian(bf.GetDataHex(2)) & “-" & bf.GetDataHex(2) & “-" & bf.GetDataHex(6)
  20.         wLen = bf.ConvertEndian(bf.GetDataHex(4))
  21.         bf.SkipData (4)
  22.         Select Case wGUID
  23.         'Header Object
  24.         Case “75B22630-668E-11CF-A6D9-00AA0062CE6C"
  25.             bf.SkipData (6)
  26.         'Content Description Object
  27.         Case “75B22633-668E-11CF-A6D9-00AA0062CE6C"
  28.             TitleLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  29.             AuthorLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  30.             CopyrightLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  31.             DescriptionLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  32.             RatingLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  33.             lcnt = lcnt + 1
  34.             sht.Cells(lcnt, 1) = “Title"
  35.             sht.Cells(lcnt, 2) = bf.GetDataUTF16(TitleLength)
  36.             lcnt = lcnt + 1
  37.             sht.Cells(lcnt, 1) = “Author"
  38.             sht.Cells(lcnt, 2) = bf.GetDataUTF16(AuthorLength)
  39.             bf.SkipData (CopyrightLength + DescriptionLength + RatingLength)
  40.         'Extended Content Encryption Object
  41.         Case “D2D0A440-E307-11D2-97F0-00A0C95EA850"
  42.             EntNum = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  43.             For i = 1 To EntNum
  44.                 DescriptorNameLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  45.                 DescriptorName = bf.GetDataUTF16(DescriptorNameLength – 2)
  46.                 Select Case DescriptorName
  47.                 Case “WM/AlbumTitle", “WM/Year", “WM/TrackNumber"
  48.                     lcnt = lcnt + 1
  49.                     sht.Cells(lcnt, 1) = Mid(DescriptorName, 4)
  50.                     bf.SkipData (4)
  51.                     DescriptorValueLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  52.                     sht.Cells(lcnt, 2) = “'" & bf.GetDataUTF16(DescriptorValueLength – 2)
  53.                     bf.SkipData (2)
  54.                 Case “WM/Picture"
  55.                     lcnt = lcnt + 1
  56.                     sht.Cells(lcnt, 1) = Mid(DescriptorName, 4)
  57.                     bf.SkipData (7)
  58.                     JpegLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(4)))
  59.                     sht.Cells(lcnt, 3) = “'" & Right(“0000000" & Hex(JpegLength), 8)
  60.                     sht.Cells(lcnt, 2) = bf.GetDataUTF16(20)
  61.                     bf.SkipData (4)
  62.                    bf.SkipData (JpegLength)
  63.                 Case Else
  64.                     bf.SkipData (4)
  65.                     DescriptorValueLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  66.                     bf.SkipData (DescriptorValueLength)
  67.                 End Select
  68.             Next i
  69.         Case Else
  70.             bf.SkipData (CLng(“&H" & wLen) – 24)
  71.         End Select
  72.     Loop
  73.     Set bf = Nothing
  74. End Sub

■WMAファイルのタグ情報から画像データを抽出する処理

WMAファイルのタグ情報を読み込み、画像データをファイルに出力するプログラムです。
⇒サンプル・プログラムで使用している、Binary Fileクラスの詳細については、Excel VBAでファイル解析(事前準備編)を参照して下さい。

処理の概要

処理の流れは以下の通りです。
①Binary Fileオブジェクトをインスタンス化し、WMAファイルを読み込み
②WMAファイルのタグ情報を解析し、画像データを取得してファイルに出力
③使用済のオブジェクトを破棄

サンプル・プログラム

行番号15でBinary Fileオブジェクトをインスタンス化し、行番号16でM4Aファイルを読み込んでいます。
行番号18~50の繰返し処理のうち、行番号26はHeader Object、行番号29~46はExtended Content Encryption Object、行番号48はそれ以外のObjectの処理です(Content Description Objectは使用したいため、行番号48で読み飛ばしています)。
行番号36~39の「添付画像」に関する処理の中で、画像データをJPEGファイルに出力しています。

  1. Dim sht, bf As Object
  2. Dim wLoc, wLen, wGUID, DescriptorName As String
  3. Dim EntNum, i As Long
  4. Dim TitleLength As Long
  5. Dim AuthorLength As Long
  6. Dim CopyrightLength As Long
  7. Dim DescriptionLength As Long
  8. Dim DescriptorValueLength As Long
  9. Dim RatingLength As Long
  10. Dim DescriptorNameLength As Long
  11. Dim JpegLength As Long
  12. Private Sub Sample2()
  13.     Set sht = ActiveSheet
  14.     Set bf = New BinaryFile
  15.     bf.InputFile (“C:\work\xxx.wma")
  16.     Do While bf.CurrentPosition < bf.FileSize
  17.         wLoc = bf.GetPositionHex
  18.         wGUID = bf.ConvertEndian(bf.GetDataHex(4)) & “-" & bf.ConvertEndian(bf.GetDataHex(2)) & “-" & bf.ConvertEndian(bf.GetDataHex(2)) & “-" & bf.GetDataHex(2) & “-" & bf.GetDataHex(6)
  19.         wLen = bf.ConvertEndian(bf.GetDataHex(4))
  20.         bf.SkipData (4)
  21.         Select Case wGUID
  22.         'Header Object
  23.         Case “75B22630-668E-11CF-A6D9-00AA0062CE6C"
  24.             bf.SkipData (6)
  25.         'Extended Content Encryption Object
  26.         Case “D2D0A440-E307-11D2-97F0-00A0C95EA850"
  27.             EntNum = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  28.             For i = 1 To EntNum
  29.                 DescriptorNameLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  30.                 DescriptorName = bf.GetDataUTF16(DescriptorNameLength – 2)
  31.                 Select Case DescriptorName
  32.                 Case “WM/Picture"
  33.                     bf.SkipData (7)
  34.                     JpegLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(4)))
  35.                     bf.SkipData (24)
  36.                     bf.TransferData (JpegLength)
  37.                     bf.OutputFile (“C:\work\xxx.jpg")
  38.                     Exit Do
  39.                 Case Else
  40.                     bf.SkipData (4)
  41.                     DescriptorValueLength = CLng(“&H" & bf.ConvertEndian(bf.GetDataHex(2)))
  42.                     bf.SkipData (DescriptorValueLength)
  43.                 End Select
  44.             Next i
  45.         Case Else
  46.             bf.SkipData (CLng(“&H" & wLen) – 24)
  47.         End Select
  48.     Loop
  49.     Set bf = Nothing
  50. End Sub

 

国本温子(著),緑川吉行(著),できるシリーズ編集部(著)
出版社:インプレス
発売日:2022/3/23
単行本(ソフトカバー):A5判/912ページ

大村あつし(著),古川順平(著)
出版社:技術評論社
発売日:2021/1/9
単行本(ソフトカバー):A5判/800ページ

高橋宣成(著)
出版社:技術評論社
発売日:2019/11/25
単行本(ソフトカバー):B5変形判/576ページ

ファイル解析

Posted by hides