3

私のサイトでは、ユーザーは動画をアップロードできます。動画はその場で暗号化され、別のサーバーに保存されます。ビデオのビットレート、フレームレートなどを保存したいのですが、それらに直接アクセスできず、次のコマンドを使用することはできません:

ffprobe -show_streams -i file.mp4

moov アトムを含む最後のチャンクをサーバーに保存しようとしましたが、ffprobe が出力されます。

Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
moov atom not found
C:\file.mp4: Invalid data found when processing input

moov アトムはそのままですが、チェックして少なくとも 1 バイトを切り捨てると、これが発生します。

moov アトムを含むファイル フラグメントからビデオ メタデータを取得する適切な方法は何ですか? mdata アトムの一部から情報を取得するのはどうですか?

4

1 に答える 1

8

ffmpeg パーサーがチャンク ファイルの moov アトムを見つける方法を知っているとは思いません。moov アトムが見つかるまで mp4 ファイルをチャンクごとに解析 (読み取りまたはスキップ) します。先頭の一部を切り取ると、チャンク構造が壊れて moov アトムが見つかりません。

考えられる解決策の 1 つは、末尾に moov アトムがあるファイルを検出し、-movflags +faststart (または c/c++ コードの同等の AVOptions) を使用して ffmpeg で再多重化することにより、moov アトムを先頭に移動することです。次に、moov アトムの後にファイルを切り詰めることができ、ヘッダーの解析は引き続き機能します。

[編集]

したがって、切り捨てられたフラグメントを意識した変更を mov デマルチプレクサ (コメントを参照) に書き込む場合は、次のようになります。まず第一に、mov_read_default() を変更しないようにしてください。これは中心的な再帰エンジンであり、ここを変更するとほとんどの通常の機能が壊れる可能性があります。むしろ、mov_read_header() に変更を加えてください (ここではヘッダーの解析のみに関心があり、フレームのデマルチプレクサーにはあまり関心がないため)。次のコードがあります。

if (mov->moov_retry)
    avio_seek(pb, 0, SEEK_SET);
if ((err = mov_read_default(mov, pb, atom)) < 0) {
    av_log(s, AV_LOG_ERROR, "error reading header\n");
    mov_read_close(s);
    return err;
}
} while (pb->seekable && !mov->found_moov && !mov->moov_retry++);
if (!mov->found_moov) {

これは、moov が上位レベルのアトムであるヘッダー ツリー構造をデコードしようとしています。ファイル内で、次のようなシーケンスを探します。

$ hexdump -n 32 -s 41934133 -C somefile.mov 
027fdd35  00 00 3e b4 6d 6f 6f 76  00 00 00 6c 6d 76 68 64  |..>.moov...lmvhd|
027fdd45  00 00 00 00 c9 6b 7b f5  c9 6b 7c 02 00 00 02 58  |.....k{..k|....X|

0x00003eb4 は「moov」アトムのバイト単位のサイズであり、その中にサイズ 0x0000006c バイトの「mvhd」と呼ばれるサブアトムがあります (ツリー構造はこの後しばらく続きます)。ファイルを逆多重化するときに、ファイル ポインターをこの正確なオフセットに設定すると、正しくデコードされます。

$ tail -c +41934134 somefile.mov > /tmp/hdr.mov
$ ffprobe  /tmp/hdr.mov
[..]
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f871b002a00] stream 0, offset 0x3f3e: partial file
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f871b002a00] Could not find codec parameters for stream 0 (Video: h264 (avc1 / 0x31637661), none(bt709), 1280x720, 10695 kb/s): unspecified pixel format
[..]
    Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none(bt709), 1280x720, 10695 kb/s, 29.97 fps, 29.97 tbr, 600 tbn, 1200 tbc (default)
[..]
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 63 kb/s (default)

その時点までのファイル オフセットを取得する方法は、あなた次第です。

  • mov_read_header () にコードを追加して、ファイルの「moov」(0x6d6f6f76) をスキャンし、ファイル ポインターをその 4 バイト前に設定できます。
  • このフラグメントを作成するコードで、そのフラグメントをファイルに保存する前に、moov をスキャンし、moov アトムの前にある先頭のゴミを切り取ることができます。

ffmpeg を変更して、他の機能にも使用する ffmpeg バージョンにこれを配置する場合は、これを何らかのオプションの下に配置して、デフォルトのファイル読み取りが有効にならないようにすることをお勧めします。そうしないと、通常の mov/mp4 ファイルの解析が正しく機能しなくなるリスクがあります。

于 2015-09-12T12:11:26.953 に答える