I am trying to save a video file as MP4 format in ubuntu16.04 using videoWriter function as below
int frame_width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
int frame_height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
VideoWriter video("/home/Desktop/1.mp4",CV_FOURCC('M','J','P','G'),10, Size(frame_width,frame_height));
But I am getting the error as below:
OpenCV: FFMPEG: tag 0x47504a4d/'MJPG' is not supported with codec id 8 and format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV: FFMPEG: fallback to use tag 0x0000006c/'l???
When I change my output file extension to .avi, I get no error but VLC player doesn't display any video. I tried different players also but in vain.
I even did the following thinking my VLC might be a problem but didn't work. Really in need of a solution
sudo apt-get ubuntu-restricted-extras
As per this link, Writing x264 from OpenCV 3 with FFmpeg on Linux the terminal message
OpenCV: FFMPEG: tag 0x47504a4d/'MJPG' is not supported with codec id 8 and format 'mp4 / MP4 (MPEG-4 Part 14)' is not an error but a warning that the codec type is incompatible with ffmpeg and mp4 container. However, it does generate the output videofile.
If MJPG codec does not matter to you, then try to replace it with 0x21 and check the output.
VideoWriter video("/home/Desktop/1.mp4",0x21,10, Size(frame_width,frame_height));
If your video still does not play then probably, your VideoWriter is not writing any frames to video. You can check if there are any frames in the written output video by your algorithm.
For more clarifications you can check the VideoWriter class refernce https://docs.opencv.org/3.4.3/dd/d9e/classcv_1_1VideoWriter.html
Thanks
Related
I am trying to simply open a video with openCV, process frames and write the processed frames into a new video file.
My problem is that even if I don't process frames at all (just opening a video, reading frames with VideoCapture and writing them with VideoWriter to a new file), the output file appears more "green" than the input.
The code to do that can be found in any openCV tutorial, nothing special.
I use openCV c++ 4.4.0 on Windows 10.
I use openCV with ffmpeg through opencv_videoio_ffmpeg440_64.dll
The input video is mp4.
I write the output as a .avi with huffyuv codec :
m_video_writer.reset(new cv::VideoWriter(m_save_video_path.toStdString(), cv::VideoWriter::fourcc('H', 'F', 'Y', 'U'), // lossless compression
m_model->getFps(), cv::Size(m_frame_size.width(), m_frame_size.height())));
I tried many other codecs and the problem remains.
The difference in pixels is small, not constant in value but always varying in the same way : blue channel is lower, red and green are higher.
Strange fact : when I open both input or output video with opencv, the matrix are actually exactly the same. So I guess the problem is in the reading ??
Here are the properties of each video file, as exported with Windows Media Playre (MPC-HC).
VS
What should I investigate ?
Thx !!
Full code here (copying the first 100 frames of my video):
VideoCapture original("C:/Users/axelle/Videos/original.MP4");
int frame_height = original.get(CAP_PROP_FRAME_HEIGHT);
int frame_width = original.get(CAP_PROP_FRAME_WIDTH);
int fps = original.get(CAP_PROP_FPS);
VideoWriter output("C:/Users/axelle/Videos/output.avi", VideoWriter::fourcc('H', 'F', 'Y', 'U'),
fps, cv::Size(frame_width, frame_height));
int count = 0;
while (count < 100)
{
count++;
Mat frame;
original >> frame;
if (frame.empty())
{
break;
}
//imshow("test", frame);
//waitKey(0);
output.write(frame);
}
original.release();
output.release();
Note: the difference in colors can be seen in the imshow already.
There is a bug in OpenCV VideoCapture when reading video frames using FFmpeg backend.
The bug results a "color shift" when H.264 video stream is marked as BT.709 color standard.
The subject is too important to leave it unanswered...
The important part of the post, is reproducing the problem, and proving the problem is real.
The solution I found is selecting GStreamer backend instead of FFmpeg backend.
The suggested solution has downsides (like the need to build OpenCV with GStreamer support).
Note:
The problem is reproducible using OpenCV 4.53 under Windows 10.
The problem is also reproducible under Ubuntu 18.04 (using OpenCV in Python).
The issue applies both "full range" and "limited range" of BT.709 color standard.
Building synthetic video pattern for reproducing the problem:
We can use FFmpeg command line tool create a synthetic video to be used as input.
The following command generates an MP4 video file with H.264 codec, and BT.709 color standard:
ffmpeg -y -f lavfi -src_range 1 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -i testsrc=size=192x108:rate=1:duration=5 -vcodec libx264 -crf 17 -pix_fmt yuv444p -dst_range 1 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -bsf:v h264_metadata=video_full_range_flag=1:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 bt709_full_range.mp4
The above command uses yuv444p pixel format (instead of yuv420p) for getting more pure colors.
The arguments -bsf:v h264_metadata=video_full_range_flag=1:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 use Bitstream Filter for marking the H.264 stream as "full range" BT.709.
Using MediaInfo tool, we can view the following color characteristics:
colour_range: Full
colour_primaries: BT.709
transfer_characteristics: BT.709
matrix_coefficients: BT.709
Capturing the video using OpenCV:
The following C++ code grabs the first frame, and save it to 1.png image file:
#include "opencv2/opencv.hpp"
void main()
{
cv::VideoCapture cap("bt709_full_range.mp4");
cv::Mat frame;
cap >> frame;
cv::imwrite("1.png", frame);
cap.release();
}
We may also use the following Python code:
import cv2
cap = cv2.VideoCapture('bt709_full_range.mp4')
_, frame = cap.read()
cv2.imwrite('1.png', frame)
cap.release()
Converting bt709_full_range.mp4 into images sequence using FFmpeg:
ffmpeg -i bt709_full_range.mp4 -pix_fmt rgb24 %03d.png
The file name of the first "extracted" frame is 001.png.
Comparing the results:
The left side is 1.png (result of OpenCV)
The right side is 001.png (result of FFmpeg command line tool)
As you can see, the colors are different.
The value of the red color pixels of OpenCV are RGB = [232, 0, 3].
The value of the red color pixels of FFmpeg are RGB = [254, 0, 0].
The original RGB value is probably [255, 0, 0] (value is 254 due to colors conversion).
As you can see, the OpenCV colors are wrong!
Solution - selecting GStreamer backend instead of FFmpeg backend:
The default OpenCV release excludes GStreamer support (at least in Windows).
You may use the following instruction for building OpenCV with GStreamer.
Here is a C++ code sample that uses GStreamer backend for grabbing the first frame:
void main()
{
cv::VideoCapture cap("filesrc location=bt709_full_range.mp4 ! decodebin ! videoconvert ! appsink", cv::CAP_GSTREAMER);
cv::Mat frame;
cap >> frame;
cv::imwrite("1g.png", frame);
cap.release();
}
Result:
The left side is 1g.png (result of OpenCV using GStreamer)
The right side is 001.png (result of FFmpeg command line tool)
The value of the red color pixels of OpenCV using GStreamer are RGB = [254, 0, 1]. (blue is 1 and not zero due to colors conversion).
Conclusions:
Using GStreamer backend (instead of FFmpeg) backend seems to solve the "color shifting" problem.
OpenCV users need to be aware of the color shifting problem.
Let's hope that OpenCV developers (or FFmpeg plugin developers) fix the problem.
I want to create a H.264 video out of frames generated by my program in C++. Is there a way to change the video encoding parameters for the VideoWriter object in my code, except the codec (eg. CRF) like we do in FFMpeg?
Thanks for your help
I would like to improve decoding H.264 video stream with MPC-HC using LAV video decoder.
The stream I will play back is always in format yuvj444p (Planar YCbCr 4:4:4 in TV level [0-255]), encoded with x264.
I'm using MPC-HC version 1.7.10, and LAV video decoder 0.68.1
I have a nVidia Quadro K5200, and I know how to write GLSL shader to run YUV to RGB conversion.
I'm wondering if someone here could give me a hint if it's worth doing such job, and possibly on where to start.
Should I customize the EVR (Enhanced Video Renderer - Custom Presenter) ?
Should I just write an internal shader?
...
Yes, LAV Video Decoder filter does support yuvj444p to RGB32 color conversion.
In order to prove it, I have tried the following test:
Create uncompressed AVI file in RGB color format (using MATLAB).
Convert the AVI file to x264 compressed MKV file in yuvj444p color format (using FFMPEG).
Build a filter graph in Graph Studio Next, with LAV Video Decoder (DirectShow) filter.
Inspect the output pin of Decoder filter.
Play the graph, and compare the output frame to original input frame.
Input AVI file name: RGB_INPUT.avi
MKV file name: OUTPUT.mkv
I used ffmpeg with the following parameters (in command line):
ffmpeg -i RGB_INPUT.avi -pix_fmt yuvj444p -vf scale=w=0:h=0:out_color_matrix=bt709 -c:v libx264 -crf 18 -x264opts colorprim=bt709:transfer=bt709:colormatrix=bt709 -an OUTPUT.mkv
I took the example from here: http://forum.doom9.org/showthread.php?p=1671195
Filter Graph:
Inspecting the output pin of LAV Video Decoder, shows that output color format is RGB32 (media sub-type is: MEDIASUBTYPE_RGB32):
Comparing uncompressed input frame, to decoded output frame:
Source frame (uncompressed image):
Video Renderer output (screenshot):
Absolute difference image (scaled by 10):
Conclusion: LAV Video Decoder correctly convert yuvj444 to RGB32.
I want to create a mpeg4 stream whith the following specs:
Container mp4.mov m4v
Resolution 1920 X 1080
Codec h264 main profile 4.1
I am wondering what CV_FOURCC and file extension should I use?
Any help appreciated.
I am using C++
In general where can find the fourcc for any coded?
If you read a file, you don't need to specify any codec.
If you write to a file, I think you need to specify X264. Full list of FOURCC codes avaliable here.
Some of the common fourCC codes used with OpenCV are mentioned here
http://opencv.willowgarage.com/wiki/documentation/cpp/highgui/VideoWriter
Here is a much longer list of the FOURCC codes of other codecs.
http://www.fourcc.org/codecs.php
Since you want to use H264, you can use H264 or X264 as the FOURCC codes.
I want to produce a video file out of a stream of RGB images flowing at 52fps. I found the opencv api pretty handy to use (cv::VideoWriter). The problem is that I can play the produced avi only with VLC; which plays the video but yells:
[0x28307b0] xcb_xv generic error: no available XVideo adaptor
Any other video player (on the same computer) is not able to read and play the video.
While recording everything looks ok: I get information about the output, about the size of the frame, the video codec, the fps, etc...no error.
Output #0, avi, to '01-23-12_15-24-51.avi':
Stream #0.0: Video: flv, yuv420p, 500x242, q=2-31, 7744 kb/s, 90k tbn, 52tbc
As OpenCv only supports avi as video container, the only thing I could change is the video codec, I tried (FOURCC code) FLV1, DIVX, DIV3 but none of them works correctly.
I would like to play this video with any video player on different computers. How can I make it work? is VideoWriter the right choice?
Any suggestion is very welcome.
Thanks.
If you have a video source for your images, it would be a good idea to use the same codec for output:
int videoType = (int)cap.get(CV_CAP_PROP_FORMAT);
VideoWriter vout;
vout.open(videofile + "_out.avi", videoType, 30, imgSize);
Or, you can try an older, simpler FOURCC. Or a Microsoft-specific, if you want to run it only on Windows.