gstreamer のデコードと保存に関する緑色の線の問題のトラブルシューティングを忘れないでください。

バックグラウンド

ビジネス ニーズでは、デコードされたビデオ フレームを画像として保存する必要があります。ほとんどの場合、画像は正常です。一部のビデオ ストリームを変更すると、保存された画像の上に緑色の線が表示されます。次に、解決プロセスを記録します。
ここに画像の説明を挿入

コードの一部は次のとおりです

デコード コールバックは次のとおりです。完全なコードについては、前の記事「Gstreamer ハード デコード Rtsp ストリームとコードの実装」を参照してください。

最終的な調査結果は次のとおりです。

一部のカメラによってプッシュされたビデオ フレームのサイズが、gstreame によってデコードされた幅と高さと一致しません。例: gstreamer は実際には幅 = 1920、高さ = 1080 を解決しますが、実際の 1 フレームのデータは 1920 * 1088、8 バイト余分です。取得した幅と高さを使用してコピーされたフレームのサイズを計算する場合、カメラのプッシュが標準ではない場合にこの問題が発生します。
ここに画像の説明を挿入

opencv を使用して画像を保存し、最初に YUV を NV12 に変換してから、cv::imwrite() を呼び出します。例として
1920 1080 を取り上げます。修復する前に、デコードされた幅と高さを使用してフレーム サイズを計算します。予想されるフレーム サイズは次のとおりです: 1920 1080*3 / 2 = 3,110,400

{
    
    
	......
	cv::Mat img;
	// 创建并初始化原始YUV Mat对象
	yuvNV12.create(height * 3 / 2, width, CV_8UC1);
	memcpy(yuvNV12.data, map.data, width * height * 3 / 2);
	
	// yuv to img Mat
	cv::cvtColor(yuvNV12, img, cv::COLOR_YUV2BGR_NV12);
	......
}

実際のフレーム サイズ map.size = 3,133,440:

{
    
    
	......
	cv::Mat img;
	// 创建并初始化原始YUV Mat对象
	yuvNV12.create((map.size / width), width, CV_8UC1);
	memcpy(yuvNV12.data, map.data, map.size);
	// yuv to img Mat
	cv::cvtColor(yuvNV12, img, cv::COLOR_YUV2BGR_NV12);
            
}
GstFlowReturn ReadvideoFrame_callback(GstElement *sink, gpointer user_data)
{
    
    
    CustomData *data = (CustomData *)user_data;

    char video_format[32] = {
    
    0};
    int framerate[2] = {
    
    0};
    unsigned long long ts = 0;
    GstSample *sample;
    GstBuffer *buffer;
    GstCaps *caps;
    GstStructure *s;
    gint width, height; // 图片的尺寸

    // 使用pull-sample拉取视频帧,并映射到map变量,通过map拷贝出frame数据
    g_signal_emit_by_name(sink, "pull-sample", &sample);
    // g_print("new_sample succeeded (type '%d').\n", sample);

    if (sample)
    {
    
    
        caps = gst_sample_get_caps(sample);
        if (!caps)
        {
    
    
            g_print("gst_sample_get_caps fail\n");
            gst_sample_unref(sample);
            return GST_FLOW_ERROR;
        }
        s = gst_caps_get_structure(caps, 0);
        gboolean res;
        res = gst_structure_get_int(s, "width", &width); // 获取图片的宽
        // g_print("width: %d,  ", width);
        res |= gst_structure_get_int(s, "height", &height); // 获取图片的高
        // g_print("height: %d \n", height);
        if (!res)
        {
    
    
            g_print("gst_structure_get_int fail\n");
            gst_sample_unref(sample);
            return GST_FLOW_ERROR;
        }

        const char *format = gst_structure_get_string(s, "format");
        strcpy(video_format, format);
        gst_structure_get_fraction(s, "framerate", &framerate[0], &framerate[1]);

        // 获取视频的一帧buffer,注意,这个buffer是无法直接用的,它不是char类型
        buffer = gst_sample_get_buffer(sample);
        if (!buffer)
        {
    
    
            g_print("gst_sample_get_buffer fail\n");
            gst_sample_unref(sample);
            return GST_FLOW_ERROR;
        }

        GstMapInfo map;
        // 把buffer映射到map,这样我们就可以通过map.data取到buffer的数据
        auto rett = gst_buffer_map(buffer, &map, GST_MAP_READ);
        if (rett)
        {
    
    
            cv::Mat yuvNV12;
            cv::Mat img;
            // 创建并初始化原始YUV Mat对象
            // 有问题代码如下:
            // yuvNV12.create(height * 3 / 2, width, CV_8UC1);
            // memcpy(yuvNV12.data, map.data, width * height * 3 / 2);

            //修复如下:
            yuvNV12.create((map.size / width), width, CV_8UC1);
            memcpy(yuvNV12.data, map.data, map.size);
            // yuv to img Mat
            cv::cvtColor(yuvNV12, img, cv::COLOR_YUV2BGR_NV12);

            gst_buffer_unmap(buffer, &map); // 解除映射
        }
        else
        {
    
    
            g_print("gst_buffer_map failed!, %d\n", rett);
        }

        // release sample reference
        gst_sample_unref(sample);
    }
    else
    {
    
    
        g_print("sample is null...\n");
    }

    return GST_FLOW_OK;
}

Zero Sound Academy の無料チュートリアルがおすすめです 個人的に先生の教え方が良かったと思うので
共有したいと思います: [Linux, Nginx, ZeroMQ, MySQL, Redis, fastdfs,
MongoDB, ZK, ストリーミングメディア, CDN, P2P、K8S、Docker、
TCP/IP、Coroutine、DPDK およびその他の技術コンテンツ。クリックしてすぐに学習できます。

おすすめ

転載: blog.csdn.net/weixin_46935110/article/details/131150066