Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing video with openCV - no key frame set for track 0

Tags:

c++

opencv

video

I'm trying to modify and write some video using openCV 2.4.6.1 using the following code:

cv::VideoCapture capture( video_filename );

    // Check if the capture object successfully initialized
    if ( !capture.isOpened() ) 
    {
        printf( "Failed to load video, exiting.\n" );
        return -1;
    }

    cv::Mat frame, cropped_img;

    cv::Rect ROI( OFFSET_X, OFFSET_Y, WIDTH, HEIGHT );


    int fourcc = static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));
    double fps = 30;
    cv::Size frame_size( RADIUS, (int) 2*PI*RADIUS );
    video_filename = "test.avi";
    cv::VideoWriter writer( video_filename, fourcc, fps, frame_size );

    if ( !writer.isOpened() && save )
    {
        printf("Failed to initialize video writer, unable to save video!\n");
    }

    while(true)
    {   
        if ( !capture.read(frame) )
        {
            printf("Failed to read next frame, exiting.\n");
            break;
        }

        // select the region of interest in the frame
        cropped_img = frame( ROI );                 

        // display the image and wait
        imshow("cropped", cropped_img);

        // if we are saving video, write the unwrapped image
        if (save)
        {
            writer.write( cropped_img );
        }

        char key = cv::waitKey(30);

When I try to run the output video 'test.avi' with VLC I get the following error: avidemux error: no key frame set for track 0. I'm using Ubuntu 13.04, and I've tried using videos encoded with MPEG-4 and libx264. I think the fix should be straightforward but can't find any guidance. The actual code is available at https://github.com/benselby/robot_nav/tree/master/video_unwrap. Thanks in advance!

like image 320
Ben S Avatar asked Sep 03 '13 17:09

Ben S


2 Answers

[PYTHON] Apart from the resolution mismatch, there can also be a frames-per-second mismatch. In my case, the resolution was correctly set, but the problem was with fps. Checking the frames per second at which VideoCapture object was reading, it showed to be 30.0, but if I set the fps of VideoWriter object to 30.0, the same error was being thrown in VLC. Instead of setting it to 30.0, you can get by with the error by setting it to 30.

P.S. You can check the resolution and the fps at which you are recording by using the cap.get(3) for width, cap.get(4) for height and cap.get(5) for fps inside the capturing while/for loop.

The full code is as follows:

import numpy as np
import cv2 as cv2
cap = cv2.VideoCapture(0)

#Define Codec and create a VideoWriter Object
fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
#30.0 in the below line doesn't work while 30 does work.
out = cv2.VideoWriter('output.mp4', fourcc, 30, (640, 480))

while(True):
    ret, frame = cap.read()
    colored_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA)
    print('Width = ', cap.get(3),' Height = ', cap.get(4),' fps = ', cap.get(5))
    out.write(colored_frame)
    cv2.imshow('frame', colored_frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

The full documentation (C++) for what all properties can be checked is available here : propId OpenCV Documentation

like image 50
Mayank Sharma Avatar answered Oct 19 '22 00:10

Mayank Sharma


This appears to be an issue of size mismatch between the frames written and the VideoWriter object opened. I was running into this issue when trying to write a series of resized images from my webcam into a video output. When I removed the resizing step and just grabbed the size from an initial test frame, everything worked perfectly.

To fix my resizing code, I essentially ran a single test frame through my processing and then pulled its size when creating the VideoWriter object:

#include <cassert>
#include <iostream>
#include <time.h>

#include "opencv2/opencv.hpp"

using namespace cv;

int main()
{
    VideoCapture cap(0);
    assert(cap.isOpened());

    Mat testFrame;
    cap >> testFrame;
    Mat testDown;
    resize(testFrame, testDown, Size(), 0.5, 0.5, INTER_NEAREST);
    bool ret = imwrite("test.png", testDown);
    assert(ret);

    Size outSize = Size(testDown.cols, testDown.rows);
    VideoWriter outVid("test.avi", CV_FOURCC('M','P','4','2'),1,outSize,true);
    assert(outVid.isOpened());

    for (int i = 0; i < 10; ++i) {
        Mat frame;
        cap >> frame;

        std::cout << "Grabbed frame" << std::endl;

        Mat down;
        resize(frame, down, Size(), 0.5, 0.5, INTER_NEAREST);

        //bool ret = imwrite("test.png", down);
        //assert(ret);
        outVid << down;


        std::cout << "Wrote frame" << std::endl;
        struct timespec tim, tim2;
        tim.tv_sec = 1;
        tim.tv_nsec = 0;
        nanosleep(&tim, &tim2);
    }
}

My guess is that your problem is in the size calculation:

cv::Size frame_size( RADIUS, (int) 2*PI*RADIUS );

I'm not sure where your frames are coming from (i.e. how the capture is set up), but likely in rounding or somewhere else your size gets messed up. I would suggest doing something similar to my solution above.

like image 2
gkanwar Avatar answered Oct 19 '22 01:10

gkanwar