7-Zipアーカイバーのmp3ファイルフィルターの実装

長い間、私の唯一のアーカイバは7-Zipプログラムです。 私はその圧縮率と作業速度が好きなので、ソフトウェア配布の圧縮、写真のコレクションのアーカイブ、音楽リリースの保存など、ほぼすべての場所で使用しています。 オンラインの非営利ラベルから音楽をダウンロードします。音楽は、ほとんどの場合、楽曲やカバーアートを含むアーカイブ(zipまたはrar)の形式で配信されます。 ダウンロード後、アーカイブは7-Zipで圧縮され、そのままハードディスクに保存されます。 音楽を聴くために、現代のプレーヤーは音楽を直接再生できるため(特にFoobar2000を使用しています)、アーカイブを解凍する必要はありません。 そして、すべてのアーカイブが占有するメモリの総量はまだハードドライブの容量からは程遠いですが、mp3ファイルの圧縮率を改善するというアイデアを取り始めました。 私の先生の一人が言ったように、課題は不満な不安感です。 それはまさに私が感じていた。 トランスコーダーを発明したくなかったので、冗長な情報を削除するフィルターを作成することにしました。


タスク条件の分析


mp3とは、MPEG-1 / 2 / 2.5レイヤー3を意味します。mp3ファイルとは何かを見てみましょう。
したがって、mp3ファイルは多くのフレームで構成され、フレームは相互に接続できます。つまり、1つのフレームをデコードするには、別のフレームを調べる必要がある場合があります。 ファイルには、オーディオデータの前後にタグが含まれる場合があります。 各フレームには1152サンプル(ステレオモードの場合)が保存され、26 msの持続時間があります。 フレームサイズは、使用されるビットレートとサンプリングレートによって異なり、次の式で計算されます。


パディングは、フレームヘッダー内の特別なフラグで、フレームが1バイトでパディングされることを意味します。

フレームは、ヘッダー、検証コード(オプション)、サンプルのデコードに必要な情報(このフレーズのロシア語の翻訳を受け入れられないため、この情報を「サイド情報」と呼びます)、実際にパックされたサンプル、およびエンコードされたサンプルとの直接的な関係:



32ビットヘッダーの構造は次のとおりです。
役職フィールド長予定
同期ワード11タイトルの検索に使用されます。 11ビットすべてが「1」に設定されます
MPEGバージョン2
レイヤーインデックス2
少しの保護1設定されていない場合、フレームにはCRCが含まれます
ビットレートインデックス4
サンプルレートインデックス2
パディングビット1フレームに1バイトが追加されたことを示す同じフラグ
プライベートビット1特定の情報を保持します。
チャネルコーディングモード2モノラル、ステレオ、ジョイントステレオ、デュアルチャネル
モード拡張2ジョイントステレオチャネルエンコーディングモードで使用
著作権ビット1このビットが設定されている場合、ファイルのコピーは違法であることを意味します
元のビット1このビットが設定されている場合、ファイルが元のメディアにあることを意味します
アクセント(強調)2追加のオーディオ処理が必要であることをデコーダに伝えます


実際には、一部のヘッダーフィールドは使用されず、かつ/またはmp3ファイル全体で同じままです。 たとえば、MPEGバージョン、レイヤーインデックス、プライベートビット、著作権ビット、元のビットなど。 ファイルが固定ビットレート(CBR)を使用して作成された場合、ビットレートインデックスフィールドは変更されません。
最初に考えたのは、フレームのすべてのヘッダーフィールドを保存する必要はなく、ファイル全体で変化するヘッダーフィールドのみを保存する必要があるということです。 残りのフィールドは、フィールドの変更ではなく、1回のみ保存できます。 すべてのフレームのヘッダーを調べて、統計を収集し、実際に使用されているフィールドを特定できます。

CRC検証コードは、ヘッダーのすぐ後ろにあります。 フレームヘッダーの最後の16ビットとすべてのサイド情報バイトに対してCRC16アルゴリズムを使用して計算される16ビット整数です。
2番目の考えは、検証コードの計算方法がわかっているため、保存できないことです。 もちろん、フレームからCRCを取り出して捨てる権利はありません。 最初に、エラーが検証コード自体または計算されるバイトに侵入する可能性があるため、それが正しい値を表していることを確認する必要があります。

サイド情報の詳細については詳しく説明しません。 サイド情報は、各フレームで変化する多くのフィールドを持つかなり複雑な構造です。 フレームヘッダーフィールドと同じように、サイドインフォメーションフィールドでも同じトリックを実行することはできません。

サイド情報の後には、ハフマン圧縮オーディオデータが続きます。 実際、ハフマンコードはスケールファクターと交互に変化するため、これは完全に真実ではありませんが、簡単にするために、サイド情報の後、フレームの最後までオーディオデータが配置されると仮定します。

このデータ間にフレームヘッダーシグネチャ(同期ワード)がない場合のみ、他のデータがフレーム間にある可能性があります。

アルゴリズム


7-Zipのソースコードを調べた後、実行可能ファイル(* .exe、* .dll)の圧縮を改善するために設計されたBCJ2フィルターの実装に出会いました。 このフィルターの特徴は、1つの入力と4つの出力があることです。 各出力には独自のエンコーダがあります。 したがって、入力ファイルは4つのストリームに分割され、各ストリームは独自のエンコーダーで圧縮されていることがわかります。

いくつかのexitのアイデアが気に入ったので、フィルターに適用することにしました。
-最初の考えに従って、フレームヘッダーフィールドを1つのストリームにパックする
-2番目のストリームのサイド情報をパックする
-最後に、3番目のストリームで、残りの情報(ハフマンのタグとコード)をパックします

最初の2つのストリームは、アーカイブヘッダーを圧縮するために7-Zip内で使用される設定でLZMAアルゴリズムを使用して圧縮され、3番目のストリームは[アーカイブに追加]ウィンドウでユーザーが選択したアルゴリズムによって圧縮されます。

エンコーダは次のように機能します。ファイルのすべてのフレームが順番に検索されます。 フレームは3つの部分に分かれています。サイド情報はサイド情報ストリームに送信され、ハフマンコードはメイン出力ストリームに送信され、ヘッダーフィールドはバッファに保存されます。 フレームにCRCが存在し、それが真であることが判明した場合、スキップされます。それ以外の場合、その値はアンパック時に復元できるようにヘッダーストリームに転送されます。
各ヘッダーの同期ワード(11ビット)は、単に破棄されます。 ファイル中に変更されなかったフィールドの値は、ヘッダーストリームに1回だけ書き込まれますが、変更フィールドは次々に順番に書き込まれます。

デコーダーはエンコーダーにミラーリングされて機能します。まず、すべてのヘッダーが復元され、次に各フレームの復元が開始されます。 最初のCRCストリームから計算または復元され、その後にサイド情報とフレームの残りが続きます。

実装と実際の結果


実装は特に複雑ではないため、ここに実装する意味はわかりません。 githubに投稿されたソース。 7-Zipでのそのようなフィルター(1つの入力と複数の出力)のサポートが十分に透過的に実装されていないことに注意してください。 はい、ところで、フィルターを開発するとき、7-Zip 9.20のソースが使用されました。
コンパイルされたdllは同じgithubにあります。 彼女は、7-Zipをインストールしたフォルダー内の7z.dllを置き換える必要があります。

作業のテストは、Windows XPオペレーティングシステム、Intel Core 2 6700プロセッサ(2.66 GHz)、および3ギガバイトのRAMを搭載したコンピューターで、総容量16755839778バイト(15.605 GB)の1351ファイルのサンプルで実行されました。 各ファイルは個別にアーカイブに圧縮され、解凍されました。 まず、フィルターを使用せずに、次にフィルターを使用します。 すべての場所でUltra圧縮レベルが使用されました。

フィルターなしフィルター付き
圧縮データの総量16300442691バイト(15.181 GB)16064243440バイト(14.961 GB)
パッケージングに費やした合計時間12181.09秒11273.47秒
開梱にかかった合計時間3215.44秒2744.76秒


保存できるフィルター:
-ハードドライブ上の236199251バイト(〜225 MB)のメモリ
-パッケージで908秒(〜15分)
-開梱で407秒(〜8分)

ご覧のように、パッケージング速度は8%増加し、解凍速度は最大15%増加しました。

おわりに


このフィルターにより、mp3ファイルの圧縮率が1.5%向上しました。 フィルターは圧縮データで機能するため、この結果は未解決とは言えませんが、悪いとも言えません。
以上です。 ご清聴ありがとうございました。

Source: https://habr.com/ru/post/J125336/


All Articles