v4l2,一開始聽到這個名詞的時候,以為又是一個很難很難的模塊,涉及到視頻的處理,后來在網上各種找資料后,才發現其實v4l2已經分裝好了驅動程序,只要我們根據需要調用相應的接口和函數,從而實現視頻的獲取和處理。只要認真的看幾篇文章就對v4l2有一定的了解了,由於是第一次接觸,網上的資料良莠不齊,難得可以找到幾篇自己感覺很不錯的。記錄下來:(沒必要看太多,很多都是一樣的意思)
http://www.embedu.org/Column/Column320.htm 這篇是不錯的介紹,很討厭有彈窗
http://www.cnblogs.com/emouse/archive/2013/03/04/2943243.html 這個可以作為第一篇來看,博主整理的不錯
http://blog.chinaunix.net/uid-11765716-id-2855735.html 這篇也比較詳細
http://blog.csdn.net/ddddwant/article/details/8475211 這篇提到的問題和我遇到的一樣,花屏了,內存沒有讀取好
http://my.oschina.net/u/1024767/blog/210801#OSC_h2_14 對capture.c文件的解讀
http://blog.csdn.net/g_salamander/article/details/8107692 對各個結構體有比較好的說明
一、Video for Linux two
v4l2為linux下視頻設備程序提供了一套接口規范。包括一套數據結構和底層V4L2驅動接口。只能在linux下使用。它使程序有發現設備和操作設備的能力。它主要是用一系列的回調函數來實現這些功能。像設置攝像頭的頻率、幀頻、視頻壓縮格式和圖像參數等等。當然也可以用於其他多媒體的開發,如音頻等。
在Linux下,所有外設都被看成一種特殊的文件,成為“設備文件”,可以象訪問普通文件一樣對其進行讀寫。一般來說,采用V4L2驅動的攝像頭設備文是/dev/v4l/video0。為了通用,可以建立一個到/dev/video0的鏈接。V4L2支持兩種方式來采集圖像:內存映射方式(mmap)和直接讀取方式(read)。V4L2在include/linux/videodev.h文件中定義了一些重要的數據結構,在采集圖像的過程中,就是通過對這些數據的操作來獲得最終的圖像數據。Linux系統V4L2的能力可在Linux內核編譯階段配置,默認情況下都有此開發接口。V4L2從Linux 2.5.x版本的內核中開始出現。
V4L2規范中不僅定義了通用API元素(Common API Elements),圖像的格式(Image Formats),輸入/輸出方法(Input/Output),還定義了Linux內核驅動處理視頻信息的一系列接口(Interfaces),這些接口主要有:
視頻采集接口——Video Capture Interface;
視頻輸出接口—— Video Output Interface;
視頻覆蓋/預覽接口——Video Overlay Interface;
視頻輸出覆蓋接口——Video Output Overlay Interface;
編解碼接口——Codec Interface。
二、v4l2結構體介紹
1、常用的結構體在內核目錄include/linux/videodev2.h中定義
struct v4l2_requestbuffers //申請幀緩沖,對應命令VIDIOC_REQBUFS
struct v4l2_capability //視頻設備的功能,對應命令VIDIOC_QUERYCAP
struct v4l2_input //視頻輸入信息,對應命令VIDIOC_ENUMINPUT
struct v4l2_standard //視頻的制式,比如PAL,NTSC,對應命令VIDIOC_ENUMSTD
struct v4l2_format //幀的格式,對應命令VIDIOC_G_FMT、VIDIOC_S_FMT等
struct v4l2_buffer //驅動中的一幀圖像緩存,對應命令VIDIOC_QUERYBUF
struct v4l2_crop //視頻信號矩形邊框
v4l2_std_id //視頻制式
常用結構體的內容:
struct v4l2_capability { u8 driver[16]; // 驅動名字 u8 card[32]; // 設備名字 u8 bus_info[32]; // 設備在系統中的位置 u32 version; // 驅動版本號 u32 capabilities; // 設備支持的操作 u32 reserved[4]; // 保留字段 };
其中域 capabilities 代表設備支持的操作模式,常見的值有 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING 表示是一個視頻捕捉設備並且具有數據流控制模式;另外 driver 域需要和 struct video_device 中的 name 匹配。
struct v4l2_format { enum v4l2_buf_type type; union { struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ __u8 raw_data[200]; /* user-defined */ } fmt; }; enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, ... V4L2_BUF_TYPE_PRIVATE = 0x80, }; struct v4l2_pix_format { __u32 width; __u32 height; __u32 pixelformat; enum v4l2_field field; __u32 bytesperline; /* for padding, zero if unused */ __u32 sizeimage; enum v4l2_colorspace colorspace; __u32 priv; /* private data, depends on pixelformat */ };
常見的捕獲模式為 V4L2_BUF_TYPE_VIDEO_CAPTURE 即視頻捕捉模式,在此模式下 fmt 聯合體采用域 v4l2_pix_format:其中 width 為視頻的寬、height 為視頻的高、pixelformat 為視頻數據格式(常見的值有 V4L2_PIX_FMT_YUV422P | V4L2_PIX_FMT_RGB565)、bytesperline 為一行圖像占用的字節數、sizeimage 則為圖像占用的總字節數、colorspace 指定設備的顏色空間。
struct v4l2_requestbuffers 與 VIDIOC_REQBUFS ,VIDIOC_REQBUFS 命令通過結構 v4l2_requestbuffers 請求驅動申請一片連續的內存用於緩存視頻信息:
struct v4l2_requestbuffers { __u32 count; enum v4l2_buf_type type; enum v4l2_memory memory; __u32 reserved[2]; }; enum v4l2_memory { V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR = 2, V4L2_MEMORY_OVERLAY = 3, };
count 指定根據圖像占用空間大小申請的緩存區個數,type 為視頻捕獲模式,memory 為內存區的使用方式。
struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; __u32 flags; enum v4l2_field field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence; /* memory location */ enum v4l2_memory memory; union { __u32 offset; unsigned long userptr; } m; __u32 length; __u32 input; __u32 reserved; };
index 為緩存編號
type 為視頻捕獲模式
bytesused 為緩存已使用空間大小
flags 為緩存當前狀態(常見值有 V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE,分別代表當前緩存已經映射、緩存可以采集數據、緩存可以提取數據)
timestamp 為時間戳
sequence為緩存序號
memory 為緩存使用方式
offset 為當前緩存與內存區起始地址的偏移
length 為緩存大小
reserved 一般用於傳遞物理地址值。
另外 VIDIOC_QBUF 和 VIDIOC_DQBUF 命令都采用結構 v4l2_buffer 與驅動通信:VIDIOC_QBUF 命令向驅動傳遞應用程序已經處理完的緩存,即將緩存加入空閑可捕獲視頻的隊列,傳遞的主要參數為 index;VIDIOC_DQBUF 命令向驅動獲取已經存放有視頻數據的緩存,v4l2_buffer 的各個域幾乎都會被更新,但主要的參數也是 index,應用程序會根據 index 確定可用數據的起始地址和范圍。
2、常用的IOCTL接口命令也在include/linux/videodev2.h中定義
VIDIOC_REQBUFS //分配內存
VIDIOC_QUERYBUF //把VIDIOC_REQBUFS中分配的數據緩存轉換成物理地址
VIDIOC_QUERYCAP //查詢驅動功能
VIDIOC_ENUM_FMT //獲取當前驅動支持的視頻格式
VIDIOC_S_FMT //設置當前驅動的頻捕獲格式
VIDIOC_G_FMT //讀取當前驅動的頻捕獲格式
VIDIOC_TRY_FMT //驗證當前驅動的顯示格式
VIDIOC_CROPCAP //查詢驅動的修剪能力
VIDIOC_S_CROP //設置視頻信號的矩形邊框
VIDIOC_G_CROP //讀取視頻信號的矩形邊框
VIDIOC_QBUF //把數據從緩存中讀取出來
VIDIOC_DQBUF //把數據放回緩存隊列
VIDIOC_STREAMON //開始視頻顯示函數
VIDIOC_STREAMOFF //結束視頻顯示函數
VIDIOC_QUERYSTD //檢查當前視頻設備支持的標准,例如PAL或NTSC。
三、調用v4l2的工作流程
打開設備-> 檢查和設置設備屬性-> 設置幀格式-> 設置一種輸入輸出方法(緩沖 區管理)-> 循環獲取數據-> 關閉設備。
(1)打開設備文件
打開視頻設備非常簡單,在V4L2中,視頻設備被看做一個文件。使用open函數打開這個設備:
1. 用非阻塞模式打開攝像頭設備
int cameraFd;
cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK);
2. 如果用阻塞模式打開攝像頭設備,上述代碼變為:
cameraFd = open("/dev/video0", O_RDWR);
關於阻塞模式和非阻塞模式
應用程序能夠使用阻塞模式或非阻塞模式打開視頻設備,如果使用非阻塞模式調用視頻設備,即使尚未捕獲到信息,驅動依舊會把緩存(DQBUFF)里的東西返回給應用程序。
(2)取得設備的capability
struct v4l2_capability capability;
int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability);
看看設備具有什么功能,比如是否具有視頻輸入特性。
struct v4l2_capability cap; memset(&cap, 0, sizeof(cap)); /* 獲取設備支持的操作 */ if(ioctl(dev->fd, VIDIOC_QUERYCAP, &cap) < 0){ if(EINVAL == errno){ /*EINVAL為返回的錯誤值*/ printf(stderr,"%s is no V4L2 device\n", dev->dev); return TFAIL; } else { printf(stderr,"%s is not V4L2 device,unknow error\n", dev->dev); return TFAIL; } } //獲取成功,檢查是否有視頻捕獲功能 if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){ printf(stderr, "%s is no video capture device\n",dev->dev); return TFAIL; } /* streaming I/O ioctls */ if(!(cap.capabilities & V4L2_CAP_STREAMING)){ printf(stderr, "%s does not support streaming i/o\n",dev->dev); return TFAIL; }
(3)選擇視頻輸入
struct v4l2_input input;
……初始化input
int ret = ioctl(fd, VIDIOC_QUERYCAP, &input);
一個視頻設備可以有多個視頻輸入。如果只有一路輸入,這個功能可以沒有。
VIDIOC_G_INPUT 和 VIDIOC_S_INPUT 用來查詢和選則當前的 input,一個 video 設備節點可能對應多個視頻源,比如 saf7113 可以最多支持四路 cvbs 輸入,如果上層想在四個cvbs視頻輸入間切換,那么就要調用 ioctl(fd, VIDIOC_S_INPUT, &input) 來切換。VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回當前的 video input和output的index.
struct v4l2_input { __u32 index; /* Which input * /__u8 name[32]; /* Label */ __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* Associated tuner */ v4l2_std_id std; __u32 status; __u32 reserved[4]; };
(4)檢測視頻支持的制式
v4l2_std_id std;
do {
ret = ioctl(fd, VIDIOC_QUERYSTD, &std);
} while (ret == -1 && errno == EAGAIN);
switch (std) {
case V4L2_STD_NTSC:
//……
case V4L2_STD_PAL:
//……
}
(5)設置視頻捕獲格式
v4l2_format 結構體用來設置攝像頭的視頻制式、幀格式等,在設置這個參數時應先填 好 v4l2_format 的各個域,如 type(傳輸流類型),fmt.pix.width(寬),fmt.pix.heigth(高),fmt.pix.field(采樣區域,如隔行采樣),fmt.pix.pixelformat(采樣類型,如 YUV4:2:2),然后通過 VIDIO_S_FMT 操作命令設置視頻捕捉格式。
struct v4l2_format fmt; memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = g_display_width; fmt.fmt.pix.height = g_display_height; fmt.fmt.pix.pixelformat = g_fmt; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; /* 設置設備捕獲視頻的格式 */ if(ioctl(dev->fd, VIDIOC_S_FMT, &fmt) < 0) { printf(stderr, "%s iformat not supported \n",dev->dev); close(dev->fd); return TFAIL; }
注意:如果該視頻設備驅動不支持你所設定的圖像格式,視頻驅動會重新修改struct v4l2_format結構體變量的值為該視頻設備所支持的圖像格式,所以在程序設計中,設定完所有的視頻格式后,要獲取實際的視頻格式,要重新讀取struct v4l2_format結構體變量。
(6)向驅動申請幀緩存
一般不超過5個,CAP_BUF_NUM = 4
struct v4l2_requestbuffers req; /* 申請設備的緩存區 */ memset(&req, 0, sizeof(req)); req.count = CAP_BUF_NUM; //申請一個擁有四個緩沖幀的緩沖區 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(dev->fd, VIDIOC_REQBUFS, &req) < 0) { if (EINVAL == errno) { printf(stderr, "%s does not support " "memory mapping\n", dev->dev); return TFAIL; } else { printf(stderr, "%s does not support " "memory mapping, unknow error\n", dev->dev); return TFAIL; } } if (req.count < 2) { printf(stderr, "Insufficient buffer memory on %s\n", dev->dev); return TFAIL; }
v4l2_requestbuffers結構中定義了緩存的數量,驅動會據此申請對應數量的視頻緩存。多個緩存可以用於建立FIFO,來提高視頻采集的效率。控制命令VIDIOC_REQBUFS
功能: 請求V4L2驅動分配視頻緩沖區(申請V4L2視頻驅動分配內存),V4L2是視頻設備的驅動層,位於內核空間,所以通過VIDIOC_REQBUFS控制命令字申請的內存位於內核空間,應用程序不能直接訪問,需要通過調用mmap內存映射函數把內核空間內存映射到用戶空間后,應用程序通過訪問用戶空間地址來訪問內核空間。
參數說明:參數類型為V4L2的申請緩沖區數據結構體類型struct v4l2_requestbuffers ;
返回值說明: 執行成功時,函數返回值為 0;V4L2驅動層分配好了視頻緩沖區;
(7)獲取每個緩存的信息,並mmap到用戶空間
應用程序和設備有三種交換數據的方法,直接 read/write、內存映射(memory mapping)和用戶指針。這里只討論內存映射(memory mapping)。
typedef struct VideoBuffer { //定義一個結構體來映射每個緩沖幀 void *start; size_t length; } VideoBuffer; VideoBuffer* buffers = calloc( req.count, sizeof(*buffers) ); struct v4l2_buffer buf; for (numBufs = 0; numBufs < req.count; numBufs++) {//映射所有的緩存 memset( &buf, 0, sizeof(buf) ); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = numBufs; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {//獲取到對應index的緩存信息,此處主要利用length信息及offset信息來完成后面的mmap操作。 return -1; } buffers[numBufs].length = buf.length; // 轉換成相對地址 buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (buffers[numBufs].start == MAP_FAILED) { return -1; } //addr 映射起始地址,一般為NULL ,讓內核自動選擇 //length 被映射內存塊的長度 //prot 標志映射后能否被讀寫,其值為PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONE //flags 確定此內存映射能否被其他進程共享,MAP_SHARED,MAP_PRIVATE //fd,offset, 確定被映射的內存地址 返回成功映射后的地址,不成功返回MAP_FAILED ((void*)-1) int munmap(void *addr, size_t length);// 斷開映射 //addr 為映射后的地址,length 為映射后的內存長度
(8)開始采集視頻 (在緩沖區處理好之后就可以獲得視頻了 )
在開始之前,還應當把緩沖幀放入緩沖隊列,應用程序和設備有三種交換數據的方法,直接 read/write、內存映射(memory mapping)和用戶指針。這里只討論內存映射(memory mapping)。
//把四個緩沖幀放入隊列 for (i = 0; i < CAP_BUF_NUM; i++) { memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; buf.m.offset = dev->buffer[i].offset; /* 將空閑的內存加入可捕獲視頻的隊列 */ if(ioctl(dev->fd, VIDIOC_QBUF, &buf) < 0) { printf("ERROR: VIDIOC_QBUF[%s], FUNC[%s], LINE[%d]\n", dev->dev, __FUNCTION__, __LINE__); return TFAIL; } } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* 打開設備視頻流 */ if(ioctl(dev->fd, VIDIOC_STREAMON, &type) < 0) { printf("ERROR: VIDIOC_STREAMON[%s], FUNC[%s], LINE[%d]\n", dev->dev, __FUNCTION__, __LINE__); return TFAIL; }
前期初始化完成后,只是解決了一幀視頻數據的格式和大小問題,而連續視頻幀數據的采集需要用幀緩沖區隊列的方式來解決,即要通過驅動程序在內存中申請幾個幀緩沖區來存放視頻數據。
應用程序通過API接口提供的方法(VIDIOC_REQBUFS)申請若干個視頻數據的幀緩沖區,申請幀緩沖區數量一般不低於3個,每個幀緩沖區存放一幀視頻數據,這些幀緩沖區在內核空間。
應用程序通過API接口提供的查詢方法(VIDIOC_QUERYBUF)查詢到幀緩沖區在內核空間的長度和偏移量地址。
應用程序再通過內存映射方法(mmap),將申請到的內核空間幀緩沖區的地址映射到用戶空間地址,這樣就可以直接處理幀緩沖區的數據。
(1)將幀緩沖區在視頻輸入隊列排隊,並啟動視頻采集
在驅動程序處理視頻的過程中,定義了兩個隊列:視頻采集輸入隊列(incoming queues)和視頻采集輸出隊列(outgoing queues),前者是等待驅動存放視頻數據的隊列,后者是驅動程序已經放入了視頻數據的隊列。如圖2所示。
應用程序需要將上述幀緩沖區在視頻采集輸入隊列排隊(VIDIOC_QBUF),然后可啟動視頻采集。
(2)循環往復,采集連續的視頻數據
啟動視頻采集后,驅動程序開始采集一幀數據,把采集的數據放入視頻采集輸入隊列的第一個幀緩沖區,一幀數據采集完成,也就是第一個幀緩沖區存滿一幀數據后,驅動程序將該幀緩沖區移至視頻采集輸出隊列,等待應用程序從輸出隊列取出。驅動程序接下來采集下一幀數據,放入第二個幀緩沖區,同樣幀緩沖區存滿下一幀數據后,被放入視頻采集輸出隊列。
應用程序從視頻采集輸出隊列中取出含有視頻數據的幀緩沖區,處理幀緩沖區中的視頻數據,如存儲或壓縮。
最后,應用程序將處理完數據的幀緩沖區重新放入視頻采集輸入隊列,這樣可以循環采集,如圖1所示。
(9)取出FIFO緩存中已經采樣的幀緩存
struct v4l2_buffer capture_buf; memset(&capture_buf, 0, sizeof(capture_buf)); capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; capture_buf.memory = V4L2_MEMORY_MMAP; /* 將已經捕獲好視頻的內存拉出已捕獲視頻的隊列 */ if (ioctl(dev.fd, VIDIOC_DQBUF, &capture_buf) < 0) { printf("ERROR: VIDIOC_DQBUF[%s], FUNC[%s], LINE[%d]\n", dev, __FUNCTION__, __LINE__); return TFAIL; } } image_data_handle(buffer[capture_buf.index].start, capture_buf.bytesused);
(10)將剛剛處理完的緩沖重新入隊列尾,這樣可以循環采集
if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
return -1;
}
(11)停止視頻的采集,解除映射
int ret = ioctl(fd, VIDIOC_STREAMOFF, &buf_type);
munmap(buffer[j].start, buffer[j].length);
(12)關閉視頻設備
close(fd);
最后這個是一般mmap形式的使用流程,還有使用read/write方式的內存讀寫流程,具體的可以參考官方的capture.c這個文檔,程序的流程很清楚,也有相關的博文有寫到。
文字描述版流程:
(1)打開視頻設備文件。int fd=open("/dev/video0",O_RDWR);
(2)查詢視頻設備的能力,比如是否具有視頻輸入,或者音頻輸入輸出等。ioctl(fd_v4l, VIDIOC_QUERYCAP, &cap)
(3)設置視頻采集的參數
設置視頻的制式,制式包括PAL/NTSC,使用ioctl(fd_v4l, VIDIOC_S_STD, &std_id)
設置視頻圖像的采集窗口的大小,使用ioctl(fd_v4l, VIDIOC_S_CROP, &crop)
設置視頻幀格式,包括幀的點陣格式,寬度和高度等,使用ioctl(fd_v4l, VIDIOC_S_FMT, &fmt)
設置視頻的幀率,使用ioctl(fd_v4l, VIDIOC_S_PARM, &parm)
設置視頻的旋轉方式,使用ioctl(fd_v4l, VIDIOC_S_CTRL, &ctrl)
(4)向驅動申請視頻流數據的幀緩沖區
請求/申請若干個幀緩沖區,一般為不少於3個,使用ioctl(fd_v4l, VIDIOC_REQBUFS, &req)
查詢幀緩沖區在內核空間中的長度和偏移量 ioctl(fd_v4l, VIDIOC_QUERYBUF, &buf)
(5)應用程序通過內存映射,將幀緩沖區的地址映射到用戶空間,這樣就可以直接操作采集到的幀了,而不必去復制。
buffers[i].start = mmap (NULL, buffers[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_v4l, buffers[i].offset);
(6)將申請到的幀緩沖全部放入視頻采集輸出隊列,以便存放采集的數據。ioctl (fd_v4l, VIDIOC_QBUF, &buf)
(7)開始視頻流數據的采集。 ioctl (fd_v4l, VIDIOC_STREAMON, &type)
(8) 驅動將采集到的一幀視頻數據存入輸入隊列第一個幀緩沖區,存完后將該幀緩沖區移至視頻采集輸出隊列。
(9)應用程序從視頻采集輸出隊列中取出已含有采集數據的幀緩沖區。ioctl (fd_v4l, VIDIOC_DQBUF, &buf) ,應用程序處理該幀緩沖區的原始視頻數據。
(10)處理完后,應用程序的將該幀緩沖區重新排入輸入隊列,這樣便可以循環采集數據。ioctl (fd_v4l, VIDIOC_QBUF, &buf)
重復上述步驟8到10,直到停止采集數據。
(11)停止視頻的采集。ioctl (fd_v4l, VIDIOC_STREAMOFF, &type)
(12)釋放申請的視頻幀緩沖區unmap,關閉視頻設備文件close(fd_v4l)。
以上的程序流程,包含了視頻設備采集連續的視頻數據的邏輯關系。而在實際運用中,往往還要加入對視頻數據進行處理(如壓縮編碼)的工作,否則,視頻流數據量相當大,需要很大的存儲空間和傳輸帶寬。