3

ビデオのすべてのiフレームを破棄したい。これを行うには、ビデオのiフレームのみを暗号化するだけでビデオを視聴できないようにするのに十分かどうかを確認したいと思います。これどうやってするの?それらを削除してビデオを再圧縮するだけでは、bフレームなどを再計算せずにストリーム内のiフレームを実際に上書きすることと同じではありません。

4

2 に答える 2

6

libavformat (ffmpeg のライブラリ) を使用すると、ビデオを単一フレームを表すパケットに逆多重化できます。その後、キー フレームとしてマークされたパケット内のデータを暗号化できます。最後に、ビデオを新しいファイルに再多重化できます。libavformat/libavcodec の優れたチュートリアルがここにあります。圧縮データを暗号化したいだけだと思う​​ので、実際にフレームをデコード/エンコードする必要はありません。この場合、 を読み取っAVPacketたら、それがキー フレーム ( ) であれば、そのデータを暗号化するだけpacket->flags & PKT_FLAG_KEYです。その後、パケットを新しいファイルに書き込む必要があります。

libavformat やその他のデマルチプレクサ ソフトウェアから返された I フレーム パケットを暗号化する場合は、ビットストリームに格納されている他のヘッダーからのデータが含まれている可能性があるため、注意が必要です。たとえば、libavformat がビデオ フレーム パケットの一部としてシーケンスまたはピクチャ ヘッダーのグループを返すのをよく見てきました。この情報を破棄すると、テストが無効になる場合があります。

この問題に対処するためのより簡単な方法は、ビデオのエンコードに使用されるコーデックのビットストリーム構文を調査し、開始コードを使用してフレームの開始位置と I フレームかどうかを判断することです。問題の 1 つは、ほとんどのビデオ ファイルには実際の圧縮データの周りにコンテナー (AVI、MP4、MPEG-PS/TS) があり、その領域では何も暗号化したくないということです。ほとんどの場合、単一フレームの圧縮データ内に散在するコンテナー形式に属するヘッダー情報が見つかります。したがってffmpeg、コマンド ラインから を使用して、生の圧縮ビデオ データのみを出力できます。

ffmpeg -i filename -an -vcodec copy -f rawvideo output_filename

これにより、コンテナーのないビデオ データのみ (オーディオなし) のファイルが作成されます。ここから、特定のビデオ形式の開始コードを使用して、I フレームに対応するファイル内のバイト範囲を見つけることができます。

たとえば、MPEG-4 では0x000001b6、VOP (ビデオ オブジェクト プレーン) の開始を示す 32 ビットの開始コードを探します。スタート コードの直後の 2 ビットが と等しいかどうかをテストすることで、I フレームであるかどうかを判断できます00。I フレームの場合は、次の開始コード (24 ビット0x000001) に到達するまでデータを暗号化します。後で復号化を開始する場所がわかるように、開始コードとフレーム タイプ コードはそのままにしておくことをお勧めします。

I フレームを暗号化すると動画が見られなくなるかどうかのテスト結果について。それはあなたの監視不能の意味に依存します。元のビデオが動いている場合、その情報は B または P フレームにエンコードする必要があるため、元のビデオに存在する主要な形状を理解できる可能性があると期待していますが、色とディテールは依然としてゴミです。I フレームのシングル ビット エラーにより、画像のグループ全体 (I フレームとそれに依存するすべてのフレーム) がゴミのように見えるのを見てきました。圧縮の目的は、各ビットが重要になるまで冗長性を減らすことです。I フレーム全体を破棄すると、ほぼ確実に監視できなくなります。

編集:コメントへの応答

開始コードはバイト単位で整列されることが保証されているため、ファイルを一度に 1 バイトずつ 4 バイトのバッファーに読み込み、それが開始コードと等しいかどうかをテストできます。C++ では、次の方法でこれを行うことができます。

#include <iostream>
using namespace std;
//...

//...
ifstream ifs("filename", ios::in | ios::binary);
//initialize buffer to 0xffffffff
unsigned char buffer[4] = {0xff, 0xff, 0xff, 0xff};
while(!ifs.eof())
{
    //Shift to make space for new read.
    buffer[0] = buffer[1];
    buffer[1] = buffer[2];
    buffer[2] = buffer[3];

    //read next byte from file
    buffer[3] = ifs.get();

    //see if the current buffer contains the start code.
    if(buffer[0]==0x00 && buffer[1]==0x00 && buffer[2]==0x01 && buffer[3]==0xb6)
    {
        //vop start code found
        //Test for I-frame
        unsigned char ch = ifs.get();
        int vop_coding_type = (ch & 0xc0) >> 6;   //masks out the first 2 bits and shifts them to the least significant bits of the uchar
        if(vop_coding_type == 0)
        {
            //It is an I-frame
            //...
        }
    }
}

24 ビットの開始コードの検索も同様で、3 バイトのバッファを使用するだけです。これを行う前に、ffmpeg を使用してビデオ コンテナーを削除する必要があることに注意してください。そうしないと、コンテナー情報の一部が破棄される可能性があります。

于 2010-04-12T15:04:08.483 に答える
0

Windowsでは、 VFWを使用して再圧縮せずにファイルをコピーし、Iフレームをスキップできます。Iフレームを見つけるには、フラグ付きのFindSample関数を使用できます。FIND_KEY

于 2010-04-12T13:31:31.730 に答える