V4L2文檔翻譯(六)

http://linuxtv.org/downloads/v4l-dvb-apis/crop.html

圖像裁剪、插入及縮放


一些視頻捕捉設備可以取一張圖片的小部分,然後對圖片進行任意尺寸的放大或縮小。我們將這些能力稱之爲裁剪和縮放。一些視頻使出設備可以將圖片放大或縮小,然後將其插入到視頻信號的任意掃描線和橫向偏移中。

應用程序可以使用一下API來選擇視頻信號中的區域,查詢默認區域以及硬件限制。不管他們的名字是什麼,VIDIOC_CROPCAP VIDIOC_G_CROP VIDIOC_S_CROP ioctl都可以作用於輸入及輸出設備。

裁剪需要源和目標。在視頻捕捉或overlay設備上源就是視頻信號,然後通過裁剪ioctl決定需要裁剪的區域。目標就是程序讀取的圖片或overlay到物理屏幕上。他們的尺寸(overlay可選)是通過VIDIOC_G_FMT和VIDIOC_S_FMT ioctl協商決定的。

在一個視頻輸出設備上源是應用程序走過的圖片,他們的尺寸還是通過VIDIOC_G/S_FMT ioctl協商確定的,或者也可能是編碼壓縮入了視頻流中。目標是視頻信號,且才加你ioctl決定圖片插入哪個區域。

就算設備不支持裁剪或VIDIOC_G/S_FMT等ioctl源和目標矩形區域依然被定義。他們的尺寸(或許是位置)在這種情況下將不變。所有捕捉及輸出設備必須支持VIDIOC_CROPCAP ioctl,這樣應用程序就可以決定能否進行裁剪。


裁剪結構體

視頻捕捉設備左上角,可取樣區域的寬高可以通過VIDIOC_CRAOCAP ioctl返回的struct v4l2_cropcap結構體中的bound子成員結構體給出。爲了兼容更廣泛的硬件設備,這裏不會定義起點和單位。按照慣例,驅動應該橫向計算相對於0H的取樣範圍,豎向的是第一個區域(4.2 ITU-R 525)的ITU-R線數量。如果驅動能夠捕獲兩個區域則乘以二。

左上角源矩形的寬高是實際能取樣的區域,通過struct v4l2_crop結構體給出,座標系統與struct v4l2_cropcap相同。應用程序可以通過使用VIDIOC_G_CROP和VIDIOC_S_CROP ioctl來獲取和設置矩形區域。它必須完全在捕捉範圍內,而且驅動之後可能根據硬件限制修改所請求的尺寸及(或)位置。

每個捕捉設備都有一個默認的源矩形,通過struct v4l2_cropcap結構提中的defrect成員結構體給出。矩形的中心應該與視頻信號中的活躍圖片區域中心對準,且涵蓋驅動編寫者所關心的完整圖片。在驅動首次加載時,驅動就應對源矩形區域進行重置,而不是之後再做。

對於輸出設備來說,這些結構體和ioctl的使用就要看情況。定義目標矩形區域即代表要把圖片插入到視頻信號中的哪裏。


縮放調整

視頻硬件可擁有各種裁剪、插入及縮放限制。可能只能放大或縮小,只支持離散的縮放係數,或在橫向和豎向上有不同的縮放能力,也可能根本就不支持縮放。struct v4l2_crop矩形被對齊的同時,源和目標矩形可能擁有了無限制的縮放尺寸。特別是在結構體struct v4l2_crop中的最大width和height可能會比struct v4l2_cropcap.bounds區域要小。因此,慣例,驅動要對請求的參數進行調整然後返回選擇的實際值。

應用程序可以首先改變源或目標的矩形區域,比如一張特殊的圖片尺寸或視頻信號中的明確區域。如果驅動不得不因爲硬件限制進行調整,那麼最後的請求是最優先的,且驅動應該傾向於調整相反的那一個。無論如何,VIDIOC_TRY_FMT ioctl不應該修改驅動狀態,且只是調整所請求的矩形區域。

假設在一個視頻捕捉設備上進行縮放,在每個方向上其係數爲1:1或2:1,且圖像尺寸必須是16 x 16像素的整數倍。源裁剪矩形區域被設置爲默認,這個區域也作爲此例中的上限值。640 x 400像素爲偏移0,0。一個應用程序請求一張300 x 225像素的圖片,假設視頻會根據全圖進行縮小。驅動設置圖像尺寸爲最接近的數值304 x 224,然後選擇裁剪矩形區域爲最接近請求尺寸的608 x 224(224 x 2:1會超過400的限制)。偏移0,0依然有效,因爲未修改過。通過VIDIOC_CROPCAP給出的默認裁剪矩形區域,應用程序可以輕鬆的修改此區域中心。

現在,應用程序可以使用像素縱橫比接近原始請求的圖片來覆蓋區域,所以它請求裁剪608 x 456像素的矩形區域。當前縮放係數限制裁剪只能到640 x 384,所以驅動返回608 x 384的裁剪尺寸,並且調整圖片尺寸爲最接近的304 x 192。


示例

源和目標矩形區域在關閉和重打開一個設備時應保持不變,以至於穿梭與設備的管道數據不需要特別的準備。高級的應用程序會在開始IO操作前確認參數是否合適。

例1.10 重置裁剪參數
假設一個視頻捕捉設備,爲其他設備修改V4L2_BUF_TYPE_VIDEO_CAPTURE。

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.11 簡單縮放

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);
}

例1.12 選擇輸出區域

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.13 當前縮放係數與像素縱橫比

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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章