4. cx2341x 驅動

4.1. 未壓縮檔案格式

cx23416 可以生成(並且 cx23415 也可以讀取)原始 YUV 輸出。YUV 幀的格式為 16x16 線性平鋪 NV12 (V4L2_PIX_FMT_NV12_16L16)。

該格式為 YUV 4:2:0,每個畫素使用 1 個 Y 位元組,每四個畫素使用 1 個 U 和 V 位元組。

資料編碼為兩個宏塊平面,第一個包含 Y 值,第二個包含 UV 宏塊。

Y 平面從左到右、從上到下分為 16x16 畫素的塊。每個塊依次逐行傳輸。

因此,前 16 位元組是左上角塊的第一行,接下來的 16 位元組是左上角塊的第二行,依此類推。傳輸完這個塊後,第一個塊右側塊的第一行將開始傳輸,依此類推。

UV 平面從左到右、從上到下分為 16x8 UV 值的塊。每個塊依次逐行傳輸。

因此,前 16 位元組是左上角塊的第一行,包含 8 對 UV 值(共 16 位元組)。接下來的 16 位元組是左上角塊 8 對 UV 值的第二行,依此類推。傳輸完這個塊後,第一個塊右側塊的第一行將開始傳輸,依此類推。

下面的程式碼提供瞭如何將 V4L2_PIX_FMT_NV12_16L16 轉換為單獨的 Y、U 和 V 平面的示例。此程式碼假定幀為 720x576 (PAL) 畫素。

幀的寬度始終為 720 畫素,無論實際指定的寬度是多少。

如果高度不是 32 行的倍數,則捕獲的影片末尾會缺少宏塊,從而無法使用。因此,高度必須是 32 的倍數。

4.1.1. 原始格式 C 示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static unsigned char frame[576*720*3/2];
static unsigned char framey[576*720];
static unsigned char frameu[576*720 / 4];
static unsigned char framev[576*720 / 4];

static void de_macro_y(unsigned char* dst, unsigned char *src, int dstride, int w, int h)
{
unsigned int y, x, i;

// descramble Y plane
// dstride = 720 = w
// The Y plane is divided into blocks of 16x16 pixels
// Each block in transmitted in turn, line-by-line.
for (y = 0; y < h; y += 16) {
        for (x = 0; x < w; x += 16) {
        for (i = 0; i < 16; i++) {
                memcpy(dst + x + (y + i) * dstride, src, 16);
                src += 16;
        }
        }
}
}

static void de_macro_uv(unsigned char *dstu, unsigned char *dstv, unsigned char *src, int dstride, int w, int h)
{
unsigned int y, x, i;

// descramble U/V plane
// dstride = 720 / 2 = w
// The U/V values are interlaced (UVUV...).
// Again, the UV plane is divided into blocks of 16x16 UV values.
// Each block in transmitted in turn, line-by-line.
for (y = 0; y < h; y += 16) {
        for (x = 0; x < w; x += 8) {
        for (i = 0; i < 16; i++) {
                int idx = x + (y + i) * dstride;

                dstu[idx+0] = src[0];  dstv[idx+0] = src[1];
                dstu[idx+1] = src[2];  dstv[idx+1] = src[3];
                dstu[idx+2] = src[4];  dstv[idx+2] = src[5];
                dstu[idx+3] = src[6];  dstv[idx+3] = src[7];
                dstu[idx+4] = src[8];  dstv[idx+4] = src[9];
                dstu[idx+5] = src[10]; dstv[idx+5] = src[11];
                dstu[idx+6] = src[12]; dstv[idx+6] = src[13];
                dstu[idx+7] = src[14]; dstv[idx+7] = src[15];
                src += 16;
        }
        }
}
}

/*************************************************************************/
int main(int argc, char **argv)
{
FILE *fin;
int i;

if (argc == 1) fin = stdin;
else fin = fopen(argv[1], "r");

if (fin == NULL) {
        fprintf(stderr, "cannot open input\n");
        exit(-1);
}
while (fread(frame, sizeof(frame), 1, fin) == 1) {
        de_macro_y(framey, frame, 720, 720, 576);
        de_macro_uv(frameu, framev, frame + 720 * 576, 720 / 2, 720 / 2, 576 / 2);
        fwrite(framey, sizeof(framey), 1, stdout);
        fwrite(framev, sizeof(framev), 1, stdout);
        fwrite(frameu, sizeof(frameu), 1, stdout);
}
fclose(fin);
return 0;
}

4.2. 嵌入式 V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI 資料的格式

作者:Hans Verkuil <hverkuil@xs4all.nl>

本節描述了嵌入在 MPEG-2 程式流中的 VBI 資料的 V4L2_MPEG_STREAM_VBI_FMT_IVTV 格式。此格式部分受 ivtv 驅動(Conexant cx23415/6 晶片的驅動)的一些硬體限制,特別是 VBI 資料的最大大小。任何超出此長度的資料在透過 cx23415 回放 MPEG 流時都會被截斷。

這種格式的優點是它非常緊湊,並且所有行的所有 VBI 資料都可以在不超過最大允許大小的情況下儲存。

VBI 資料流 ID 為 0xBD。嵌入式資料的最大大小為 4 + 43 * 36 位元組,其中包括 4 位元組的頭部,以及 2 * 18 行 VBI 資料,每行包含 1 位元組的頭部和 42 位元組的負載。任何超出此限制的資料都會被 cx23415/6 韌體截斷。除了 VBI 行資料之外,我們還需要 36 位用於確定捕獲哪些行的位掩碼,以及 4 位元組的魔術字,表示此資料包包含 V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI 資料。如果所有行都已使用,則不再有空間容納位掩碼。為解決此問題,引入了兩個不同的魔術數字:

‘itv0’:此魔術數字後跟兩個無符號長整型。第一個無符號長整型的位 0-17 表示捕獲了第一個場的哪些行。第一個無符號長整型的位 18-31 和第二個無符號長整型的位 0-3 用於第二個場。

‘ITV0’:此魔術數字假定所有 VBI 行都被捕獲,即它隱含地表示位掩碼為 0xffffffff 和 0xf。

在這些魔術字(如果是 ‘itv0’ 魔術字,則還包括 8 位元組的位掩碼)之後,捕獲的 VBI 行開始傳輸。

對於每一行,第一個位元組的最低有效 4 位包含資料型別。可能的值如下表所示。負載位於接下來的 42 位元組中。

以下是可能的資料型別列表

#define IVTV_SLICED_TYPE_TELETEXT       0x1     // Teletext (uses lines 6-22 for PAL)
#define IVTV_SLICED_TYPE_CC             0x4     // Closed Captions (line 21 NTSC)
#define IVTV_SLICED_TYPE_WSS            0x5     // Wide Screen Signal (line 23 PAL)
#define IVTV_SLICED_TYPE_VPS            0x7     // Video Programming System (PAL) (line 16)