1.28. 影像裁剪、插入和縮放——CROP API¶
注意
CROP API 大部分已被新的 SELECTION API 取代。除畫素寬高比檢測(由 VIDIOC_CROPCAP 實現,且在 SELECTION API 中沒有等效項)外,新 API 在大多數情況下應優先使用。有關兩個 API 的比較,請參見 與舊裁剪 API 的比較。
一些影片捕獲裝置能夠對影像的子部分進行取樣,並將其縮小或放大到任意大小的影像。我們稱這些能力為裁剪和縮放。一些影片輸出裝置可以將影像放大或縮小,並將其插入到影片訊號的任意掃描線和水平偏移位置。
應用程式可以使用以下 API 來選擇影片訊號中的區域,查詢預設區域和硬體限制。
注意
儘管名稱如此,VIDIOC_CROPCAP、VIDIOC_G_CROP 和 VIDIOC_S_CROP ioctl 既適用於輸入裝置,也適用於輸出裝置。
縮放需要源和目標。在影片捕獲或疊加裝置上,源是影片訊號,裁剪 ioctl 確定實際取樣的區域。目標是應用程式讀取的影像或疊加到圖形螢幕上的影像。它們的大小(以及疊加的位置)透過 VIDIOC_G_FMT 和 VIDIOC_S_FMT ioctl 進行協商。
在影片輸出裝置上,源是應用程式傳入的影像,它們的大小同樣透過 VIDIOC_G_FMT 和 VIDIOC_S_FMT ioctl 進行協商,或者可能編碼在壓縮影片流中。目標是影片訊號,裁剪 ioctl 確定影像插入的區域。
即使裝置不支援縮放或 VIDIOC_G_CROP 和 VIDIOC_S_CROP ioctl,源和目標矩形也已定義。在這種情況下,它們的大小(以及適用時的位置)將是固定的。
注意
所有支援 CROP 或 SELECTION API 的捕獲和輸出裝置也將支援 VIDIOC_CROPCAP ioctl。
1.28.1. 裁剪結構¶
影像裁剪、插入和縮放¶
裁剪、插入和縮放過程
對於捕獲裝置,可以取樣的區域的左上角座標、寬度和高度由 VIDIOC_CROPCAP ioctl 返回的 v4l2_cropcap 結構體的 bounds 子結構給出。為了支援廣泛的硬體,本規範沒有定義原點或單位。然而,根據慣例,驅動程式應水平地將未縮放的樣本相對於 0H(水平同步脈衝的前沿,參見 圖 4.1. 行同步)進行計數。垂直方向上,ITU-R 第一場的行號(參見 ITU R-525 行號,針對 525 行 和 625 行),如果驅動程式可以捕獲兩個場,則乘以二。
源矩形(即實際取樣的區域)的左上角座標、寬度和高度由 v4l2_crop 結構體使用與 v4l2_cropcap 結構體相同的座標系給出。應用程式可以使用 VIDIOC_G_CROP 和 VIDIOC_S_CROP ioctl 來獲取和設定此矩形。它必須完全位於捕獲邊界內,驅動程式可以根據硬體限制進一步調整請求的大小和/或位置。
每個捕獲裝置都有一個預設的源矩形,由 v4l2_cropcap 結構體的 defrect 子結構給出。此矩形的中心應與影片訊號活動影像區域的中心對齊,並覆蓋驅動程式編寫者認為的完整影像。驅動程式應在首次載入時將源矩形重置為預設值,但之後不再重置。
對於輸出裝置,這些結構體和 ioctl 相應地使用,定義了影像將被插入影片訊號的目標矩形。
1.28.2. 縮放調整¶
影片硬體可能存在各種裁剪、插入和縮放限制。它可能只支援放大或縮小,只支援離散的縮放因子,或者在水平和垂直方向具有不同的縮放能力。此外,它可能根本不支援縮放。同時,v4l2_crop 矩形可能需要對齊,並且源和目標矩形可能具有任意的上下尺寸限制。特別是,v4l2_crop 結構體中的最大 width 和 height 可能小於 v4l2_cropcap 結構體的 bounds 區域。因此,像往常一樣,驅動程式應調整請求的引數並返回實際選擇的值。
應用程式可以首先更改源矩形或目標矩形,因為它們可能更喜歡特定的影像尺寸或影片訊號中的某個區域。如果驅動程式必須同時調整兩者以滿足硬體限制,則最後請求的矩形應具有優先權,驅動程式應優先調整另一個矩形。然而,VIDIOC_TRY_FMT ioctl 不應更改驅動程式狀態,因此只能調整請求的矩形。
假設影片捕獲裝置上的縮放限制為在任一方向上 1:1 或 2:1 的因子,並且目標影像尺寸必須是 16 × 16 畫素的倍數。源裁剪矩形設定為預設值,在此示例中,預設值也是上限,為 640 × 400 畫素,偏移量為 0, 0。應用程式請求影像尺寸為 300 × 225 畫素,假設影片將根據“全影像”相應縮小。驅動程式將影像尺寸設定為最接近的可能值 304 × 224,然後選擇最接近請求尺寸的裁剪矩形,即 608 × 224(224 × 2:1 將超出限制 400)。偏移量 0, 0 仍然有效,因此未修改。給定 VIDIOC_CROPCAP 報告的預設裁剪矩形,應用程式可以輕鬆提出另一個偏移量來使裁剪矩形居中。
現在,應用程式可能堅持使用接近原始請求的影像寬高比來覆蓋區域,因此它要求一個 608 × 456 畫素的裁剪矩形。當前的縮放因子將裁剪限制為 640 × 384,因此驅動程式返回裁剪尺寸 608 × 384 並將影像尺寸調整為最接近的 304 × 192。
1.28.3. 示例¶
源和目標矩形在裝置關閉和重新開啟時應保持不變,以便資料進出裝置無需特殊準備即可工作。更高階的應用程式應在開始 I/O 之前確保引數合適。
注意
在接下來的兩個示例中,假設是一個影片捕獲裝置;對於其他型別的裝置,請將 V4L2_BUF_TYPE_VIDEO_CAPTURE 更改為其他型別。
1.28.4. 示例:重置裁剪引數¶
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
memset (&cropcap, 0, sizeof (cropcap));
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
perror ("VIDIOC_CROPCAP");
exit (EXIT_FAILURE);
}
memset (&crop, 0, sizeof (crop));
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect;
/* Ignore if cropping is not supported (EINVAL). */
if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
&& errno != EINVAL) {
perror ("VIDIOC_S_CROP");
exit (EXIT_FAILURE);
}
1.28.5. 示例:簡單縮小¶
struct v4l2_cropcap cropcap;
struct v4l2_format format;
reset_cropping_parameters ();
/* Scale down to 1/4 size of full picture. */
memset (&format, 0, sizeof (format)); /* defaults */
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = cropcap.defrect.width >> 1;
format.fmt.pix.height = cropcap.defrect.height >> 1;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
if (-1 == ioctl (fd, VIDIOC_S_FMT, &format)) {
perror ("VIDIOC_S_FORMAT");
exit (EXIT_FAILURE);
}
/* We could check the actual image size now, the actual scaling factor
or if the driver can scale at all. */
1.28.6. 示例:選擇輸出區域¶
注意
本示例假設一個輸出裝置。
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
memset (&cropcap, 0, sizeof (cropcap));
cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (-1 == ioctl (fd, VIDIOC_CROPCAP;, &cropcap)) {
perror ("VIDIOC_CROPCAP");
exit (EXIT_FAILURE);
}
memset (&crop, 0, sizeof (crop));
crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
crop.c = cropcap.defrect;
/* Scale the width and height to 50 % of their original size
and center the output. */
crop.c.width /= 2;
crop.c.height /= 2;
crop.c.left += crop.c.width / 2;
crop.c.top += crop.c.height / 2;
/* Ignore if cropping is not supported (EINVAL). */
if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
&& errno != EINVAL) {
perror ("VIDIOC_S_CROP");
exit (EXIT_FAILURE);
}
1.28.7. 示例:當前縮放因子和畫素寬高比¶
注意
本示例假設一個影片捕獲裝置。
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format format;
double hscale, vscale;
double aspect;
int dwidth, dheight;
memset (&cropcap, 0, sizeof (cropcap));
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
perror ("VIDIOC_CROPCAP");
exit (EXIT_FAILURE);
}
memset (&crop, 0, sizeof (crop));
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl (fd, VIDIOC_G_CROP, &crop)) {
if (errno != EINVAL) {
perror ("VIDIOC_G_CROP");
exit (EXIT_FAILURE);
}
/* Cropping not supported. */
crop.c = cropcap.defrect;
}
memset (&format, 0, sizeof (format));
format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl (fd, VIDIOC_G_FMT, &format)) {
perror ("VIDIOC_G_FMT");
exit (EXIT_FAILURE);
}
/* The scaling applied by the driver. */
hscale = format.fmt.pix.width / (double) crop.c.width;
vscale = format.fmt.pix.height / (double) crop.c.height;
aspect = cropcap.pixelaspect.numerator /
(double) cropcap.pixelaspect.denominator;
aspect = aspect * hscale / vscale;
/* Devices following ITU-R BT.601 do not capture
square pixels. For playback on a computer monitor
we should scale the images to this size. */
dwidth = format.fmt.pix.width / aspect;
dheight = format.fmt.pix.height;