国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

項目之利用 V4L2應用程序框架 進行視頻錄制

這篇具有很好參考價值的文章主要介紹了項目之利用 V4L2應用程序框架 進行視頻錄制。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

知識儲備:

視頻采集方式:

處理采集數(shù)據(jù):

相關結構體:

對于設備的操作步驟:


????????V4L2較V4L有較大的改動,并已成為2.6的標準接口,函蓋video\dvb\FM...,多數(shù)驅動都在向V4l2遷移。更好地了解V4L2先從應用入手,然后再深入到內核中結合物理設備/接口的規(guī)范實現(xiàn)相應的驅動。本文先就V4L2在視頻捕捉或camera方面的應用框架。
????????V4L2采用流水線的方式,操作更簡單直觀,基本遵循打開視頻設備、設置格式、處理數(shù)據(jù)、關閉設備,更多的具體操作通過ioctl函數(shù)來實現(xiàn)。

知識儲備:

?V4L2視頻編程本質:IO操作

攝像頭相關頭文件:/usr/include/linux/videodev2.h

設備文件不能被用戶創(chuàng)建,用戶也不能直接訪問內核的代碼和數(shù)據(jù)

=====================================================================

V4L2使用V4L2_MEMORY_USERPTR和V4L2_MEMORY_MMAP的區(qū)別:
視頻應用可以通過兩種方式從V4L2驅動申請buffer
1. USERPTR, 顧名思義是用戶空間指針的意思,應用層負責分配需要的內存空間,然后以指針的形式傳遞給V4L2驅動層,V4L2驅動會把capture的內容保存到指針所指的空間(層級切換,會慢不少)
一般來說,應用層需要確保這個內存空間物理上是連續(xù)的(IPU處理單元的需求),在android系統(tǒng)可以通過PMEM驅動來分配大塊的連續(xù)物理內存。應用層在不需要的時候要負責釋放申請的PMEM內存。
2. MMAP方式,內存映射模式,應用調用VIDIOC_REQBUFS ioctl分配設備buffers,參數(shù)標識需要的數(shù)目和類型。這個ioctl也可以用來改變buffers的數(shù)據(jù)以及釋放分配的內存,當然這個內存空間一般也是連續(xù)的。在應用空間能夠訪問這些物理地址之前,必須調用mmap函數(shù)把這些物理空間映射為用戶虛擬地址空間。
虛擬地址空間是通過munmap函數(shù)釋放的; 而物理內存的釋放是通過VIDIOC_REQBUFS來實現(xiàn)的(設置參數(shù)buf count為(0)),物理內存的釋放是實現(xiàn)特定的,mx51 v4l2是在關閉設備時進行釋放的。
所以二者都是申請連續(xù)的物理內存,只是申請和釋放的方式不同

V4L2使用V4L2_MEMORY_USERPTR和V4L2_MEMORY_MMAP的區(qū)別 - Lxk- - 博客園

====================================================================

視頻采集方式:

?操作系統(tǒng)一般把系統(tǒng)使用的內存劃分成用戶空間和內核空間,分別由應用程序管理和操作系統(tǒng)管理。應用程序可以直接訪問內存的地址,而內核空間存放的是供內核訪問的代碼和數(shù)據(jù),用戶不能直接訪問。v4l2捕獲的數(shù)據(jù),最初是存放在內核空間的,這意味著用戶不能直接訪問該段內存,必須通過某些手段來轉換地址。

?一共有三種視頻采集方式:使用read、write方式;內存映射方式和用戶指針模式。

read、write方式,在用戶空間和內核空間不斷拷貝數(shù)據(jù),占用了大量用戶內存空間,效率不高。

內存映射方式:把設備里的內存映射到應用程序中的內存控件,直接處理設備內存,這是一種有效的方式。上面的mmap函數(shù)就是使用這種方式。

用戶指針模式:內存片段由應用程序自己分配。這點需要在v4l2_requestbuffers里將memory字段設置成V4L2_MEMORY_USERPTR。??

====================================================================

處理采集數(shù)據(jù):

V4L2有一個數(shù)據(jù)緩存,存放req.count數(shù)量的緩存數(shù)據(jù)。數(shù)據(jù)緩存采用FIFO的方式,當應用程序調用緩存數(shù)據(jù)時,緩存隊列將最先采集到的視頻數(shù)據(jù)緩存送出,并重新采集一張視頻數(shù)據(jù)。這個過程需要用到兩個ioctl命令,VIDIOC_DQBUFVIDIOC_QBUF.

====================================================================

相關結構體:

struct v4l2_fmtdesc結構體:用于獲取攝像頭支持的視頻格式

  • struct v4l2_fmtdesc {
  • ?????__u32?????????? index;???????????? /* Format number編號*/
  • ?????__u32?????????? type;????????????? /* enum v4l2_buf_type */
  • ?????__u32?????????????? flags;
  • ?????__u8??????????? description[32];?? /* Description string */
  • ?????__u32?????????? pixelformat;?????? /* Format fourcc????? */
  • ?????__u32?????????? reserved[4];

?};

struct v4l2_format結構體:用于設置當前攝像頭的采集格式和大小
struct v4l2_format{
??? enum v4l2_buf_type type;?// 數(shù)據(jù)流類型,固定V4L2_BUF_TYPE_VIDEO_CAPTURE
??? union
??? {
??????? struct v4l2_pix_format??? pix;?
??????? struct v4l2_window??????? win;?
??????? struct v4l2_vbi_format??? vbi;?
??????? __u8?? ?raw_data[200];?????????
??? } fmt;
};

struct v4l2_pix_format結構體:是struct v4l2_format結構體的子結構體

struct v4l2_pix_format{
???
__u32?????????????????? width;??????? // 寬,必須是16的倍數(shù)
??? __u32?????????????????? height;?????? // 高,必須是16的倍數(shù)
??? __u32?????????????????? pixelformat;? // 視頻數(shù)據(jù)存儲類型,例如是YUV4:2:2還是RGB
??? enum v4l2_field???????? field;????????/* enum v4l2_field */
??? __u32?????????????????? bytesperline;? //對于填充,如果未使用,則為0
??? __u32?????????????????? sizeimage;
???
enum v4l2_colorspace??? colorspace;?/* enum v4l2_colorspace */
??? __u32?????????????????? priv;?? //私有數(shù)據(jù),依賴于pixelformat???
};

struct v4l2_requestbuffers結構體:用于在內核分配空間

struct v4l2_requestbuffers{

????????__u32?????????????? count;? // 緩存數(shù)量,也就是說在緩存隊列里保持多少張照片 ???

????????enum v4l2_buf_type? type;?// 數(shù)據(jù)流類型,固定V4L2_BUF_TYPE_VIDEO_CAPTURE?

????????enum v4l2_memory??memory; // V4L2_MEMORY_MMAP(內存映射方式)或?V4L2_MEMORY_USERPTR(用戶空間指針方式)??

????????__u32?????????????? reserved[2];

};

=====================================================================

int ioctl(int fd,unsigned long int request,...);

常用的命令標志符:

  • VIDIOC_REQBUFS:分配內存
  • VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的數(shù)據(jù)緩存轉換成物理地址
  • VIDIOC_QUERYCAP:查詢驅動功能
  • VIDIOC_ENUM_FMT:獲取當前驅動支持的視頻格式
  • VIDIOC_S_FMT:設置當前驅動的頻捕獲格式
  • VIDIOC_G_FMT:讀取當前驅動的頻捕獲格式
  • VIDIOC_TRY_FMT:驗證當前驅動的顯示格式
  • VIDIOC_CROPCAP:查詢驅動的修剪能力
  • VIDIOC_S_CROP:設置視頻信號的邊框
  • VIDIOC_G_CROP:讀取視頻信號的邊框
  • VIDIOC_QBUF:把數(shù)據(jù)從緩存中讀取出來
  • VIDIOC_DQBUF:把數(shù)據(jù)放回緩存隊列
  • VIDIOC_STREAMON:開始視頻顯示函數(shù)
  • VIDIOC_STREAMOFF:結束視頻顯示函數(shù)
  • VIDIOC_QUERYSTD:檢查當前視頻設備支持的標準,例如PAL或NTSC。

====================================================================

對于設備的操作步驟:


打開設備(阻塞或者非阻塞,驅動會將緩存(DQBUFF)里的東西返回給應用程序)

獲取設備支持的視頻格式(亞洲一般使用PAL(720*576)制式攝像頭、歐洲NTSC(720*480)制式攝像頭,使用VIDIOC_QUERYSTD來檢測)

根據(jù)獲得的視頻格式,設置當前攝像頭的采集格式和大小(liunx編程中ioctl函數(shù))

設置視頻捕獲格式(設置fmt.fmt.pix.pixelformat為YUYV還是V4L2_PIX_FMT_MJPEG)

在內核分配內存空間(設置緩存數(shù)量(count)和存儲模式(內存映射、用戶空間指針))

獲取并記錄緩存的物理空間(使用VIDIOC_REQBUFS,獲取count個緩存數(shù)量,其次調用VIDIOC_QUERYBUF獲取這些緩存的地址,然后使用mmap函數(shù)轉換成應用程序中的絕對地址,最后把這段緩存放入緩存隊列(這是用到內存映射、優(yōu)勢是不用頻繁轉換到用戶或者內核層,更快速))

視頻采集(選擇read、write方式,內存映射方式,用戶指針模式? 這3種模式之一)

⑧處理采集數(shù)據(jù)(V4L2的數(shù)據(jù)緩存采用FIFO方式,將采集到的視頻數(shù)據(jù)緩存送出后再重新采集一張視頻數(shù)據(jù),需要用到VIDIOC_DQBUFVIDIOC_QBUF)

關閉視頻設備(close、fclose或者mmap(使用mmap后還需使用munmap方法))

#include <stdio.h>
#include <linux/videodev2.h>    //攝像頭相關的頭文件
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h> 
#include <sys/mman.h>
#include <stdlib.h>
//定義用戶緩沖區(qū),定義一個結構體、用來存儲 內核空間映射之后的首地址和空間大小
typedef struct VideoBuffer{
    void *start;
    size_t length;
}VideoBuffer;
//定義結構體數(shù)組,用來代表一個數(shù)組元素映射的緩沖區(qū)
struct VideoBuffer buffers[8];
//calloc:在堆區(qū)開辟8個sizeof(*buffers)這么大的連續(xù)空間
//VideoBuffer *buffers = calloc(fmt3.count,sizeof(*buffers));
//定義一個全局緩沖區(qū)
struct v4l2_buffer buf;
int camera_init(const char *dev,int *ismjpeg)
{
    //1、以阻塞模式打開攝像頭
    int fd = open(dev,O_RDWR,0);
    if(fd < 0){
        perror("open_error");
        return -1;
    }
    //2、獲取攝像頭支持的視頻格式 
    char fmtBuf[32] = {0};
    struct v4l2_fmtdesc fmt1;
    memset(&fmt1,0,sizeof(fmt1));
    fmt1.index = 0;
    //V4L2_BUF_TYPE_VBI_CAPTURE:數(shù)據(jù)流類型,固定一直都是
    fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    //VIDIOC_ENUM_FMT:獲取當前驅動的頻捕獲格式
    while( ioctl(fd,VIDIOC_ENUM_FMT,&fmt1) != -1){
        printf("fmt1.index:%d\n",fmt1.index++);
        printf("format:%s\n",fmt1.description);
        strcat(fmtBuf,fmt1.description);
    }
    //3、根據(jù)獲得的視頻格式,設置當前攝像頭的采集格式和大小
    struct v4l2_format fmt2;
    fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt2.fmt.pix.width = 640;
    fmt2.fmt.pix.height = 480;
    //設置視頻捕獲格式為JPG
    if(strstr(fmtBuf,"JPEG")!=NULL){
        fmt2.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
        *ismjpeg = 1;
    }
    else{
        //如果是YUYV的視頻格式,后續(xù)還需要轉碼, YUYV->RGB24->JPEG
        fmt2.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
        *ismjpeg = 0;
    }
    if( ioctl(fd,VIDIOC_S_FMT,&fmt2)==-1 ){
        perror("set fmt");
        return -1;
    }
    //4、在內核分配內存空間
    struct v4l2_requestbuffers fmt3;
    fmt3.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    //設置緩存隊列里保持8張照片
    fmt3.count = 8;
    fmt3.memory = V4L2_MEMORY_MMAP;
    //VIDIOC_REQBUFS:分配內存
    if(ioctl(fd,VIDIOC_REQBUFS,&fmt3)==-1){
        perror("req fmt");
        return -1;
    }
    //5、獲取并記錄緩存的物理空間 
//    struct v4l2_buffer buf;
    for(int i=0;i<fmt3.count;++i){
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        //讀取內核中的某個index編號的緩沖區(qū)
        if( ioctl(fd,VIDIOC_QUERYBUF,&buf)==-1 ){
            perror("VIDIOC_QUERYBUF");
            return -1;
        }
        //將內核中讀取的緩存映射到 用戶空間 
        buffers[i].length = buf.length; //先保存編號為i的內核空間的大小到用戶空間
        //內存映射
        buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,MAP_SHARED,fd, buf.m.offset);
		if(buffers[i].start == MAP_FAILED){	//判斷是否映射失敗
			perror("mmap");
			return -1;
		}
		//將讀取出來的緩存重新放入緩存隊列
		if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
			perror("mmap qbuf");
			return -1;
		}
    }
    return fd;
}
int camera_start(int fd)
{
	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	//開始視頻采集,必須指定攝像頭拍攝的圖片存儲的緩存區(qū)的數(shù)據(jù)類型
	if(ioctl(fd,VIDIOC_STREAMON,&type)==-1 ){
		perror("start no");
		return -1;
	}
	return 0;
}
int camera_eqbuf(int fd,void **jpeg,int *size,int *index)
{
//	struct v4l2_buffer buf;//局部放不回去,設置為全局的
	memset(&buf,0,sizeof(buf));
	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	buf.memory = V4L2_MEMORY_MMAP;
	buf.index = 0;	//指定要出隊的 內核緩存編號

	//將編號為 0 的內核緩存出隊,緩存數(shù)據(jù)映射到了 用戶緩存區(qū)buffers	
	//如果內核緩存沒有圖片數(shù)據(jù),那么出隊將會永久阻塞,為了防止永久阻塞,建議使用IO多路復用來出隊
	if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1){
		perror("DQBUF");
		return -1;
	}
	//由于緩存中的數(shù)據(jù)都已經映射到了 用戶空間,因此可以將 用戶緩存中的數(shù)據(jù) 讀取出來
	//*size = buf[0].length;
	*size = buf.bytesused;		//保存一張圖片的實際大小
	*jpeg = buffers[0].start;	//保存一張圖片數(shù)據(jù)的首地址
	*index = buf.index;			//保存當前圖片緩存的索引

    return 0;
}
int camera_ebuf(int fd,int index)
{
	buf.index = index;
	if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
		perror("qbuf");
		return -1;
	}
	return 0;
}
int camera_stop(int fd)
{
	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	//開始視頻采集,必須指定攝像頭拍攝的圖片存儲的緩存區(qū)的數(shù)據(jù)類型
	if(ioctl(fd,VIDIOC_STREAMON,&type)==-1 ){
		perror("start no");
		return -1;
	}
	return 0;
}
int camera_quit(int fd)
{
	close(fd);
	return 0;
}
int main(int argc, char *argv[])
{ 
    int ismjpeg = 0;
	int index = -1,size;
	char *yuv,*jpeg;//野指針,取一個地址,讓野指針去存儲圖片首地址,會出問題
    int cameraFd = camera_init("/dev/video0",&ismjpeg);
    if(cameraFd<0){
        return -1;
    }
	if( camera_start(cameraFd)==-1 ){
		return -1;
	}
	if(ismjpeg == 1){
		printf("capture format:MJPEG\n");
		jpeg = (char *)malloc(640*480);
	}else{
		printf("capture format:YUYV\n");
	}
    for(int i=0;i<8;i++){
		//出隊,得到一張圖片的 首地址和大小,以及該圖片的 索引編號
		if(camera_eqbuf(cameraFd,(void **)&yuv,&size,&index)==-1){
			break;
        }
        //入隊 
        if(camera_ebuf(cameraFd,index)==-1 ){
            break;
        }
     }
	while(1){	
		//出隊,得到一張圖片的 首地址和大小,以及該圖片的 索引編號
		if(camera_eqbuf(cameraFd,(void **)&yuv,&size,&index)==-1){
			break;
		}
        printf("size:%d\n",size);
        memset(jpeg,0,sizeof(jpeg));
        memcpy(jpeg,yuv,size);
        int fd1=open("1.jpg",O_WRONLY|O_CREAT,0644);
        int count = 0;
        while(count<size){
            int ret = write(fd1,jpeg+count,size-count);
            if(ret<size){
                printf("----數(shù)據(jù)太少----\n");
            }
            count += ret;
        }
        close(fd1);
        usleep(5000);
        //入隊 
        if(camera_ebuf(cameraFd,index)==-1 ){
            break;
        }
	}
    camera_stop(cameraFd);
    camera_quit(cameraFd);
    return 0;
} 

視頻格式如果是YUYV,則需要轉碼:YUYV=>RGB24=>JPEG文章來源地址http://www.zghlxwxcb.cn/news/detail-407664.html

#include "convert.h"

#define ROUND_0_255(v)	((v) < 0 ? 0 : ((v) > 255 ? 255 : (v)))

typedef struct {
	struct jpeg_destination_mgr pub;
	JOCTET *buffer;
	unsigned char *outbuffer;
	int outbuffer_size;
	unsigned char *outbuffer_cursor;
	int *written;
} jpeg_dest_mgr, *jpeg_dest_mgr_ptr;

struct jpeg_mgr_info {
	unsigned long written;
	JSAMPROW row_pointer[1];
	struct jpeg_error_mgr jerr;
	struct jpeg_compress_struct cinfo;
};

static struct jpeg_mgr_info jinfo;

static short radj[] = {
	-175, -174, -172, -171, -169, -168, -167, -165, 
	-164, -163, -161, -160, -159, -157, -156, -154, 
	-153, -152, -150, -149, -148, -146, -145, -143, 
	-142, -141, -139, -138, -137, -135, -134, -132, 
	-131, -130, -128, -127, -126, -124, -123, -121, 
	-120, -119, -117, -116, -115, -113, -112, -111, 
	-109, -108, -106, -105, -104, -102, -101, -100, 
	-98,  -97,  -95,  -94,  -93,  -91,  -90,  -89, 
	-87,  -86,  -84,  -83,  -82,  -80,  -79,  -78, 
	-76,  -75,  -74,  -72,  -71,  -69,  -68,  -67, 
	-65,  -64,  -63,  -61,  -60,  -58,  -57,  -56, 
	-54,  -53,  -52,  -50,  -49,  -47,  -46,  -45, 
	-43,  -42,  -41,  -39,  -38,  -37,  -35,  -34, 
	-32,  -31,  -30,  -28,  -27,  -26,  -24,  -23, 
	-21,  -20,  -19,  -17,  -16,  -15,  -13,  -12, 
	-10,   -9,   -8,   -6,   -5,   -4,   -2,   -1, 
	0,    1,    2,    4,    5,    6,    8,    9, 
	10,   12,   13,   15,   16,   17,   19,   20, 
	21,   23,   24,   26,   27,   28,   30,   31, 
	32,   34,   35,   37,   38,   39,   41,   42, 
	43,   45,   46,   47,   49,   50,   52,   53, 
	54,   56,   57,   58,   60,   61,   63,   64, 
	65,   67,   68,   69,   71,   72,   74,   75, 
	76,   78,   79,   80,   82,   83,   84,   86, 
	87,   89,   90,   91,   93,   94,   95,   97, 
	98,  100,  101,  102,  104,  105,  106,  108, 
	109,  111,  112,  113,  115,  116,  117,  119, 
	120,  121,  123,  124,  126,  127,  128,  130, 
	131,  132,  134,  135,  137,  138,  139,  141, 
	142,  143,  145,  146,  148,  149,  150,  152, 
	153,  154,  156,  157,  159,  160,  161,  163, 
	164,  165,  167,  168,  169,  171,  172,  174,
};

static short gadj1[] = {
	-89,  -88,  -87,  -87,  -86,  -85,  -85,  -84, 
	-83,  -83,  -82,  -81,  -80,  -80,  -79,  -78, 
	-78,  -77,  -76,  -76,  -75,  -74,  -73,  -73, 
	-72,  -71,  -71,  -70,  -69,  -69,  -68,  -67, 
	-67,  -66,  -65,  -64,  -64,  -63,  -62,  -62, 
	-61,  -60,  -60,  -59,  -58,  -57,  -57,  -56, 
	-55,  -55,  -54,  -53,  -53,  -52,  -51,  -50, 
	-50,  -49,  -48,  -48,  -47,  -46,  -46,  -45, 
	-44,  -43,  -43,  -42,  -41,  -41,  -40,  -39, 
	-39,  -38,  -37,  -36,  -36,  -35,  -34,  -34, 
	-33,  -32,  -32,  -31,  -30,  -30,  -29,  -28, 
	-27,  -27,  -26,  -25,  -25,  -24,  -23,  -23, 
	-22,  -21,  -20,  -20,  -19,  -18,  -18,  -17, 
	-16,  -16,  -15,  -14,  -13,  -13,  -12,  -11, 
	-11,  -10,   -9,   -9,   -8,   -7,   -6,   -6, 
	-5,   -4,   -4,   -3,   -2,   -2,   -1,    0, 
	0,    0,    1,    2,    2,    3,    4,    4, 
	5,    6,    6,    7,    8,    9,    9,   10, 
	11,   11,   12,   13,   13,   14,   15,   16, 
	16,   17,   18,   18,   19,   20,   20,   21, 
	22,   23,   23,   24,   25,   25,   26,   27, 
	27,   28,   29,   30,   30,   31,   32,   32, 
	33,   34,   34,   35,   36,   36,   37,   38, 
	39,   39,   40,   41,   41,   42,   43,   43, 
	44,   45,   46,   46,   47,   48,   48,   49, 
	50,   50,   51,   52,   53,   53,   54,   55, 
	55,   56,   57,   57,   58,   59,   60,   60, 
	61,   62,   62,   63,   64,   64,   65,   66, 
	67,   67,   68,   69,   69,   70,   71,   71, 
	72,   73,   73,   74,   75,   76,   76,   77, 
	78,   78,   79,   80,   80,   81,   82,   83, 
	83,   84,   85,   85,   86,   87,   87,   88, 
};

static short gadj2[] = {
	-43,  -42,  -42,  -42,  -41,  -41,  -41,  -40, 
	-40,  -40,  -39,  -39,  -39,  -38,  -38,  -38, 
	-37,  -37,  -37,  -36,  -36,  -36,  -35,  -35, 
	-35,  -34,  -34,  -34,  -33,  -33,  -33,  -32, 
	-32,  -32,  -31,  -31,  -31,  -30,  -30,  -30, 
	-29,  -29,  -29,  -28,  -28,  -28,  -27,  -27, 
	-27,  -26,  -26,  -25,  -25,  -25,  -24,  -24, 
	-24,  -23,  -23,  -23,  -22,  -22,  -22,  -21, 
	-21,  -21,  -20,  -20,  -20,  -19,  -19,  -19, 
	-18,  -18,  -18,  -17,  -17,  -17,  -16,  -16, 
	-16,  -15,  -15,  -15,  -14,  -14,  -14,  -13, 
	-13,  -13,  -12,  -12,  -12,  -11,  -11,  -11, 
	-10,  -10,  -10,   -9,   -9,   -9,   -8,   -8, 
	-8,   -7,   -7,   -7,   -6,   -6,   -6,   -5, 
	-5,   -5,   -4,   -4,   -4,   -3,   -3,   -3, 
	-2,   -2,   -2,   -1,   -1,   -1,    0,    0, 
	0,    0,    0,    1,    1,    1,    2,    2, 
	2,    3,    3,    3,    4,    4,    4,    5, 
	5,    5,    6,    6,    6,    7,    7,    7, 
	8,    8,    8,    9,    9,    9,   10,   10, 
	10,   11,   11,   11,   12,   12,   12,   13, 
	13,   13,   14,   14,   14,   15,   15,   15, 
	16,   16,   16,   17,   17,   17,   18,   18, 
	18,   19,   19,   19,   20,   20,   20,   21, 
	21,   21,   22,   22,   22,   23,   23,   23, 
	24,   24,   24,   25,   25,   25,   26,   26, 
	27,   27,   27,   28,   28,   28,   29,   29, 
	29,   30,   30,   30,   31,   31,   31,   32, 
	32,   32,   33,   33,   33,   34,   34,   34, 
	35,   35,   35,   36,   36,   36,   37,   37, 
	37,   38,   38,   38,   39,   39,   39,   40, 
	40,   40,   41,   41,   41,   42,   42,   42,
};

static short badj[] = {
	-221, -220, -218, -216, -214, -213, -211, -209, 
	-207, -206, -204, -202, -200, -199, -197, -195, 
	-194, -192, -190, -188, -187, -185, -183, -181, 
	-180, -178, -176, -174, -173, -171, -169, -168, 
	-166, -164, -162, -161, -159, -157, -155, -154, 
	-152, -150, -148, -147, -145, -143, -142, -140, 
	-138, -136, -135, -133, -131, -129, -128, -126, 
	-124, -123, -121, -119, -117, -116, -114, -112, 
	-110, -109, -107, -105, -103, -102, -100,  -98, 
	-97,  -95,  -93,  -91,  -90,  -88,  -86,  -84, 
	-83,  -81,  -79,  -77,  -76,  -74,  -72,  -71, 
	-69,  -67,  -65,  -64,  -62,  -60,  -58,  -57, 
	-55,  -53,  -51,  -50,  -48,  -46,  -45,  -43, 
	-41,  -39,  -38,  -36,  -34,  -32,  -31,  -29, 
	-27,  -25,  -24,  -22,  -20,  -19,  -17,  -15, 
	-13,  -12,  -10,   -8,   -6,   -5,   -3,   -1, 
	0,    1,    3,    5,    6,    8,   10,   12, 
	13,   15,   17,   19,   20,   22,   24,   25, 
	27,   29,   31,   32,   34,   36,   38,   39, 
	41,   43,   45,   46,   48,   50,   51,   53, 
	55,   57,   58,   60,   62,   64,   65,   67, 
	69,   71,   72,   74,   76,   77,   79,   81, 
	83,   84,   86,   88,   90,   91,   93,   95, 
	97,   98,  100,  102,  103,  105,  107,  109, 
	110,  112,  114,  116,  117,  119,  121,  123, 
	124,  126,  128,  129,  131,  133,  135,  136, 
	138,  140,  142,  143,  145,  147,  148,  150, 
	152,  154,  155,  157,  159,  161,  162,  164, 
	166,  168,  169,  171,  173,  174,  176,  178, 
	180,  181,  183,  185,  187,  188,  190,  192, 
	194,  195,  197,  199,  200,  202,  204,  206, 
	207,  209,  211,  213,  214,  216,  218,  220,
};

void convert_yuv_to_rgb(void *yuv, void *rgb, unsigned int width, unsigned int height, unsigned int bps)
{
	unsigned int i;
	int y1, y2, u, v;
	unsigned char *src = yuv;
	unsigned char *dst = rgb;
	unsigned int count = width * height / 2;

	switch (bps) {
	case 24:
		for (i = 0; i < count; i++) {
			y1 = *src++;
			u  = *src++;
			y2 = *src++;
			v  = *src++;

			*dst++ = ROUND_0_255(y1 + radj[v]);
			*dst++ = ROUND_0_255(y1 - gadj1[u] - gadj2[v]);
			*dst++ = ROUND_0_255(y1 + badj[u]);

			*dst++ = ROUND_0_255(y2 + radj[v]);
			*dst++ = ROUND_0_255(y2 - gadj1[u] - gadj2[v]);
			*dst++ = ROUND_0_255(y2 + badj[u]);
		}
		break;
	}
}

void convert_rgb_to_jpg_init(void)
{
	memset(&jinfo, 0, sizeof(struct jpeg_mgr_info));
	jinfo.cinfo.err = jpeg_std_error(&jinfo.jerr);
	jpeg_create_compress(&jinfo.cinfo);
}

int convert_rgb_to_jpg_work(void *rgb, void *jpeg, unsigned int width, unsigned int height, unsigned int bpp, int quality)
{
	jinfo.written = width * height * bpp / 3;
	jpeg_mem_dest(&jinfo.cinfo, (unsigned char **)&jpeg, &jinfo.written);

	jinfo.cinfo.image_width = width;
	jinfo.cinfo.image_height = height;
	jinfo.cinfo.input_components = bpp / 8;
	jinfo.cinfo.in_color_space = JCS_RGB;
	jpeg_set_defaults(&jinfo.cinfo);
	jpeg_set_quality(&jinfo.cinfo, quality, TRUE);

	jpeg_start_compress(&jinfo.cinfo, TRUE);

	while(jinfo.cinfo.next_scanline < height) {
		jinfo.row_pointer[0] = rgb + jinfo.cinfo.next_scanline * width * bpp / 8;
		jpeg_write_scanlines(&jinfo.cinfo, jinfo.row_pointer, 1);
	}

	jpeg_finish_compress(&jinfo.cinfo);

	return (jinfo.written);
}
void convert_rgb_to_jpg_exit(void)
{
	jpeg_destroy_compress(&jinfo.cinfo);
}

到了這里,關于項目之利用 V4L2應用程序框架 進行視頻錄制的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包