Jetson TK1: OpenCV VideoWriter Not Capturing Video Frames at All

Hello,

[My Environment]

  • Jetson TK1
  • Jetpack 3.1 (Linux 4 Tegra 21.8 = Ubuntu 14.04)
  • OpenCV4Tegra 2.4.13
  • ZED SDK 1.1.1

[My Problem]
I’m encountering an issue similar to the one described here: Cannot write video frame using OpenCV VideoWriter. My code is supposed to record video, but it only outputs a 5.7KB avi file, indicating that the frames are not being captured correctly.

[My Pseudo Code]
I’ve trimmed the unnecessary code and simplified it for clarity.

// Standard includes
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>

// ZED includes
#include <zed/Mat.hpp>
#include <zed/Camera.hpp>
#include <zed/utils/GlobalDefine.hpp>

// OpenCV includes
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <ctime> // For time functions

// CUDA functions include
#include "kernel.cuh"

using namespace sl::zed;
using namespace std;

int main(int argc, char **argv) {
    // Initialize ZED camera
    Camera* zed = new Camera(HD720, 15);
    InitParams parameters;
    parameters.unit = UNIT::METER;
    ERRCODE err = zed->init(parameters);
    if (err != SUCCESS) {
        std::cerr << "Error initializing ZED camera: " << errcode2str(err) << std::endl;
        delete zed;
        return 1;
    }

    // Initialize CUDA memory
    CPU_obstacleCounts = (int*)malloc(sizeof(int) * 3);
    *CPU_obstacleCounts = 0;
    *(CPU_obstacleCounts + 1) = 0;
    *(CPU_obstacleCounts + 2) = 0;
    int* GPU_obstacleCounts;
    cudaMalloc((void**)&GPU_obstacleCounts, 3 * sizeof(int));
    cudaMemcpy(GPU_obstacleCounts, CPU_obstacleCounts, 3 * sizeof(int), cudaMemcpyHostToDevice);

    // ZED OpenCV Variables
    int width = zed->getImageSize().width;
    int height = zed->getImageSize().height;
    
    // Create and allocate GPU memory for the image matrix
    Mat imageCropp;
    imageCropp.data = (unsigned char*)nppiMalloc_8u_C4(width, height, &imageCropp.step);
    imageCropp.setUp(width, height, 4, sl::zed::UCHAR, GPU);
    
    // Create and allocate GPU memory for the mask matrix
    Mat imageCheckerboard;
    imageCheckerboard.data = (unsigned char*)nppiMalloc_8u_C4(width, height, &imageCheckerboard.step);
    imageCheckerboard.setUp(width, height, 4, sl::zed::UCHAR, GPU);
    
    // Compute the checkerboard only once; it will be used to mask the invalid area
    cuCreateCheckerboard(imageCheckerboard);

    // Create a CPU image for display purposes
    cv::Mat imDisplay(height, width, CV_8UC4);

    // Initialize VideoWriter to record video
    std::string outputVideo = "output_" + getCurrentDateTime() + ".avi"; // Output file name
    int codec = CV_FOURCC('M', 'J', 'P', 'G'); // Codec MJPEG = .avi
    int fps = 15;
    cv::VideoWriter videoWriter(outputVideo, codec, fps, cv::Size(width, height));

    if (!videoWriter.isOpened()) {
        std::cout << "Could not open the output video file for writing." << std::endl;
        return -1;
    }

    float distCut = 1.0;

    // Main processing loop
    while (true) {
        bool res = zed->grab(STANDARD);
        Mat imageLeftGPU = zed->retrieveImage_gpu(LEFT);
        Mat depthGPU = zed->retrieveMeasure_gpu(DEPTH);
        cuDetectObstacleByDepth(depthGPU, imageLeftGPU, imageCropp, imageCheckerboard, distCut, GPU_obstacleCounts);

        // Copy processed image from GPU to CPU
        cudaMemcpy2D((uchar*)imDisplay.data, imDisplay.step, (Npp8u*)imageCropp.data, imageCropp.step, imageCropp.getWidthByte(), imageCropp.height, cudaMemcpyDeviceToHost);
        cudaMemcpy(CPU_obstacleCounts, GPU_obstacleCounts, 3 * sizeof(int), cudaMemcpyDeviceToHost);

        videoWriter.write(imDisplay); // Video recording
        cv::imshow("Obstacle Display", imDisplay);
        char key = cv::waitKey(1);

        if (key == 'q' || key == 'Q') {
            std::cout << "q pressed. Breaking." << std::endl;
            break;
        }
        cudaMemset(GPU_obstacleCounts, 0, 3 * sizeof(int)); // Clear GPU data
    }
    
    std::cout << "[1] Loop exited." << std::endl;
    
    // Cleanup
    videoWriter.release(); // Release the video writer
    free(CPU_obstacleCounts);
    cudaFree(GPU_obstacleCounts);
    std::cout << "[2] Obstacle counts memory freed." << std::endl;
    imDisplay.release();
    std::cout << "[3] OpenCV Image Display released." << std::endl;
    imageCropp.deallocate();
    imageCheckerboard.deallocate();
    delete zed;
    std::cout << "[4] All dynamic memory deallocated successfully." << std::endl;
    
    return 0;
}

[What I’ve Tried]
In the code, I’ve set the codec to CV_FOURCC('M','J','P','G'). I’ve also tried other codecs like ‘XVID’, ‘DIVX’, ‘H264’, and ‘MP4V’, but they didn’t work. I installed VLC media player and the issue persisted. Additionally, I installed FFmpeg codecs using the command:

sudo apt-get install libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavl-dev libavresample-dev libavutil-dev

as suggested in this link: How to install FFmpeg on Jetson TX1, but it didn’t resolve the issue.

“sudo apt-get install ffmpeg” didn’t work.

Hi @stm32h757,

In your sample, are the images correctly displayed with imshow?

Yes.

I communicate with the mini car using serial communication (MAVLink protocol) and display information on imDisplay.

It works very well.

Actually, I’m doing this to debug why the car isn’t stopping when it encounters obstacles. The car stops during bench tests, but in real-world situations, it doesn’t. I suspect the reason is that obstacles aren’t being detected within 1 meter, but I want to confirm this with video.

If video saving fails, I will take a screenshot every second.

I think this might be a codec problem.

If I could install ‘ffmpeg,’ it would solve the problem, but ‘sudo apt-get install ffmpeg’ doesn’t work. I heard that it works on other Linux distributions with ‘sudo apt-get install ffmpeg.’

I also posted this on the NVIDIA Jetson TK1 forum, and I think they can help me.

Thank you.

cv::Mat convertedFrame;
cv::cvtColor(imDisplay, convertedFrame, cv::COLOR_BGRA2BGR); // Convert from BGRA (4 channels) to BGR (3 channels)
videoWriter.write(convertedFrame);

This codes solved the problem.

1 Like