上一次实现了 YUV 摄像头,这次带来的是实现 RGB 摄像头,理论上更容易实现在摄像头上绘制期望的内容。
代码是基于上次 YUV摄像头实现的,修改如下:
1.描述符的修改:需要改为 RGB24 的GUID, 同时需要修改一个点占用多少个Bits(下图中 24Bits==3Bytes)
0x01, // Index of this format descriptor
0x01, // Number of frame descriptors following that correspond to this format
//0x14,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71, // Globally Unique Identifier used to identify stream-encoding format 59563132-1000-800000AA-389B71
0x7d,0xeb,0x36,0xe4,0x4f,0x52,0xce,0x11,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70,
0x18, // Number of bits per pixel used to specify color in the decoded video frame
0x01,
2。下面描述符中需要根据分辨率计算进行填充
/*CS_INTERFACE Descriptor (46 bytes) */
0x2E, // Descriptor size is 46 bytes
0x24, // CS_INTERFACE Descriptor Type
0x05, // VS_FRAME_UNCOMPRESSED descriptor subtype
0x01, // Index of this frame descriptor
0x01, // D0: Still image supported 1
0xA0,0x00, // Width of decoded bitmap frame in pixels
0x78,0x00, // Height of decoded bitmap frame in pixels
0x00,0x08,0x07,0x00, // 最小的bps,注意计算方法是:图像长度x宽度x3x8x最慢的fps. 最后的单位是 bps,这里是 160*120*3*8*1=0x70800
0x00,0x18,0x15,0x00, // 最大的bps,注意计算方法是:图像长度x宽度x3x8x最快的fps. 最后的单位是 bps,这里是 160*120*3*8*3=0x151800
0x00,0xE1,0x00,0x00, // 一张图片的尺寸:图像长度x宽度x3
0xD5,0xDC,0x32,0x00, // 指定下面的哪个作为默认的FPS
0x05, // 这里给出下面有多少种 FPS
0xD5,0xDC,0x32,0x00, // FPS 这里是 3,333,333 ,单位是 100ns, 因此实际表示 333,333,300ns 就是 333ms,算下来是3FPS, 最快3FPS
0x00,0x09,0x3D,0x00, // Shortest frame interval supported (at highest frame rate), in 100 ns units
0x40,0x4B,0x4C,0x00, // Shortest frame interval supported (at highest frame rate), in 100 ns units
0xE0,0x70,0x72,0x00, // Shortest frame interval supported (at highest frame rate), in 100 ns units
0x80,0x96,0x98,0x00, // FPS 这里是10,000,000 ,单位是 100ns, 因此实际表示 1,000,000,000ns 就是 1s,算下来是1FPS,最慢1FPS
3.此外,修改下面几个请求的返回值
/* GET_CUR Video_Streaming */
const uint8_t GET_CUR_VideoStreaming[ ] =
{
0x00,0x00,0x01,0x01,0x15,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xE1,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x24,0xF4,0x00,0x00,0x00,
0x00,0x00
};
上述数据中0x00 0xE1 是一帧的大小,0xFE 是一个USB包能放置的数据大小(256-2)。
GET_CUR Video_Streaming 用于获取当前 Video Streaming(视频流)接口的配置参数。
接下来的2个和上面的含义类似:
const uint8_t GET_MAX_VideoStreaming[ ]=
{
0x00,0x00,0x01,0x01,0x55,0x58,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xE1,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x24,0xF4,0x00,0x00,0x00,
0x00,0x00
};
const uint8_t GET_MIN_VideoStreaming[ ]=
{
0x00,0x00,0x01,0x01,0x15,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xE1,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x24,0xF4,0x00,0x00,0x00,
0x00,0x00
};
4.写一个随机数生成器,每次使用随机数填充作为显示内容。
uint32_t seed=1;
uint8_t random() {
seed=seed*1103515245+12345;
return (uint8_t)((seed>>16)&0xFF);
}
uint8_t color=80;
const uint16_t TOTAL=160*120*3;
uint16_t leftLength=TOTAL;
void USBFS_Endp_ZSend (void) {
if (USBFS_Endp_Busy[3] == 0) { // 可以发送
for (int i=2;i<256;i++) {
USBFS_EP3_Buf[i]=random();
}
if (leftLength==TOTAL) {
if (USBFS_EP3_Buf[1] == 0x80) {
USBFS_EP3_Buf[1] = 0x81;
} else {
USBFS_EP3_Buf[1] = 0x80;
}
}
if (leftLength>254) {
USBFSD_UEP_TLEN (3)=256;
leftLength=leftLength-254;
} else {
USBFSD_UEP_TLEN (3)=leftLength+2;
leftLength=0;
}
//printf ("%d %x %x %x\r\n", leftLength, USBFSD_UEP_TLEN (3), USBFS_EP3_Buf[1], USBFS_EP3_Buf[2]);
USBFSD_UEP_TX_CTRL (3) = (USBFSD_UEP_TX_CTRL (3) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NONE;
USBFS_Endp_Busy[3] = 1;
if (leftLength == 0) {
leftLength=TOTAL;
}
}
}
工作的测试视频
完整的项目代码