我必须使用MS DirectShow从相机捕捉video帧(我只想要原始像素数据)。
我能够构buildgraphics/滤波器networking(捕获设备filter和ISampleGrabber)并实现callback(ISampleGrabberCB)。 我收到适当大小的样本。
但是,它们总是颠倒(垂直翻转,即不旋转),颜色通道是BGR顺序(不是RGB)。
我试图将BITMAPINFOHEADER中的biHeight字段设置为正值和负值,但没有任何效果。 根据MSDN文档,ISampleGrapper :: SetMediaType()忽略video数据的格式块。
这里是我看到的(用不同的相机logging的,不是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
我正在检查每个函数的返回types,并没有得到任何错误。
我很感激任何暗示或想法。
我已经尝试过的事情:
将biHeight字段设置为捕捉设备filter或样本采集器的负值,或者两者兼得或两者兼备 – 都没有任何影响。
使用IGraphBuilder连接引脚 – 同样的问题。
在更改媒体types之前连接引脚 – 同样的问题。
通过再次查询filter来检查媒体types是否被filter实际应用 – 但是显然它被应用或者至less被存储。
将图像解释为总字节反转(最后一个字节在前,最后一个字节) – 然后水平翻转。
检查摄像机是否有问题 – 当我用VLC(DirectShow capture)testing时,看起来很正常。
我注意到,当使用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); }
我的这个快速破解:
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色彩空间上是正确的,对于其他色彩空间这个代码需要纠正