3

したがって、最終年度のプロジェクトでは、Video4Linux2を使用してカメラからYUV420画像をプルし、それらをx264(これらの画像をネイティブに使用)に解析してから、エンコードされたストリームをLive555経由でRTP/RTCP準拠のビデオプレーヤーに送信します。ワイヤレスネットワークを介したクライアント。これらすべてをリアルタイムで実行しようとしているので、制御アルゴリズムがありますが、それはこの質問の範囲ではありません。Live555を除くこれらすべてはCで書かれています。現在、私はビデオのエンコードが終わりに近づいていますが、パフォーマンスを向上させたいと考えています。

控えめに言っても、私は問題にぶつかりました... V4L2のユーザースペースポインターを避け、mmap()を使用しようとしています。私はビデオをエンコードしていますが、YUV420なので、x264が読み取るためにY'、U、V平面を3つの異なる変数に保持するために新しいメモリをmallocしています。これらの変数をmmapされたメモリへのポインタとして保持したいと思います。

ただし、V4L2デバイスにはバッファリングされたストリーム用の単一のファイル記述子があり、ストリームをYUV420標準に準拠した3つのmmap変数に分割する必要があります...

buffers[n_buffers].y_plane = mmap(NULL, (2 * width * height) / 3,
                                    PROT_READ | PROT_WRITE, MAP_SHARED,
                                    fd, buf.m.offset);
buffers[n_buffers].u_plane = mmap(NULL, width * height / 6,
                                    PROT_READ | PROT_WRITE, MAP_SHARED,
                                    fd, buf.m.offset +
                                    ((2 * width * height) / 3 + 1) /
                                    sysconf(_SC_PAGE_SIZE));
buffers[n_buffers].v_plane = mmap(NULL, width * height / 6,
                                    PROT_READ | PROT_WRITE, MAP_SHARED,
                                    fd, buf.m.offset +
                                    ((2 * width * height) / 3 + 
                                    width * height / 6 + 1) / 
                                    sysconf(_SC_PAGE_SIZE));

ここで、「幅」と「高さ」はビデオの解像度です(例:640x480)。

私が理解していることから...MMAPは次のよ​​うなファイルを検索します(疑似コード):

fd = v4l2_open(...);
lseek(fd, buf.m.offset + (2 * width * height) / 3);
read(fd, buffers[n_buffers].u_plane, width * height / 6);

私のコードはここのLaunchpadリポジトリにあります(詳細については):http: //bazaar.launchpad.net/~alex-stevens/+junk/spyPanda/files(リビジョン11)

そして、YUV420フォーマットはこのWikiの図からはっきりと見ることができます:http://en.wikipedia.org/wiki/File :Yuv420.svg (私は基本的にY、U、Vバイトを各mmapに分割したいメモリー)

1つのファイル記述子から3つの変数をメモリにmmapする方法を説明したい人はいますか、それともなぜ私が失敗したのですか?または、YUV420バッファをx264に解析するためのより良いアイデアを示唆することさえできますか?:P

乾杯!^^

4

2 に答える 2

3

3つの別々のは必要ありませんmmap。一度だけmmap、マップ全体のベースポインタを基準にして各平面のベースポインタを計算します。

編集:あなたはこのようなものが必要です:

unsigned char *y = mmap(...); /* map total size of all 3 planes */
unsigned char *u = y + y_height*y_bytes_per_line;
unsigned char *v = u + u_height*u_bytes_per_line;
于 2011-06-09T13:42:33.753 に答える
1

私があなたが望むものを理解したなら、あなたはmmap'uninterleave'シーケンシャルメモリを別々のポインタにすることはできません。単一のメモリブロックをmmapし、バッファ内の適切なオフセットを手動で計算する必要がありますか?

(しかし、同じfdを数回mmapできない理由はまったくありません。何が悪かったのかは決して言わなかったでしょう。)

于 2011-06-09T13:09:54.320 に答える