5

カメラからビデオ フレームをキャプチャするには、MS DirectShow を使用する必要があります (生のピクセル データが必要なだけです)。
グラフ/フィルター ネットワーク (キャプチャ デバイス フィルターと ISampleGrabber) を構築し、コールバック (ISampleGrabberCB) を実装することができました。適切なサイズのサンプルを受け取ります。

ただし、それらは常に逆さまであり (垂直方向に反転、つまり回転していない)、カラー チャネルは BGR 順 (RGB ではありません) です。

BITMAPINFOHEADER の biHeight フィールドを正と負の両方の値に設定しようとしましたが、効果がありません。MSDN のドキュメントによると、ISampleGrapper::SetMediaType() はとにかくビデオ データのフォーマット ブロックを無視します。

これが私が見たもの(DSではなく別のカメラで記録されたもの)で、DirectShow ISampleGrabberが私に与えたものです:「RGB」は実際にはそれぞれ赤、緑、青です:

これが私が見たものです(DSではなく別のカメラで記録されました)

これが DirectShow ISampleGrabber から得られるものです。

私が使用しているコードのサンプル、少し簡略化:

// 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

すべての関数の戻り値の型をチェックしていますが、エラーは発生しません。

ヒントやアイデアに感謝します。

私がすでに試したこと:

  1. キャプチャ デバイス フィルターまたはサンプル グラバーのいずれか、または両方、またはどちらにも負の値を biHeight フィールドに設定しても、効果はありません。

  2. IGraphBuilder を使用してピンを接続する - 同じ問題。

  3. メディアの種類を変更する前にピンを接続する - 同じ問題。

  4. メディア タイプがフィルターによって実際に適用されたかどうかを再度クエリして確認しますが、明らかに適用されているか、少なくとも保存されています。

  5. 画像を合計バイトが反転したものとして解釈すると (最後のバイトが最初、最初のバイトが最後)、水平方向に反転されます。

  6. ビデオ カメラに問題があるかどうかを確認しています。VLC (DirectShow キャプチャ) でテストすると、正常に見えます。

4

2 に答える 2

0

I420 色空間を使用すると回転が消えることに気付きました。さらに、最新のコーデック (VP8) は、Raw 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);
}
于 2014-05-15T01:47:57.240 に答える
-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 色空間では正しいですが、他の色空間ではこのコードを修正する必要があります

于 2014-05-08T11:06:55.297 に答える