How to get meta data from media?
-
say i have a video, say h.264 (that i have confirmed will indeed play), and i'd like to glean some of its meta data BEFORE playing it. Like it's dimensions ("Resolution"), it's audio bitrate ("AudioBitRate"), and any of the other standard things like duration, title, artist, album etc.
it's my understanding that QMediaPlayer knows nothing of this info (even though it provides APIs for them), until AFTER the underlying media in question has started playing? is there a way to, say "preroll" the media to get the meta data to be available, BEFORE playing? or must i actually, secretly play the media a bit and wait for a "meta data available" singnal?
all i could find on the web suggests that the solution is the latter, that there is no "preroll" API i can call.
This is the code i've come up with:
void QVideoWindow::WaitForMetaData(QMediaPlayer *playerP) { if (!i_got_metaB) { QGraphicsVideoItem vidWid; playerP->setVideoOutput(&vidWid); // metaDataAvailableChanged i_playerP = playerP; QObject::connect( playerP, &QMediaPlayer::mediaStatusChanged, this, &QVideoWindow::onMediaStatusChanged); playerP->setVolume(0); playerP->play(); QEventLoop loop; while (!i_got_metaB) { //IdleDuration(0.1); loop.processEvents(); } QObject::disconnect( playerP, &QMediaPlayer::mediaStatusChanged, this, &QVideoWindow::onMediaStatusChanged); i_playerP = NULL; playerP->stop(); playerP->setPosition(0); playerP->setVideoOutput((QVideoWidget *)NULL); i_got_metaB = false; } } void QVideoWindow::onMediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus) { if (mediaStatus == QMediaPlayer::BufferedMedia) { QString outStr; QTextStream outStream(&outStr); for (auto &item: i_playerP->availableMetaData()) { outStream << item << ", "; } Logf("availz: %s\n", SuperString(outStr).utf8Z()); i_got_metaB = true; } }
At the time that
WaitForMetaData()
is called, i assure you thatQMediaPlayer
has been allocated withQMediaPlayer::VideoSurface
, and the mp4 file path has been properly set withsetMedia()
.I have tried using a
QVideoWidget
instead of aQGraphicsVideoItem
, and I have tried connecting to themetaDataAvailableChanged
signal too, to no avail.the issue is that my slot
onMediaStatusChanged
is never called (and yes it is properly designated as a slot in the header).- this method seems ridiculously convoluted for something so potentially common and mundane
- does anyone have a FUNCTIONING bit of code that does what is needed, that they can paste in here?
thanks!
-dave
-
In windows 10, I can get meta data after
setMedia
, without callingplay
, but it is asynchronousauto player = new QMediaPlayer(this); player->setMedia(QUrl::fromLocalFile("QTSRCDIR/qtwebengine/src/3rdparty/chromium/third_party/webrtc/examples/objc/AppRTCMobile/ios/resources/foreman.mp4")); connect(player, &QMediaPlayer::metaDataAvailableChanged, [=](bool avaliable){ if(avaliable) { for (auto key : player->availableMetaData()) { qDebug() << key << player->metaData(key); } } });
output:
"Duration" QVariant(qlonglong, 10001) "PixelAspectRatio" QVariant(QSize, QSize(1, 1)) "Resolution" QVariant(QSize, QSize(352, 288)) "VideoBitRate" QVariant(uint, 433960) "VideoCodec" QVariant(QString, "H.264 Video") "VideoFrameRate" QVariant(double, 30)
Haven't tried that in other platforms though.
-
that's equivalent to my above code, which does not work. i'm on a mac, by the way.
by "does not work" i mean the slot is never called
-
does anyone know how to use Qt to get meta data from a media file, on mac?
-
@davecotter You should still try @Bonnie code as yours is not exactly the same (you're using a local event loop which is actually not needed if using assynchronous nature of Qt properly, also you call play which Bonnie doesn't).
Also you should connect a slot to https://doc.qt.io/qt-5/qmediaplayer.html#error-1 to see whether you get any errors.
https://doc.qt.io/qt-5/qmediaplayer.html#mediaChanged, https://doc.qt.io/qt-5/qmediaplayer.html#stateChanged and https://doc.qt.io/qt-5/qmediaplayer.html#mediaStatusChanged are also worth checking. -
i suppose it's my fault for not being clear: i have tried a half dozen solutions, INCLUDING the one proposed by @Bonnie , and none work.
can someone who really believes this should work on a mac please try it?
and the point is i need the data BEFORE the function exits, hence my synchronous approach.
note i admit this DOES work fine on windows, but that's not my problem, my problem is mac. on mac the slot is never called.
at the risk of being overly clear / verbose, i added all this code:
// error connect(playerP, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error), [=](QMediaPlayer::Error error) { qDebug() << error; } ); // metaDataAvailableChanged connect(playerP, &QMediaPlayer::metaDataAvailableChanged, [=](bool avaliable) { if (avaliable) { for (auto key : playerP->availableMetaData()) { qDebug() << key << playerP->metaData(key); } } } ); // mediaChanged connect(playerP, &QMediaPlayer::mediaChanged, [=](const QMediaContent &media) { qDebug() << "mediaChanged"; } ); // mediaStatusChanged connect(playerP, &QMediaPlayer::mediaStatusChanged, [=](QMediaPlayer::MediaStatus status) { qDebug() << status; } ); // stateChanged connect(playerP, &QMediaPlayer::stateChanged, [=](QMediaPlayer::State state) { qDebug() << state; } );
on mac: NONE of the slots are called.
on win: they are called as expected:
metaDataAvailableChanged is called first, printing out a nice list of all the meta data
mediaStatusChanged is then called, showing "loadedMedia" -
@davecotter Sorry, I don't have Mac, so can't test.
-
there is a minimal project available in the bug report if someone would like to see the problem.
note the major problem (no signals) only happens on mac, but there ARE problems on windows, which you can see by reading the bug report.