QT Multimedia, black screen for H264 movie - c++

I'm trying to play a movie using the QT Multimedia framework (5.0.1), but I only get a black screen with a mov coded with H.264.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *mainWidget = new QWidget();
mainWidget->setGeometry(0,0, 1920, 1080);
QVideoWidget *widget = new QVideoWidget(mainWidget);
widget->setGeometry(0, 0, 1920, 1080);
QMediaPlayer *player = new QMediaPlayer;
QUrl localUrl = QUrl::fromLocalFile("test_mov.mov");
player->setMedia(localUrl);
qDebug() << "Player error state -> " << player->error();
qDebug() << "Media supported state -> " << QMediaPlayer::hasSupport("video/mov");
player->setVideoOutput(widget);
mainWidget->show();
player->play();
return a.exec();
}
The code compiles correctly and gives the following output on console, while the video widget remains black:
Player error state -> QMediaPlayer::NoError
Media supported state -> 1 // means "Probably supported"
I'm using Qt 5.0.1 on a Mac OSX 10.7.5. The file is correctly played by the player and ffmpeg -i test_mov.mov gives
Duration: 00:00:02.52, start: 0.000000, bitrate: 63708 kb/s
Stream #0:0(eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1920x1080, 63684 kb/s, SAR 1745:1920 DAR 349:216, 25 fps, 25 tbr, 25 tbn, 50 tbc
Does anyone knows what are the formats supported by QT Multimedia ?
Thank you

In Windows, QT video file formats usually appear with the .mov filename extension.
Other file formats that QuickTime supports natively (to varying degrees) include AIFF, WAV, DV, MP3, and MPEG-1.

Related

Can you play SEMI transparent WEBM videos in QT?

I am using QT to build a custom component for QML. I want this component to be able to play a WEBM video that contains an alpha channel. However, all of my attempts have resulted in the transparent pixels of the video getting replaced with black ones. This is my code currently:
MyClass::MyClass()
{
m_pixmap = new QPixmap(1920, 1080); // Create a canvas to draw on:
// Create something that can be drawn:
m_painter = new QPainter(m_pixmap);
m_rect = new QRect(0, 0, 1920, 1080);
// Create an area to present on:
m_label = new QLabel();
m_label->setPixmap(*m_pixmap);
m_label->show();
// Play video:
m_videoSink = new QVideoSink();
m_mediaPlayer = new QMediaPlayer();
m_mediaPlayer->setVideoSink(m_videoSink);
m_mediaPlayer->setSource(QUrl::fromLocalFile("path..."));
m_mediaPlayer->setLoops(QMediaPlayer::Infinite);
m_mediaPlayer->play();
// Add a an event for when the video frame changes:
connect(m_videoSink, SIGNAL(videoFrameChanged(QVideoFrame)), this, SLOT(SetFrame(QVideoFrame)));
qDebug() << "Constructed";
}
void MyClass::SetFrame(QVideoFrame frame)
{
frame.paint(m_painter, *m_rect, m_options); //Stores the frame in the m_pixmap
m_label->setPixmap(*m_pixmap);
}
In this example I attempt to use a QMediaPlayer to play the video, then a QVideoSink to extract the currently playing QVideoFrame and paint that to a QPixmap that is finally being displayed in a QLabel.
I have also tried to have the QMediaPlayer directly hooked up to a QVideoWidget.
I know that my WEBM video works as it is displaying as expected when imported in to other programs.

How to get fps for video with ffmpeg in c++?

I have videofile. How can I get fps for this video with ffmpeg in c++?
Type full code, please.
This is a simple program I wrote to dump video information to console:
#include <libavformat/avformat.h>
int main(int argc, const char *argv[])
{
if (argc < 2)
{
printf("No video file.\n");
return -1;
}
av_register_all();
AVFormatContext *pFormatCtx = NULL;
//open video file
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
return -1;
//get stream info
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1;
av_dump_format(pFormatCtx, 0, argv[1], 0);
}
Compile and run it, output looks like:
s#ubuntu-vm:~/Desktop/video-info-dump$ ./vdump a.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'a.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isom
creation_time : 2014-04-23 06:18:02
encoder : FormatFactory : www.pcfreetime.com
Duration: 00:07:20.60, start: 0.000000, bitrate: 1354 kb/s
Stream #0:0(und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 640x480 [SAR 1:1 DAR 4:3], 1228 kb/s, 24 fps, 24 tbr, 24k tbn, 24 tbc (default)
Metadata:
creation_time : 2014-04-23 06:18:02
handler_name : video
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 123 kb/s (default)
Metadata:
creation_time : 2014-04-23 06:18:25
handler_name : sound
Recommend a very good tutorial for ffmpeg and SDL.
#zhm answer was very close, I've made a small update to get the frame rate only. On my end, I need the bit_rate and this is an int64_t value in the AVFormatContext *.
For the FPS, you need to go through the list of streams, probably check whether it's audio or video, and then access the r_frame_rate, which is an AVRational value. The parameter is a nominator and denominator, you can simple divide one by the other to get a double and they even offer a function (av_q2d()) to do it.
int main(int argc, char * argv[])
{
if (argc < 2)
{
printf("No video file.\n");
return -1;
}
av_register_all();
AVFormatContext *pFormatCtx = NULL;
//open video file
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
return -1;
//get stream info
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1;
// dump the whole thing like ffprobe does
//av_dump_format(pFormatCtx, 0, argv[1], 0);
// get the frame rate of each stream
for(int idx(0); idx < pFormatCtx->nb_streams; ++idx)
{
AVStream *s(pFormatCtx->streams[idx]);
std::cout << idx << ". " << s->r_frame_rate.nom
<< " / " << s->r_frame_rate.den
<< " = " << av_q2d(s->r_frame_rate)
<< "\n";
}
// get the video bit rate
std::cout << "bit rate " << pFormatCtx->bit_rate << "\n";
return 0;
}
For more information, you may want to take a look at the avformat.h header where the AVFormatContext and AVStream structures are defined.
You could execute ffmpeg.exe like this ffmpeg -i filename and it would output the framerate if its not variable.
Example:
Input #0, matroska,webm, from 'somerandom.mkv':
Duration: 01:16:10.90, start: 0.000000, bitrate: N/A
Stream #0.0: Video: h264 (High), yuv420p, 720x344 [PAR 1:1 DAR 90:43], 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
Stream #0.1: Audio: aac, 48000 Hz, stereo, s16 (default)
This video has a fps of 25.
To execute a program you can use the answer in https://stackoverflow.com/a/17703834/58553
Source: https://askubuntu.com/questions/110264/how-to-find-frames-per-second-of-any-video-file

Write to dummy video stream using OpenCV

I'm using OpenCV and v4l2loopback library to emulate video devices:
modprobe v4l2loopback devices=2
Then I check what devices I have:
root#blah:~$ v4l2-ctl --list-devices
Dummy video device (0x0000) (platform:v4l2loopback-000):
/dev/video1
Dummy video device (0x0001) (platform:v4l2loopback-001):
/dev/video2
XI100DUSB-SDI (usb-0000:00:14.0-9):
/dev/video0
video0 is my actual camera where I grab frames from, then I plan to process them via OpenCV and write it to video2 (which is a sink I believe).
Here is how I attempt to do so:
int width = 320;
int height = 240;
Mat frame(height, width, CVX_8UC3, Scalar(0, 0, 255));
cvtColor(frame, frame, CVX_BGR2YUV);
int fourcc = CVX_FOURCC('Y', 'U', 'Y', '2');
cout << "Trying to open video for write: " << FLAGS_out_video << endl;
VideoWriter outputVideo = VideoWriter(
FLAGS_out_video, fourcc, 30, frame.size());
if (!outputVideo.isOpened()) {
cerr << "Could not open the output video for write: " << FLAGS_out_video
<< endl;
}
As far as I know video output format should be YUYV (which is equal to YUY2 in OpenCV). Please correct me if I'm wrong. In my code I'm not writing into outputVideo anything yet, just trying to open it for write, but I keep getting outputVideo.isOpened()==false for some reason, no additional errors/info in the output:
root#blah:~$ main --uid='' --in_video='0' --out_video='/dev/video2'
Trying to open video for write: /dev/video2
Could not open the output video for write: /dev/video2
I'd appreciate any advice or help on how to debug/resolve this issue. Thank you in advance!

Can not set the number of channels in VideoCapture in OpenCV

I am trying to use OpenCV to apply treatments on an mj2 file encoded as grayscale uint16 per pixel. Unfortunately, a non disclosure agreement covers this file (which I did not generate myself) and I can not post a sample mj2 file.
The description of my .mj2 file as provided by ffmpeg is:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'data/DEVISSAGE_181.mj2':
Metadata:
major_brand : mjp2
minor_version : 0
compatible_brands: mjp2
creation_time : 2015-10-09 08:07:43
Duration: 00:01:03.45, start: 0.000000, bitrate: 14933 kb/s
Stream #0:0: Video: jpeg2000 (mjp2 / 0x32706A6D), gray16le, 1152x288, lossless, 14933 kb/s, SAR 1:4 DAR 1:1, 5.50 fps, 5.50 tbr, 55 tbn, 55 tbc (default)
Metadata:
creation_time : 2015-10-09 08:07:43
handler_name : Video
encoder : Motion JPEG2000
I take it that gray16le confirms the uint16 encoding somehow.
Here is my C++ code:
#include<iostream>
#include "opencv2/opencv.hpp"
int main(int, char**) {
cv::VideoCapture cap("data/DEVISSAGE_181.mj2"); // open the video file
cap.set(CV_CAP_PROP_FORMAT, CV_16UC1);
cv::Mat frame;
cap.read(frame); // get a new frame from file
std::cout << "frame.rows: " << frame.rows << ", frame.cols: " << frame.cols << ", frame.channels(): " << frame.channels() << std::endl;
return 0;
}
The result of running this code is:
frame.rows: 288, frame.cols: 1152, frame.channels(): 3, frame.depth(): 0
Which indicates a 3 channels, CV_8U pixel encoding. Why does the cap.set instruction appear to be ignored ? What should I do to get the correct encoding ?

OpenCV VideoWriter won't set properly the FPS

In my program, I'm reading from a webcam or a video file, via OpenCV and displaying it via Qt.
I get the fps from the video properties and set the timer accordingly.
I have no problem reading the videos, the fps calibration is good (since the webcam show 0fps, I set it to 30)
But when I record the images, I set the output video's fps to the same as the original video, yet, when I read it in VLC or even Windows Media Player the video is accelerated.
The most curious thing is when I play the recorded video in my program, the fps is good, and the video isn't accelerated.
Here's how I do it :
Constructor()
{
// Initializing the video resources
cv::VideoCapture capture;
cv::VideoWriter writer;
cv::Mat frame;
int fps;
if (webcam)
{
capture.open(0);
fps = 30;
}
else
{
capture.open(inputFilePath);
fps = this->capture.get(CV_CAP_PROP_FPS);
}
// .avi
writer = cv::VideoWriter(outputFilePath, CV_FOURCC('M', 'J', 'P', 'G'), fps, frame.size());
// Defining the refresh timer;
QTimer timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(updateFeed()));
this->timer->start(1000 / fps);
}
updateFeed()
{
// ... display the image in a QLabel ... at a reasonnable speed.
writer.write(frame);
}
Now is there anything I do wrong ?
Thanks