摄像头V4L2获取的YUY2格式转YUV420格式

摄像头取出格式YUY2(YUYV)

Y   U00Y    V00Y   U01Y    V01Y   U02Y   V02Y   U03Y   V03
YU10YV10YU11YV11YU12YV12YU13YV13
YU20YV20YU21YV21YU22YV22YU23YV23
YU30YV30YU31YV31YU32YV32YU33YV33

转为 NV12(YUV420) 

这里的转化主要是我的电脑软件pyuv 只支持yuv420格式的预览

另一方面主要是因为 ffmpeg 中进行编码时,采用的是 AV_PIX_FMT_YUV420P.

也是需要把摄像头中的YUYV转化为 ffmpeg 支持的YUV420P格式

Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  
YYYYYYYYYYYYYYYY
U00U01U02U03U20U21U22U23V00V01V02V03V20V21V22V23

这里转换主要为需要隔1整行取出1整行的UV数据,而不是间隔一个一个取。

可以看出丢失了一部分UV数据,只要Y数据没有丢失,图像会依然保持完整呈现。

转换代码:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>

#define CAM_W 640
#define CAM_H 480

typedef struct{
    char y1;
    char u;
    char y2;
    char v;
}TAG_YUY2;

static int YUYV_TO_NV12(unsigned char yuyv_in[], unsigned char* out){
    TAG_YUY2 *p_yuy2;
    int yuy2_size = CAM_W*CAM_H;
    int i = 0;
    int j = 0;
    int total = CAM_W*CAM_H*2;
    int tag_size = CAM_W*CAM_H/2;
    p_yuy2 = (TAG_YUY2 *)malloc(total);
    memcpy(p_yuy2, yuyv_in, total);
    
    i=0;
    j=0;
    int n = 0;
    for(i=0; i<tag_size; i++){
        out[j++] = p_yuy2[i].y1;
        out[j++] = p_yuy2[i].y2;
    }
    int pos = 0;
    int x = 0;
    int y = 0;
    int len_x = CAM_W/2;
    for(y = 0; y < CAM_H; y+=2){ // 每2行取一次值 u
        for(x = 0; x < len_x; x++){
            out[j++] = p_yuy2[y*len_x + x].u;
        }
    }
    for(y = 0; y < CAM_H; y+=2){ // 每2行取一次值 v
        for(x = 0; x < len_x; x++){
            out[j++] = p_yuy2[y*len_x + x].v;
        }
    }
    free(p_yuy2);
    return (CAM_W*CAM_H*3/2);
}

int main(){
    int result;
    FILE *fp_yuyv = fopen("frame.yuv", "rb");
    FILE *fp_nv21 = fopen("nv21.yuv", "wb");
    
    unsigned char* buf_yuv = (unsigned char*)malloc(CAM_W*CAM_H*2);
    unsigned char* nv21 = (unsigned char*)malloc(CAM_W*CAM_H*2);

    fread(buf_yuv, 1, CAM_W*CAM_H*2, fp_yuyv);

    memset(nv21, 0, CAM_W*CAM_H*2);
    result = YUYV_TO_NV12(buf_yuv, nv21);

    fwrite(nv21, 1, result, fp_nv21);
    
    free(buf_yuv);
    free(nv21);
    
    fclose(fp_yuyv);
    fclose(fp_nv21);
    return 0;
}

整个转换的核心是隔行采样 UV 数据, 而不是间隔1个UV单位采样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值