组织S920(I420平面)格式

时间:2016-03-21 03:27:22

标签: video webcam yuv

目前,我正在使用支持3种格式的网络摄像头,根据v4l2-ctl --list-formats

Index       : 0
Type        : Video Capture
Pixel Format: 'S920'
Name        : GSPCA SN9C20X I420

Index       : 1
Type        : Video Capture
Pixel Format: 'BA81'
Name        : 8-bit Bayer BGBG/GRGR

Index       : 2
Type        : Video Capture
Pixel Format: 'JPEG' (compressed)
Name        : JFIF JPEG

JPEG工作正常。 当我想使用I420原始数据时出现问题。 我做的是640x480。它确实返回正确的字节数。这是460800(640x480x1.5)。但经过一整天的实验,我仍然无法得到它的组织方式。

看起来它以像素块的形式返回,即128(192字节)。 如果我覆盖凸轮,我可以看到前128个(y分量)字节很小,后面跟着64个更大的字节。因此我假设它是128 y,接着是32 u和32 v。

当我覆盖网络摄像头时,这是一个示例hexdump -n 200

0000000 2b2b 2c2b 2e2b 2e2d 2b2b 2c2b 2c2b 2d2c 
0000010 2b2b 2b2b 2b2a 2c2b 2b2b 2b2c 2b2a 2b2c 
0000020 2b2a 2c2b 2b2b 2b2b 2a2a 2b2b 2b2b 2b2c 
0000030 2a2a 2c2b 2b2b 2c2b 2b2c 2c2b 2b2b 2b2b 
0000040 2d2d 2c2c 2c2c 2d2c 2c2d 2c2d 2c2d 2c2c 
0000050 2c2c 2b2b 2c2c 2c2c 2c2c 2b2c 2c2c 2c2c 
0000060 2b2b 2b2b 2b2b 2c2b 2b2c 2c2c 2b2c 2c2c 
0000070 2c2b 2c2b 2c2b 2c2b 2b2b 2c2c 2c2d 2c2b 
0000080 7a7a 7b79 7c79 7a7a 7979 797a 797a 787a
0000090 7a7a 797a 7a77 797a 797a 797a 7978 797a 
00000a0 7e7e 7d7e 7f7e 7f7f 7e7e 7e7f 7e7f 7e7f 
00000b0 7d7e 7e7d 7e7e 7e7e 7e7f 7e7e 7e7e 7e7e
00000c0 2d2c 2c2c 2d2c 2f2d  

然而,经过反复试验后,我仍然无法找到这些组件如何映射到整个640x480。 我尝试将其转换为yuy2,如下所示:

y0 u0 y1 v0 y2 u0 y3 v0,y4 u1 y5 v1 y6 u1 y7 v1

但看起来不是.. 我用谷歌搜索,但没有看到很多人使用这种格式。有没有人有使用这种yuv格式的经验?

更新: 我能得到的最接近的图像是https://drive.google.com/file/d/0Bz9G05et_k8fOS0zLUNkMXpYalU/view?usp=sharing我使用每块16x8像素,因为S920每块输出128像素(我假设,基于我看到的模式)。经过一些反复试验后,我认为16x8是最接近的。

1 个答案:

答案 0 :(得分:2)

嗯,这很有趣:-) 事实证明,GSPCA SN9C20X I42格式只是yuv420的一些变体,实际上它是yuv420,但是框架被打成了瓷砖。

我发现这个link引导我朝着正确的方向发展。

输出图像如下所示 enter image description here

这是用于将其转换为IYUV的C代码,我从github获得并使用main函数稍微修改:

/*
 * Sonix SN9C20X decoder
 * Vasily Khoruzhick, (C) 2008-2009
 * Algorithm based on Java code written by Jens on microdia google group
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Note this code was originally licensed under the GNU GPL instead of the
 * GNU LGPL, its license has been changed by its author.
 */

//#include "libv4lconvert-priv.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>



#define DO_SANITY_CHECKS 0

static const int UVTranslate[32] = {0, 1, 2, 3,
            8, 9, 10, 11,
            16, 17, 18, 19,
            24, 25, 26, 27,
            4, 5, 6, 7,
            12, 13, 14, 15,
            20, 21, 22, 23,
            28, 29, 30, 31};

static const int Y_coords_624x[128][2] = {
{ 0,  0}, { 1,  0}, { 2,  0}, { 3,  0}, { 4,  0}, { 5,  0}, { 6,  0}, { 7,  0},
{ 0,  1}, { 1,  1}, { 2,  1}, { 3,  1}, { 4,  1}, { 5,  1}, { 6,  1}, { 7,  1},
{ 0,  2}, { 1,  2}, { 2,  2}, { 3,  2}, { 4,  2}, { 5,  2}, { 6,  2}, { 7,  2},
{ 0,  3}, { 1,  3}, { 2,  3}, { 3,  3}, { 4,  3}, { 5,  3}, { 6,  3}, { 7,  3},

{ 0,  4}, { 1,  4}, { 2,  4}, { 3,  4}, { 4,  4}, { 5,  4}, { 6,  4}, { 7,  4},
{ 0,  5}, { 1,  5}, { 2,  5}, { 3,  5}, { 4,  5}, { 5,  5}, { 6,  5}, { 7,  5},
{ 0,  6}, { 1,  6}, { 2,  6}, { 3,  6}, { 4,  6}, { 5,  6}, { 6,  6}, { 7,  6},
{ 0,  7}, { 1,  7}, { 2,  7}, { 3,  7}, { 4,  7}, { 5,  7}, { 6,  7}, { 7,  7},

{ 8,  0}, { 9,  0}, {10,  0}, {11,  0}, {12,  0}, {13,  0}, {14,  0}, {15,  0},
{ 8,  1}, { 9,  1}, {10,  1}, {11,  1}, {12,  1}, {13,  1}, {14,  1}, {15,  1},
{ 8,  2}, { 9,  2}, {10,  2}, {11,  2}, {12,  2}, {13,  2}, {14,  2}, {15,  2},
{ 8,  3}, { 9,  3}, {10,  3}, {11,  3}, {12,  3}, {13,  3}, {14,  3}, {15,  3},

{ 8,  4}, { 9,  4}, {10,  4}, {11,  4}, {12,  4}, {13,  4}, {14,  4}, {15,  4},
{ 8,  5}, { 9,  5}, {10,  5}, {11,  5}, {12,  5}, {13,  5}, {14,  5}, {15,  5},
{ 8,  6}, { 9,  6}, {10,  6}, {11,  6}, {12,  6}, {13,  6}, {14,  6}, {15,  6},
{ 8,  7}, { 9,  7}, {10,  7}, {11,  7}, {12,  7}, {13,  7}, {14,  7}, {15,  7}
};

static void do_write_u(const unsigned char *buf, unsigned char *ptr,
    int i, int j)
{
    *ptr = buf[i + 128 + j];
}

static void do_write_v(const unsigned char *buf, unsigned char *ptr,
    int i, int j)
{
    *ptr = buf[i + 160 + j];
}

void v4lconvert_sn9c20x_to_yuv420(const unsigned char *raw, unsigned char *i420,
  int width, int height, int yvu)
{
    int i = 0, x = 0, y = 0, j, relX, relY, x_div2, y_div2;
    const unsigned char *buf = raw;
    unsigned char *ptr;
    int frame_size = width * height;
    int frame_size_div2 = frame_size >> 1;
    int frame_size_div4 = frame_size >> 2;
    int width_div2 = width >> 1;
    int height_div2 = height >> 1;
    void (*do_write_uv1)(const unsigned char *buf, unsigned char *ptr, int i,
    int j) = NULL;
    void (*do_write_uv2)(const unsigned char *buf, unsigned char *ptr, int i,
    int j) = NULL;

    if (yvu) {
        do_write_uv1 = do_write_v;
        do_write_uv2 = do_write_u;
    }
    else {
        do_write_uv1 = do_write_u;
        do_write_uv2 = do_write_v;
    }

    while (i < (frame_size + frame_size_div2)) {
        for (j = 0; j < 128; j++) {
            relX = x + Y_coords_624x[j][0];
            relY = y + Y_coords_624x[j][1];

#if (DO_SANITY_CHECKS==1)
            if ((relX < width) && (relY < height)) {
#endif
                ptr = i420 + relY * width + relX;
                *ptr = buf[i + j];
#if (DO_SANITY_CHECKS==1)
            }
#endif

        }
        x_div2 = x >> 1;
        y_div2 = y >> 1;
        for (j = 0; j < 32; j++) {
            relX = (x_div2) + (j & 0x07);
            relY = (y_div2) + (j >> 3);

#if (DO_SANITY_CHECKS==1)
            if ((relX < width_div2) && (relY < height_div2)) {
#endif
                ptr = i420 + frame_size +
                    relY * width_div2 + relX;
                do_write_uv1(buf, ptr, i, j);
                ptr += frame_size_div4;
                do_write_uv2(buf, ptr, i, j);
#if (DO_SANITY_CHECKS==1)
            }
#endif
        }

        i += 192;
        x += 16;
        if (x >= width) {
            x = 0;
            y += 8;
        }
    }
}

int main(int argc, char** argv)
{
    int cnt;
    FILE* fd;
    size_t size = 640*480*3/2;

    fd = fopen(argv[1], "rb");
    if (!fd) {
        fprintf(stderr, "Error opening %s\n", argv[1]);
        return EXIT_FAILURE;
    }

    uint8_t* raw = malloc(size*sizeof(uint8_t));
    uint8_t* out = malloc(size*sizeof(uint8_t));

    if (!raw || !out) {
        goto cleanup;
    }

    fread(raw, sizeof(uint8_t), size, fd);
    fclose(fd);

    v4lconvert_sn9c20x_to_yuv420(raw, out, 640, 480, 0);

    fd = fopen("out_640x480.yuv", "wb");
    if (!fd) {
        fprintf(stderr, "Error opening %s\n", argv[1]);
        goto cleanup;
    }
    fwrite(out, sizeof(uint8_t), size, fd);

cleanup:
    free(raw);
    free(out);

    return EXIT_SUCCESS;
}