1. 程式人生 > >V4L2採集YUYV資料—X264編碼H264視訊例項

V4L2採集YUYV資料—X264編碼H264視訊例項

    前幾天在網上買個羅技的C270攝像頭,它支援YUYV(YUV422)和JPEG資料輸出。它規格書上寫的是支援HD720P(1280*720畫素),在實際的除錯過程中,我使用該解析度會導致資料採集過慢。這裡需要注意一下,羅技的攝像頭C270在有些虛擬機器上使用是有異常的,有些是不能對映到虛擬機器上,有些是對映過去操作非常緩慢。因為之前在自己的開發板上除錯過YUV420的攝像頭,在此基礎上改為YUYV資料格式,除錯的時候還是遇到不少的問題。

在PC上編譯X264,可以直接執行下面三條命令:

./configure --enable-shared
make
make install

下面貼出x264部分的程式碼:

/*=============================================================================
#     FileName: h264encoder.c
#         Desc: this program aim to get image from USB camera,
#               used the V4L2 interface.
#       Author: licaibiao
#      Version: 
#   LastChange: 2017-02-21 
=============================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "./include/h264encoder.h"

int WIDTH = 640;
int HEIGHT = 480;

void compress_begin(Encoder *en, int width, int height) {
	en->param = (x264_param_t *) malloc(sizeof(x264_param_t));
	en->picture = (x264_picture_t *) malloc(sizeof(x264_picture_t));
	x264_param_default(en->param); //set default param
	//en->param->rc.i_rc_method = X264_RC_CQP;
	// en->param->i_log_level = X264_LOG_NONE;

	en->param->i_threads  = X264_SYNC_LOOKAHEAD_AUTO;
	en->param->i_width = width; //set frame width
	en->param->i_height = height; //set frame height
	WIDTH = width;
	HEIGHT = height;

	//en->param->i_frame_total = 0;

	//en->param->i_keyint_max = 10;
	en->param->rc.i_lookahead = 0; 
	//en->param->i_bframe = 5; 

	//en->param->b_open_gop = 0;
	//en->param->i_bframe_pyramid = 0;
	//en->param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;

	//en->param->rc.i_bitrate = 1024 * 10;//rate 10 kbps
	en->param->i_fps_num = 30; 
	en->param->i_fps_den = 1;
	en->param->i_csp = X264_CSP_I422;

	x264_param_apply_profile(en->param, x264_profile_names[4]); 

	if ((en->handle = x264_encoder_open(en->param)) == 0) {
		return;
	}
	/* Create a new pic */
	x264_picture_alloc(en->picture, X264_CSP_I422, en->param->i_width,
			en->param->i_height);
}

int compress_frame(Encoder *en, int type, uint8_t *in, uint8_t *out) {
	x264_picture_t pic_out;
	int index_y, index_u, index_v;
	int num;
	int nNal = -1;
	int result = 0;
	int i = 0;
	static long int pts = 0;
	uint8_t *p_out = out;
	char *y = en->picture->img.plane[0];   
	char *u = en->picture->img.plane[1];   
	char *v = en->picture->img.plane[2];   
	char * ptr;

	index_y = 0;
        index_u = 0;
        index_v = 0;

        num = WIDTH * HEIGHT * 2 - 4  ;

        for(i=0; i<num; i=i+4)
        {
                *(y + (index_y++)) = *(in + i);
                *(u + (index_u++)) = *(in + i + 1);
                *(y + (index_y++)) = *(in + i + 2);
                *(v + (index_v++)) = *(in + i + 3);
        }

	switch (type) {
	case 0:
		en->picture->i_type = X264_TYPE_P;
		break;
	case 1:
		en->picture->i_type = X264_TYPE_IDR;
		break;
	case 2:
		en->picture->i_type = X264_TYPE_I;
		break;
	default:
		en->picture->i_type = X264_TYPE_AUTO;
		break;
	}

	en->picture->i_pts = pts++;

	if (x264_encoder_encode(en->handle, &(en->nal), &nNal, en->picture,
			&pic_out) < 0) {
		return -1;
	}

	for (i = 0; i < nNal; i++) {
		memcpy(p_out, en->nal[i].p_payload, en->nal[i].i_payload);   
		p_out += en->nal[i].i_payload;								 
		result += en->nal[i].i_payload;
	}

	return result;
}

void compress_end(Encoder *en) {
	if (en->handle) {
		x264_encoder_close(en->handle);
	}
	if (en->picture) {
		x264_picture_clean(en->picture);
		free(en->picture);
		en->picture = 0;
	}
	if (en->param) {
		free(en->param);
		en->param = 0;
	}
}

上面的程式碼是配置x264編碼器的,有下面幾個地方需要特別注意:

(1)CSP引數的配置

en->param->i_csp = X264_CSP_I422;
在X264中預設的i_csp值是3,也就是X264_CSP_NV12 的值,如果採用YUYV(422)輸入格式,這個值一定需要重新設定,不然會出現錯誤提示:x264 [error]: Invalid input colorspace 。這是因為在x264核心中他會把輸入格式裝換為下面三種中的一種:X264_CSP_NV12,X264_CSP_NV16,X264_CSP_I444.轉換如下:
static int x264_frame_internal_csp( int external_csp )
{
    switch( external_csp & X264_CSP_MASK )
    {
        case X264_CSP_NV12:
        case X264_CSP_NV21:
        case X264_CSP_I420:
        case X264_CSP_YV12:
            return X264_CSP_NV12;
        case X264_CSP_NV16:
        case X264_CSP_I422:
        case X264_CSP_YV16:
        case X264_CSP_V210:
            return X264_CSP_NV16;
        case X264_CSP_I444:
        case X264_CSP_YV24:
        case X264_CSP_BGR:
        case X264_CSP_BGRA:
        case X264_CSP_RGB:
            return X264_CSP_I444;
        default:
            return X264_CSP_NONE;
    }
}
(2)profile型別設定
x264_param_apply_profile(en->param, x264_profile_names[4]); 
在YUV422中,它不支援baseline,預設設定會提示:x264 [error]: baseline profile doesn't support 4:2:2 可以設定下面的其他引數:
x264_profile_names[] = { "baseline", "main", "high", "high10", "high422", "high444", 0 };

(3)圖片記憶體分配

x264_picture_alloc(en->picture, X264_CSP_I422, en->param->i_width,
			en->param->i_height);
這裡的第二個引數一定要與你的輸入格式先對應,不然的話會出現記憶體溢位的錯誤。因為預設的分配圖片記憶體大小是YUV420的。以640*480 解析度來舉例,YUV420 分配一幀影象的記憶體是450K,而我們YUV422的資料量是600K。

(4)Y,U,V 資料需要分離
for(i=0; i<num; i=i+4)
        {
                *(y + (index_y++)) = *(in + i);
                *(u + (index_u++)) = *(in + i + 1);
                *(y + (index_y++)) = *(in + i + 2);
                *(v + (index_v++)) = *(in + i + 3);
        }
    YUYV的資料是交錯儲存的,因此需要把他們分離出來單獨儲存,如果這裡不做處理,影象就會出現異常。

(5)i_pts 引數需要遞增

en->picture->i_pts = pts++;
    i_pts = pts的引數是需要遞增的,不讓回出現警告:x264 [warning]: non-strictly-monotonic PTS

    完整的編譯執行結果如下:

[[email protected] test]# ls
h264encoder.c  include  lib  main.c  Makefile  out
[[email protected] test]# make
gcc -g    -c -o main.o main.c
gcc -g    -c -o h264encoder.o h264encoder.c
gcc -g -o x264_test main.o  h264encoder.o -lpthread -lx264 -lm
[[email protected] test]# ls
h264encoder.c  h264encoder.o  include  lib  main.c  main.o  Makefile  out  x264_test
[[email protected] test]# ./x264_test 

camera driver name is : uvcvideo
camera device name is : UVC Camera (046d:0825)
camera bus information: usb-0000:00:1a.0-1.1
n_buffer = 4
x264 [warning]: lookaheadless mb-tree requires intra refresh or infinite keyint
x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
x264 [info]: profile High 4:2:2, level 3.0, 4:2:2 8-bit
spend time 85.082031 s
x264 [info]: frame I:8     Avg QP:20.27  size: 21592
x264 [info]: frame P:503   Avg QP:21.18  size:  3119
x264 [info]: frame B:1485  Avg QP:22.03  size:   952
x264 [info]: consecutive B-frames:  0.8%  0.0%  0.0% 99.2%
x264 [info]: mb I  I16..4: 11.9% 55.2% 32.9%
x264 [info]: mb P  I16..4:  0.4%  0.2%  0.1%  P16..4: 44.8%  7.9%  8.5%  0.0%  0.0%    skip:38.2%
x264 [info]: mb B  I16..4:  0.0%  0.0%  0.0%  B16..8: 25.9%  0.6%  0.1%  direct: 1.7%  skip:71.7%  L0:51.6% L1:47.0% BI: 1.4%
x264 [info]: 8x8 transform intra:46.7% inter:95.7%
x264 [info]: coded y,uvDC,uvAC intra: 60.5% 87.6% 59.7% inter: 5.7% 23.2% 0.9%
x264 [info]: i16 v,h,dc,p:  4%  8%  1% 87%
x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 16% 39% 12%  3%  5%  4% 10%  4%  7%
x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 24% 41%  8%  3%  4%  3%  8%  3%  4%
x264 [info]: i8c dc,h,v,p: 50% 22% 21%  6%
x264 [info]: Weighted P-Frames: Y:0.2% UV:0.0%
x264 [info]: ref P L0: 40.2%  4.8% 39.3% 15.7%
x264 [info]: ref B L0: 65.6% 20.4% 14.0%
x264 [info]: ref B L1: 91.2%  8.8%
x264 [info]: kb/s:379.47
 [[email protected] test]# 
    這裡設定的解析度是640*480 ,這樣採集資料比較快。我編碼2000幀資料需要的是大約85s,幀率大約在23fps 。也不知道具體是什麼原因導致耗時這麼長時間。

視訊執行如下:




相關推薦

V4L2採集YUYV資料X264編碼H264視訊例項

    前幾天在網上買個羅技的C270攝像頭,它支援YUYV(YUV422)和JPEG資料輸出。它規格書上寫的是支援HD720P(1280*720畫素),在實際的除錯過程中,我使用該解析度會導致資料採集過慢。這裡需要注意一下,羅技的攝像頭C270在有些虛擬機器上使用是有異常的

YUYV資料X264編碼H264視訊例項

x264庫的編譯可以見之前部落格:http://blog.csdn.net/li_wen01/article/details/53571929 在PC上編譯X264,可以直接執行下面三條命令: ./configure --enable-shared make make install

android編碼h264(一):使用x264編碼yuv為h264資料的例子(軟編碼

先說下簡單流程:  1.camera回撥nv21 yuv;  2.nv21轉yuv420;  3.x264編碼h264,回調回java層;  4.寫檔案,生成.h264檔案;  5.使用vlc等播放器播放。 android java層的程式碼比較簡單,簡單說下: 這個de

V4L2視訊採集與H.264編碼原始碼大放送:Linux視訊採集編碼(三)

這幾天的努力也算沒有白費,現在我將貢獻出我的成果,當然程式碼很大一部分都不是我寫的。 V4L2視訊採集我參考了V4L2官方原始碼,H.264編碼我使用了開源編碼庫x264,並參考了網上的一些例子。 但

使用ffmpeg將BMP圖片編碼x264視訊檔案,將H264視訊儲存為BMP圖片,yuv視訊檔案儲存為圖片的程式碼

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #ifdef __cplusplus extern "C" { #endif #include

基於iOS的網路音視訊實時傳輸系統(三)- VideoToolbox編碼視訊資料H264、AAC

server端 -- 編碼音視訊資料為H264、AAC 這部分花了好多時間,本身就不具備這方面的相關知識,查閱了不少資料,不過關於VideoToolbox和AudioToolbox方面的編碼資料寥寥無幾,雖然網上搜索結果看似特別多,其實一看 內容也大同小異,建議還是看看官方

FFmpeg 4.0.2編碼YUV序列為H264視訊檔案

/****************************** 功能:編碼YUV序列為h264視訊檔案 FFmpeg:4.0.2 ******************************/ #include <iostream> extern "C" { #include &

android平臺下基於ffmpeg採集Camera資料編碼成H.264推流到RTMP伺服器

音視訊實踐學習 android全平臺編譯ffmpeg以及x264與fdk-aac實踐 ubuntu下使用nginx和nginx-rtmp-module配置直播推流伺服器 android全平臺編譯ffmpeg合併為單個庫實踐 android-studio使用c

V4L2採集+編碼壓縮(M-JPEG和H.264壓縮效能比較)

Linux下,一般的普通USB攝像頭V4L2視訊採集有兩種方式:V4L2_PIX_FMT_MJPEG和V4L2_PIX_FMT_YUYV。 V4L2_PIX_FMT_MJPEG採集方式得到的是經過M

H264視訊編碼成MP4檔案

        最近需要將H264視訊編碼成MP4格式。研究了一下,一種方法是採用ffmpeg庫,可以先將H264檔案解碼,再編碼生成MP4檔案,但這種方式效率較低,10M的視訊可能需要幾秒鐘才能完成。另一種方式根據MP4檔案協議直接將H264包封裝成MP4格式,由於是直接

深入淺出理解視訊編碼H264結構

編碼流程: 那麼 H.264 其編解碼流程是怎麼樣的呢?其實可以主要分為 5 部分: 幀間和幀內預測(Estimation)、變換(Transform)和反變換、量化(Quantization)和反量化、環路濾波(Loop Filter)、熵編碼(Entropy Coding)。 看起來很高深的樣子,實際上

如何從H264原始資料SPS裡面得到視訊的長寬

有這樣一種需求,給你一個h264原始資料檔案,讓你直接播放出來,如何實現? 思路是這樣的,H264原始資料格式都是 0x00000001後面跟0x67 0x68 0x65 0x41這樣的資料,解碼需要一個完整的NAL資料單元,我們需要將每個0x00000001以及下一個0x

android下將v4l2採集的yuv資料轉成jpg圖片

int write_JPEG_file (constchar* filename,unsignedchar* yuvData,int quality,int image_width,int image_height) { LOG("write_JPEG_file 1 \n"); struct jpeg_

YUV資料編碼H264

自己使用ffmpeg進行編碼,在網上搜索到了雷霄驊大神,他的部落格內幾乎全是關於ffmpeg的,內容很全面,不過ffmpeg更新很快,他部落格上的有些程式碼,不太適合了。 但是,他提供了更新後的程式碼,自己使用的是如下的程式碼例子,地址在最後面。 檔案中有兩個例子,我都實驗

H264視訊編碼的基本瞭解

參考:https://www.axis.com/files/whitepaper/wp_h264_34203_cn_0901_lo.pdf 因為視訊是有圖片不斷切換產生的,現在一張圖片都有幾兆,這樣一次傳輸一張完整圖片的成本太大,會產生大量的流量。因此會出現壓縮編碼的需求。

Android視訊編碼--H264編碼

Android視訊編碼–H264編碼 Android中的H264編碼有兩種編碼方式: 硬編碼 軟編碼 1.硬編碼 Android中的H264硬編碼主要是通過自身提供的API,呼叫底層的硬體模組實現編碼,不使用CPU。 採用硬編碼的核心示例程式

基於RTP的H264視訊資料打包解包類

      最近考慮使用RTP替換原有的高清視訊傳輸協議,遂上網查詢有關H264視訊RTP打包、解包的文件和程式碼。功夫不負有心人,找到不少有價值的文件和程式碼。參考這些資料,寫了H264 RTP打包類、解包類,實現了單個NAL單元包和FU_A分片單元包。對於丟包處理,採用簡

RTMP資料流提取RTMP視訊流組成H264視訊檔案

首先我們獲得h264的流,在監聽裡,我們通過引數可以獲得RTMP包 IStreamPacket,呼叫getData()方法直接獲得包資料 放入IOBuffer。以下是提取並修改資料存成h264檔案的步驟 1. 新增監聽 IStreamListener 2. 通過IOBu

android硬編碼h264資料,並使用rtp推送資料流,實現一個簡單的直播-MediaCodec(一)

  寫在前面:我並非專業做流媒體的coder,對流媒體行業無比崇拜,只是做了幾年安卓車載ROM,對安卓AV開發算是略懂。本篇部落格是我對MediaCodec編解碼和rtp推流的一次嘗試,希望能給有需要的朋友一些細微的幫助,不喜勿噴,如果有不對的地方希望大神指正共

使用 ffmpeg 進行網路推流:拉流->解封裝->解碼->處理原始資料(音訊、視訊)->編碼->編碼->推流

簡要說明: 1、可拉流:rtmp、rtsp、http 2、可推流: #include "stdafx.h" extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #