我必须使用MS DirectShow从相机捕获视频帧(我只想要原始像素数据) 我能够构建图形/过滤网络(捕获设备过滤器和ISampleGrabber)并实现回调(ISampleGrabberCB)。我收到了合适尺寸的样品。
然而,它们总是颠倒的(垂直翻转,不旋转),颜色通道是BGR顺序(不是RGB)。
我尝试将BITMAPINFOHEADER中的biHeight字段设置为正值和负值,但它没有任何效果。根据MSDN文档,ISampleGrapper :: SetMediaType()无论如何都会忽略视频数据的格式块。
这是我看到的(用不同的相机记录,而不是DS),以及DirectShow ISampleGrabber给我的东西:“RGB”实际上分别是红色,绿色和蓝色:
我正在使用的代码示例,略有简化:
// Setting the media type...
AM_MEDIA_TYPE* media_type = 0 ;
this->ds.device_streamconfig->GetFormat(&media_type); // The IAMStreamConfig of the capture device
// Find the BMI header in the media type struct
BITMAPINFOHEADER* bmi_header;
if (media_type->formattype != FORMAT_VideoInfo) {
bmi_header = &((VIDEOINFOHEADER*)media_type->pbFormat)->bmiHeader;
} else if (media_type->formattype != FORMAT_VideoInfo2) {
bmi_header = &((VIDEOINFOHEADER2*)media_type->pbFormat)->bmiHeader;
} else {
return false;
}
// Apply changes
media_type->subtype = MEDIASUBTYPE_RGB24;
bmi_header->biWidth = width;
bmi_header->biHeight = height;
// Set format to video device
this->ds.device_streamconfig->SetFormat(media_type);
// Set format for sample grabber
// bmi_header->biHeight = -(height); // tried this for either and both interfaces, no effect
this->ds.sample_grabber->SetMediaType(media_type);
// Connect filter pins
IPin* out_pin= getFilterPin(this->ds.device_filter, OUT, 0); // IBaseFilter interface for the capture device
IPin* in_pin = getFilterPin(this->ds.sample_grabber_filter, IN, 0); // IBaseFilter interface for the sample grabber filter
out_pin->Connect(in_pin, media_type);
// Start capturing by callback
this->ds.sample_grabber->SetBufferSamples(false);
this->ds.sample_grabber->SetOneShot(false);
this->ds.sample_grabber->SetCallback(this, 1);
// start recording
this->ds.media_control->Run(); // IMediaControl interface
我正在检查每个函数的返回类型,并且不会出现任何错误。
我很感激任何提示或想法。
我已经尝试过的事情:
将biHeight字段设置为捕获设备过滤器或样本捕获器的负值,或者两者都设置为负值,或者两者都没有 - 没有任何效果。
使用IGraphBuilder连接引脚 - 同样的问题。
在更改介质类型之前连接引脚 - 同样的问题。
通过再次查询来检查过滤器是否实际应用了介质类型 - 但显然已应用或至少已存储。
将图像解释为总字节反转(最后一个字节,第一个字节最后一个) - 然后它将水平翻转。
检查摄像机是否有问题 - 当我使用VLC(DirectShow捕获)测试时,它看起来很正常。
答案 0 :(得分:0)
我注意到当使用I420时,色彩空间转动消失。 此外,大多数当前编解码器(VP8)用作格式原始I / O I420颜色空间。
我在色彩空间I420中写了一个简单的镜像框架功能。
void Camera::OutputCallback(unsigned char* data, int len, uint32_t timestamp, void *instance_)
{
Camera *instance = reinterpret_cast<Camera*>(instance_);
Transport::RTPPacket packet;
packet.rtpHeader.ts = timestamp;
packet.payload = data;
packet.payloadSize = len;
if (instance->mirror)
{
Video::ResolutionValues rv = Video::GetValues(instance->resolution);
int k = 0;
// Chroma values
for (int i = 0; i != rv.height; ++i)
{
for (int j = rv.width; j != 0; --j)
{
int l = ((rv.width * i) + j);
instance->buffer[k++] = data[l];
}
}
// U values
for (int i = 0; i != rv.height/2; ++i)
{
for (int j = (rv.width/2); j != 0; --j)
{
int l = (((rv.width / 2) * i) + j) + rv.height*rv.width;
instance->buffer[k++] = data[l];
}
}
// V values
for (int i = 0; i != rv.height / 2; ++i)
{
for (int j = (rv.width / 2); j != 0; --j)
{
int l = (((rv.width / 2) * i) + j) + rv.height*rv.width + (rv.width/2)*(rv.height/2);
if (l == len)
{
instance->buffer[k++] = 0;
}
else
{
instance->buffer[k++] = data[l];
}
}
}
packet.payload = instance->buffer;
}
instance->receiver->Send(packet);
}
答案 1 :(得分:-1)
我快速破解:
void Camera::OutputCallback(unsigned char* data, int len, void *instance_)
{
Camera *instance = reinterpret_cast<Camera*>(instance_);
int j = 0;
for (int i = len-4; i > 0; i-=4)
{
instance->buffer[j] = data[i];
instance->buffer[j + 1] = data[i + 1];
instance->buffer[j + 2] = data[i + 2];
instance->buffer[j + 3] = data[i + 3];
j += 4;
}
Transport::RTPPacket packet;
packet.payload = instance->buffer;
packet.payloadSize = len;
instance->receiver->Send(packet);
}
在RGB32色彩空间上是正确的,对于其他色彩空间,此代码需要更正