diff --git a/PiOmxTextures.pro b/PiOmxTextures.pro
index c715305..2a90f74 100644
--- a/PiOmxTextures.pro
+++ b/PiOmxTextures.pro
@@ -31,4 +31,21 @@ SUBDIRS = \
piomxtextures_app \
piomxtextures_pocplayer \
piomxtextures_samples \
- piomxtextures_qmlutils
+ piomxtextures_qmlutils \
+ piomxtextures_pocplayer_widget
+
+qtHaveModule(webkit) {
+message("Building wk1 sample...")
+SUBDIRS += piomxtextures_browser_wk
+SUBDIRS += piomxtextures_pocplayer_yt
+}
+
+qtHaveModule(webenginewidgets) {
+#message("Building we sample based on widgets...")
+#SUBDIRS += piomxtextures_browser_we_widget
+}
+
+qtHaveModule(webengine) {
+message("Building we sample based on QML...")
+SUBDIRS += piomxtextures_browser_we
+}
diff --git a/piomxtextures_browser_we/main.cpp b/piomxtextures_browser_we/main.cpp
new file mode 100644
index 0000000..3071331
--- /dev/null
+++ b/piomxtextures_browser_we/main.cpp
@@ -0,0 +1,63 @@
+/*
+ * Project: PiOmxTextures
+ * Author: Luca Carlon
+ * Date: 11.29.2015
+ *
+ * Copyright (c) 2015 Luca Carlon. All rights reserved.
+ *
+ * This file is part of PiOmxTextures.
+ *
+ * PiOmxTextures is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PiOmxTextures is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PiOmxTextures. If not, see .
+ */
+
+/*------------------------------------------------------------------------------
+| includes
++-----------------------------------------------------------------------------*/
+#include
+#include
+#include
+#include
+
+/*------------------------------------------------------------------------------
+| main
++-----------------------------------------------------------------------------*/
+int main(int argc, char* argv[])
+{
+ QApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
+ QApplication a(argc, argv);
+
+ QStringList args = a.arguments();
+ const bool opengl = !args.contains("--no-opengl");
+ args.removeAll("--no-opengl");
+
+ if (opengl) {
+ qDebug("QML QtWebEngine...");
+
+ QQuickView* view = new QQuickView;
+ view->setSource(QUrl("qrc:/poc_main.qml"));
+ view->showFullScreen();
+
+ QObject* o = view->rootObject()->findChild("webEngineView");
+ o->setProperty("url", args.at(1));
+ }
+ else {
+ qDebug("Widget QtWebEngine...");
+
+ QWebEngineView* view = new QWebEngineView;
+ view->load(QUrl(args.at(1)));
+ view->show();
+ }
+
+ return a.exec();
+}
diff --git a/piomxtextures_browser_we/piomxtextures_browser_we.pro b/piomxtextures_browser_we/piomxtextures_browser_we.pro
new file mode 100644
index 0000000..d0fa317
--- /dev/null
+++ b/piomxtextures_browser_we/piomxtextures_browser_we.pro
@@ -0,0 +1,12 @@
+QT += core gui webenginewidgets
+
+TARGET = piomxtextures_browser_we
+TEMPLATE = app
+
+SOURCES += main.cpp
+
+DISTFILES += \
+ poc_main.qml
+
+RESOURCES += \
+ res.qrc
diff --git a/piomxtextures_browser_we/poc_main.qml b/piomxtextures_browser_we/poc_main.qml
new file mode 100644
index 0000000..53e4579
--- /dev/null
+++ b/piomxtextures_browser_we/poc_main.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import QtWebEngine 1.2
+
+Rectangle {
+ anchors.fill: parent
+ color: "red"
+
+ WebEngineView {
+ objectName: "webEngineView"
+ anchors.fill: parent
+ }
+}
diff --git a/piomxtextures_browser_we/res.qrc b/piomxtextures_browser_we/res.qrc
new file mode 100644
index 0000000..40c7545
--- /dev/null
+++ b/piomxtextures_browser_we/res.qrc
@@ -0,0 +1,5 @@
+
+
+ poc_main.qml
+
+
diff --git a/piomxtextures_browser_wk/main.cpp b/piomxtextures_browser_wk/main.cpp
new file mode 100644
index 0000000..493ad5e
--- /dev/null
+++ b/piomxtextures_browser_wk/main.cpp
@@ -0,0 +1,94 @@
+/*
+ * Project: PiOmxTextures
+ * Author: Luca Carlon
+ * Date: 11.29.2015
+ *
+ * Copyright (c) 2015 Luca Carlon. All rights reserved.
+ *
+ * This file is part of PiOmxTextures.
+ *
+ * PiOmxTextures is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PiOmxTextures is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PiOmxTextures. If not, see .
+ */
+
+/*------------------------------------------------------------------------------
+| includes
++-----------------------------------------------------------------------------*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*------------------------------------------------------------------------------
+| main
++-----------------------------------------------------------------------------*/
+int main(int argc, char* argv[])
+{
+ QApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
+ QApplication a(argc, argv);
+
+ QStringList args = a.arguments();
+ const bool opengl = !args.contains("--no-opengl");
+ const bool wk2 = args.contains("--wk2");
+ args.removeAll("--no-opengl");
+ args.removeAll("--wk2");
+ args.removeAll("--wk1"); // Default.
+
+ const QString surl = args.at(1);
+
+ if (!wk2) {
+ QGraphicsWebView* webItem = new QGraphicsWebView;
+ QOpenGLWidget* glViewport = new QOpenGLWidget;
+
+ QGraphicsView* view = new QGraphicsView;
+
+ // Set EGL to 24bit color depth.
+ QSurfaceFormat curSurface = glViewport->format();
+ curSurface.setRedBufferSize(8);
+ curSurface.setGreenBufferSize(8);
+ curSurface.setBlueBufferSize(8);
+ curSurface.setAlphaBufferSize(0);
+ glViewport->setFormat(curSurface);
+
+ view->setRenderHints(QPainter::Antialiasing);
+ view->setScene(new QGraphicsScene);
+ if (opengl)
+ view->setViewport(glViewport);
+ else
+ QObject::connect(qApp, SIGNAL(aboutToQuit()),
+ glViewport, SLOT(deleteLater()));
+ view->showFullScreen();
+
+ view->scene()->setBackgroundBrush(QBrush(Qt::red));
+ view->scene()->setSceneRect(QRectF(0, 0, 1910, 1070));
+ view->scene()->addItem(webItem);
+
+ webItem->setUrl(QUrl(surl));
+ webItem->setMinimumSize(1910, 1070);
+ }
+ else {
+ QQuickView* view = new QQuickView;
+ view->setSource(QUrl("qrc:/main_wk2.qml"));
+ view->show();
+
+ QObject* o = view->rootObject();
+ o->setProperty("url", args.at(1));
+ }
+
+ return a.exec();
+}
diff --git a/piomxtextures_browser_wk/main_wk2.qml b/piomxtextures_browser_wk/main_wk2.qml
new file mode 100644
index 0000000..b258360
--- /dev/null
+++ b/piomxtextures_browser_wk/main_wk2.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import QtWebKit 3.0
+
+WebView {
+ objectName: "webView"
+ anchors.fill: parent
+}
diff --git a/piomxtextures_browser_wk/piomxtextures_browser_wk.pro b/piomxtextures_browser_wk/piomxtextures_browser_wk.pro
new file mode 100644
index 0000000..5ecb76b
--- /dev/null
+++ b/piomxtextures_browser_wk/piomxtextures_browser_wk.pro
@@ -0,0 +1,9 @@
+QT += core gui webkitwidgets quick
+
+TARGET = piomxtextures_browser_wk
+TEMPLATE = app
+
+SOURCES += main.cpp
+
+RESOURCES += \
+ res.qrc
diff --git a/piomxtextures_browser_wk/res.qrc b/piomxtextures_browser_wk/res.qrc
new file mode 100644
index 0000000..bb415a2
--- /dev/null
+++ b/piomxtextures_browser_wk/res.qrc
@@ -0,0 +1,5 @@
+
+
+ main_wk2.qml
+
+
diff --git a/piomxtextures_lib/piomxtextures_lib.pro b/piomxtextures_lib/piomxtextures_lib.pro
index 576fe4d..4a222bd 100644
--- a/piomxtextures_lib/piomxtextures_lib.pro
+++ b/piomxtextures_lib/piomxtextures_lib.pro
@@ -23,7 +23,7 @@
TEMPLATE = lib
-VERSION = 5.2.0
+VERSION = 5.3.0
QT += core core-private gui gui-private opengl quick quick-private
CONFIG += no_private_qt_headers_warning
diff --git a/piomxtextures_pocplayer/img/loader.gif b/piomxtextures_pocplayer/img/loader.gif
new file mode 100644
index 0000000..cc70a7a
Binary files /dev/null and b/piomxtextures_pocplayer/img/loader.gif differ
diff --git a/piomxtextures_pocplayer/main.cpp b/piomxtextures_pocplayer/main.cpp
index 2975a09..42bd5fc 100644
--- a/piomxtextures_pocplayer/main.cpp
+++ b/piomxtextures_pocplayer/main.cpp
@@ -78,6 +78,7 @@ bool show_media(QQuickView* view, QString mediaLocation)
QObject* rootObject = dynamic_cast(view->rootObject());
QObject* mediaOutput = rootObject->findChild("mediaOutput");
QMetaObject::invokeMethod(mediaOutput, "showUrlMedia", Q_ARG(QVariant, uri.toString()));
+ QMetaObject::invokeMethod(mediaOutput, "play");
return true;
}
diff --git a/piomxtextures_pocplayer/qml/POC_MediaOutput.qml b/piomxtextures_pocplayer/qml/POC_MediaOutput.qml
index 9dabe9b..933f7dd 100644
--- a/piomxtextures_pocplayer/qml/POC_MediaOutput.qml
+++ b/piomxtextures_pocplayer/qml/POC_MediaOutput.qml
@@ -24,203 +24,205 @@
import QtQuick 2.0
Item {
- signal controlBarDismissed()
-
- property var currentOutput: videoOutput
-
- width: parent.width
- height: parent.height
- state: "VIDEO"
-
- // The video output component.
- POC_VideoOutput {
- id: videoOutput
- sourceUrl: mediaPlayer
-
- onControlBarDismissed: parent.controlBarDismissed()
- }
-
- // The image output.
- POC_ImageOutput {
- id: imageOutput
- opacity: 0.0
- enabled: false
-
- onControlBarDismissed: parent.controlBarDismissed()
- }
-
- /**
- * Determines the type of media and plays it using the passed path.
- */
- function showLocalMedia(mediaUri) {
- showUrlMedia(mediaUri);
- }
-
- /**
- * Determines the type of media and plays it.
- */
- function showUrlMedia(mediaUri) {
- if (utils.isSupportedAudio(mediaUri))
- showAudio(mediaUri);
- else if (utils.isSupportedImage(mediaUri))
- showImage(mediaUri);
- else if (utils.isSupportedVideo(mediaUri))
- showVideo(mediaUri);
- else
- // TODO: Implement dialog here.
- console.log("Can't handle this media, sorry.");
- }
-
- /**
- * Shows and give focus to the control bar of the currently visible output
- * component.
- */
- function showControlBar() {
- currentOutput.showControlBar();
- }
-
- /**
- * Shows a video on the media output.
- */
- function showVideo(videoUri) {
- state = "VIDEO";
-
- console.log("Setting media source...");
- mediaPlayer.source = videoUri;
-
- //console.log("Sending play command...");
- //mediaPlayer.play();
- }
-
- /**
- * Shows an image on the media output.
- */
- function showImage(imageUri) {
- mediaPlayer.stop();
- state = "IMAGE";
- imageOutput.showImage(imageUri);
- }
-
- /**
- * Starts to play the audio.
- */
- function showAudio(audioUri) {
- state = "VIDEO";
- mediaPlayer.source = audioUri;
- //mediaPlayer.play();
- }
-
- /**
- * Method used to "go on" to next media or inside the media.
- */
- function goOnMedia() {
- currentOutput.goOnMedia();
- }
-
- /**
- * Method to "go back" to prev media or inside the media.
- */
- function goBackMedia() {
- currentOutput.goBackMedia();
- }
-
- /**
- * Method to rotate the output surface.
- */
- function rotateClock() {
- currentOutput.rotateClock();
- }
-
- /**
- * Method to rotate the output surface.
- */
- function rotateCounter() {
- currentOutput.rotateCounter();
- }
-
- onStateChanged: {
- // Disable previous output surface.
- currentOutput.enabled = false;
-
- // Switch.
- switch (state) {
- case "VIDEO":
- currentOutput = videoOutput;
- break;
- case "IMAGE":
- currentOutput = imageOutput;
- break;
- default:
- console.log("Unknown media output status!");
- break;
- }
-
- // Enable the new one.
- currentOutput.enabled = true;
- }
-
- states: [
- State {
- name: "VIDEO"
- PropertyChanges {
- target: videoOutput
- opacity: 1.0
- }
- PropertyChanges {
- target: imageOutput
- opacity: 0.0
- }
- },
- State {
- name: "IMAGE"
- PropertyChanges {
- target: videoOutput
- opacity: 0.0
- }
- PropertyChanges {
- target: imageOutput
- opacity: 1.0
- }
- }
- ]
-
- transitions: [
- Transition {
- from: "VIDEO"
- to: "IMAGE"
-
- NumberAnimation {
- target: videoOutput
- property: "opacity"
- duration: 1000
- easing.type: Easing.InOutQuad
- }
-
- NumberAnimation {
- target: imageOutput
- property: "opacity"
- duration: 1000
- easing.type: Easing.InOutQuad
- }
- },
-
- Transition {
- from: "IMAGE"
- to: "VIDEO"
-
- NumberAnimation {
- target: videoOutput
- property: "opacity"
- duration: 1000
- easing.type: Easing.InOutQuad
- }
-
- NumberAnimation {
- target: imageOutput
- property: "opacity"
- duration: 1000
- easing.type: Easing.InOutQuad
- }
- }
- ]
+ signal controlBarDismissed()
+
+ property var currentOutput: videoOutput
+
+ width: parent.width
+ height: parent.height
+ state: "VIDEO"
+
+ // The video output component.
+ POC_VideoOutput {
+ id: videoOutput
+ sourceUrl: mediaPlayer
+
+ onControlBarDismissed: parent.controlBarDismissed()
+ }
+
+ // The image output.
+ POC_ImageOutput {
+ id: imageOutput
+ opacity: 0.0
+ enabled: false
+
+ onControlBarDismissed: parent.controlBarDismissed()
+ }
+
+ function play() {
+ mediaPlayer.play()
+ }
+
+ /**
+ * Determines the type of media and plays it using the passed path.
+ */
+ function showLocalMedia(mediaUri) {
+ showUrlMedia(mediaUri);
+ }
+
+ /**
+ * Determines the type of media and plays it.
+ */
+ function showUrlMedia(mediaUri) {
+ if (utils.isSupportedAudio(mediaUri))
+ showAudio(mediaUri);
+ else if (utils.isSupportedImage(mediaUri))
+ showImage(mediaUri);
+ else if (utils.isSupportedVideo(mediaUri))
+ showVideo(mediaUri);
+ else {
+ console.log("Unrecognized media: assuming video.");
+ showVideo(mediaUri);
+ }
+ }
+
+ /**
+ * Shows and give focus to the control bar of the currently visible output
+ * component.
+ */
+ function showControlBar() {
+ currentOutput.showControlBar();
+ }
+
+ /**
+ * Shows a video on the media output.
+ */
+ function showVideo(videoUri) {
+ state = "VIDEO";
+
+ console.log("Setting media source...");
+ mediaPlayer.source = videoUri;
+ }
+
+ /**
+ * Shows an image on the media output.
+ */
+ function showImage(imageUri) {
+ mediaPlayer.stop();
+ state = "IMAGE";
+ imageOutput.showImage(imageUri);
+ }
+
+ /**
+ * Starts to play the audio.
+ */
+ function showAudio(audioUri) {
+ state = "VIDEO";
+ mediaPlayer.source = audioUri;
+ mediaPlayer.play();
+ }
+
+ /**
+ * Method used to "go on" to next media or inside the media.
+ */
+ function goOnMedia() {
+ currentOutput.goOnMedia();
+ }
+
+ /**
+ * Method to "go back" to prev media or inside the media.
+ */
+ function goBackMedia() {
+ currentOutput.goBackMedia();
+ }
+
+ /**
+ * Method to rotate the output surface.
+ */
+ function rotateClock() {
+ currentOutput.rotateClock();
+ }
+
+ /**
+ * Method to rotate the output surface.
+ */
+ function rotateCounter() {
+ currentOutput.rotateCounter();
+ }
+
+ onStateChanged: {
+ // Disable previous output surface.
+ currentOutput.enabled = false;
+
+ // Switch.
+ switch (state) {
+ case "VIDEO":
+ currentOutput = videoOutput;
+ break;
+ case "IMAGE":
+ currentOutput = imageOutput;
+ break;
+ default:
+ console.log("Unknown media output status!");
+ break;
+ }
+
+ // Enable the new one.
+ currentOutput.enabled = true;
+ }
+
+ states: [
+ State {
+ name: "VIDEO"
+ PropertyChanges {
+ target: videoOutput
+ opacity: 1.0
+ }
+ PropertyChanges {
+ target: imageOutput
+ opacity: 0.0
+ }
+ },
+ State {
+ name: "IMAGE"
+ PropertyChanges {
+ target: videoOutput
+ opacity: 0.0
+ }
+ PropertyChanges {
+ target: imageOutput
+ opacity: 1.0
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "VIDEO"
+ to: "IMAGE"
+
+ NumberAnimation {
+ target: videoOutput
+ property: "opacity"
+ duration: 1000
+ easing.type: Easing.InOutQuad
+ }
+
+ NumberAnimation {
+ target: imageOutput
+ property: "opacity"
+ duration: 1000
+ easing.type: Easing.InOutQuad
+ }
+ },
+
+ Transition {
+ from: "IMAGE"
+ to: "VIDEO"
+
+ NumberAnimation {
+ target: videoOutput
+ property: "opacity"
+ duration: 1000
+ easing.type: Easing.InOutQuad
+ }
+
+ NumberAnimation {
+ target: imageOutput
+ property: "opacity"
+ duration: 1000
+ easing.type: Easing.InOutQuad
+ }
+ }
+ ]
}
diff --git a/piomxtextures_pocplayer/qml/main.qml b/piomxtextures_pocplayer/qml/main.qml
index 39aeec4..fb97f9a 100644
--- a/piomxtextures_pocplayer/qml/main.qml
+++ b/piomxtextures_pocplayer/qml/main.qml
@@ -108,6 +108,12 @@ Rectangle {
onUrlSelected: mediaOutput.showUrlMedia(url)
}
+ AnimatedImage {
+ anchors.centerIn: parent
+ source: "qrc:/img/loader.gif"
+ visible: mediaPlayer.status === MediaPlayer.Buffering
+ }
+
// These are shortcuts for common functionalities.
Keys.onPressed: {
console.log("Main interface is processing the key...");
diff --git a/piomxtextures_pocplayer/qml/main_multipleanim.qml b/piomxtextures_pocplayer/qml/main_multipleanim.qml
index b408ed3..8b3ec38 100644
--- a/piomxtextures_pocplayer/qml/main_multipleanim.qml
+++ b/piomxtextures_pocplayer/qml/main_multipleanim.qml
@@ -34,7 +34,7 @@ Rectangle {
Video {
id: video1
- x: 0; y: 0; z: 1; width: parent.width; height: parent.height
+ x: 0; y: 0; z: 0.5; width: parent.width; height: parent.height
opacity: 1
fillMode: VideoOutput.Stretch
onStopped: play()
@@ -70,7 +70,7 @@ Rectangle {
logger.debug("Moving 1...");
videoFront.z = 0;
- videoBack.z = 1;
+ videoBack.z = 0.5;
videoFront.opacity = 1.0;
videoBack.opacity = 1.0;
diff --git a/piomxtextures_pocplayer/resources_imgs.qrc b/piomxtextures_pocplayer/resources_imgs.qrc
index 1eb5bb0..31223bf 100644
--- a/piomxtextures_pocplayer/resources_imgs.qrc
+++ b/piomxtextures_pocplayer/resources_imgs.qrc
@@ -18,5 +18,6 @@
img/2_720p.jpg
img/3_720p.jpg
img/4_720p.jpg
+ img/loader.gif
diff --git a/piomxtextures_pocplayer_widget/main.cpp b/piomxtextures_pocplayer_widget/main.cpp
new file mode 100644
index 0000000..7034726
--- /dev/null
+++ b/piomxtextures_pocplayer_widget/main.cpp
@@ -0,0 +1,44 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
+ QApplication a(argc, argv);
+
+ const QString fileAbsPath = a.arguments().at(1);
+ qDebug("Opening %s...", qPrintable(fileAbsPath));
+
+ QMediaPlayer p;
+ p.setMedia(QMediaContent(QUrl(fileAbsPath)));
+
+ QGraphicsVideoItem* item = new QGraphicsVideoItem;
+ QGraphicsScene* scene = new QGraphicsScene;
+ scene->addText("TEST");
+ p.setVideoOutput(item);
+ scene->addItem(item);
+ scene->addRect(0, 0, 100, 100, QPen(Qt::red), QBrush(Qt::red));
+ item->setPos(0, 0);
+
+ //QImage image(1920, 1080, QImage::Format_ARGB32);
+ //image.fill(Qt::blue);
+
+ //QPainter painter(&image);
+ //painter.setRenderHint(QPainter::Antialiasing);
+ //scene->render(&painter);
+
+ QGraphicsView view(scene);
+ //view.scene()->addItem(item);
+ view.setViewport(new QOpenGLWidget);
+ view.show();
+
+ p.play();
+
+ return a.exec();
+}
diff --git a/piomxtextures_pocplayer_widget/piomxtextures_pocplayer_widget.pro b/piomxtextures_pocplayer_widget/piomxtextures_pocplayer_widget.pro
new file mode 100644
index 0000000..64fd561
--- /dev/null
+++ b/piomxtextures_pocplayer_widget/piomxtextures_pocplayer_widget.pro
@@ -0,0 +1,6 @@
+QT += core gui multimediawidgets opengl
+
+TARGET = POCPlayerWidget
+TEMPLATE = app
+
+SOURCES += main.cpp
diff --git a/piomxtextures_pocplayer_yt/main.cpp b/piomxtextures_pocplayer_yt/main.cpp
new file mode 100644
index 0000000..b4168c6
--- /dev/null
+++ b/piomxtextures_pocplayer_yt/main.cpp
@@ -0,0 +1,57 @@
+/*------------------------------------------------------------------------------
+| includes
++-----------------------------------------------------------------------------*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "poc_bridge.h"
+
+/*------------------------------------------------------------------------------
+| main
++-----------------------------------------------------------------------------*/
+int main(int argc, char** argv) {
+ qputenv("QT_QPA_EGLFS_FORCE888", "1");
+
+ QApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
+ QApplication a(argc, argv);
+
+ const QStringList args = a.arguments();
+ if (args.size() < 2) {
+ log_err("Video ID is missing.");
+ return 1;
+ }
+
+ const QString videoId = args.at(1);
+ log_info("Starting playback of video ID %s...", qPrintable(videoId));
+
+ POC_Bridge bridge(videoId);
+
+ QGraphicsWebView* webItem = new QGraphicsWebView;
+ webItem->page()->mainFrame()->addToJavaScriptWindowObject("bridge", &bridge);
+
+ QOpenGLWidget* glViewport = new QOpenGLWidget;
+
+ QGraphicsView* view = new QGraphicsView;
+ view->setFrameShape(QFrame::NoFrame);
+
+ view->setRenderHints(QPainter::Antialiasing);
+ view->setScene(new QGraphicsScene);
+ view->setViewport(glViewport);
+ view->showFullScreen();
+
+ view->scene()->setBackgroundBrush(QBrush(Qt::red));
+ view->scene()->setSceneRect(QRectF(0, 0, 1920, 1080));
+ view->scene()->addItem(webItem);
+
+ webItem->setUrl(QUrl("qrc:/player.html"));
+ webItem->setMinimumSize(1920, 1080);
+
+ return a.exec();
+}
diff --git a/piomxtextures_pocplayer_yt/piomxtextures_pocplayer_yt.pro b/piomxtextures_pocplayer_yt/piomxtextures_pocplayer_yt.pro
new file mode 100644
index 0000000..216f267
--- /dev/null
+++ b/piomxtextures_pocplayer_yt/piomxtextures_pocplayer_yt.pro
@@ -0,0 +1,15 @@
+QT += core gui webkitwidgets quick
+
+TARGET = piomxtextures_pocplayer_yt
+TEMPLATE = app
+
+INCLUDEPATH += ../3rdparty/LightLogger
+
+SOURCES += main.cpp \
+ poc_bridge.cpp
+
+RESOURCES += \
+ res.qrc
+
+HEADERS += \
+ poc_bridge.h
diff --git a/piomxtextures_pocplayer_yt/player.html b/piomxtextures_pocplayer_yt/player.html
new file mode 100644
index 0000000..02a0c1b
--- /dev/null
+++ b/piomxtextures_pocplayer_yt/player.html
@@ -0,0 +1,111 @@
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
diff --git a/piomxtextures_pocplayer_yt/poc_bridge.cpp b/piomxtextures_pocplayer_yt/poc_bridge.cpp
new file mode 100644
index 0000000..d1a14c1
--- /dev/null
+++ b/piomxtextures_pocplayer_yt/poc_bridge.cpp
@@ -0,0 +1,25 @@
+/*------------------------------------------------------------------------------
+| includes
++-----------------------------------------------------------------------------*/
+#include
+
+#include "poc_bridge.h"
+
+/*------------------------------------------------------------------------------
+| POC_Bridge::POC_Bridge
++-----------------------------------------------------------------------------*/
+POC_Bridge::POC_Bridge(const QString& videoId, QObject* parent) :
+ QObject(parent),
+ m_videoId(videoId)
+{
+ // Do nothing.
+}
+
+/*------------------------------------------------------------------------------
+| POC_Bridge::onPlayerReady
++-----------------------------------------------------------------------------*/
+void POC_Bridge::onPlayerReady()
+{
+ log_info("YouTube player ready.");
+ emit playVideoId(m_videoId);
+}
diff --git a/piomxtextures_pocplayer_yt/poc_bridge.h b/piomxtextures_pocplayer_yt/poc_bridge.h
new file mode 100644
index 0000000..3164755
--- /dev/null
+++ b/piomxtextures_pocplayer_yt/poc_bridge.h
@@ -0,0 +1,27 @@
+#ifndef POC_BRIDGE_H
+#define POC_BRIDGE_H
+
+/*------------------------------------------------------------------------------
+| includes
++-----------------------------------------------------------------------------*/
+#include
+
+/*------------------------------------------------------------------------------
+| POC_Bridge class
++-----------------------------------------------------------------------------*/
+class POC_Bridge : public QObject
+{
+ Q_OBJECT
+public:
+ POC_Bridge(const QString& videoId, QObject* parent = 0);
+
+ Q_INVOKABLE void onPlayerReady();
+
+signals:
+ void playVideoId(const QString& videoId);
+
+private:
+ QString m_videoId;
+};
+
+#endif // POC_BRIDGE_H
diff --git a/piomxtextures_pocplayer_yt/res.qrc b/piomxtextures_pocplayer_yt/res.qrc
new file mode 100644
index 0000000..3ad3000
--- /dev/null
+++ b/piomxtextures_pocplayer_yt/res.qrc
@@ -0,0 +1,5 @@
+
+
+ player.html
+
+
diff --git a/piomxtextures_qmlutils/piomxtextures_qmlutils.pro b/piomxtextures_qmlutils/piomxtextures_qmlutils.pro
index 3d85047..e85b683 100644
--- a/piomxtextures_qmlutils/piomxtextures_qmlutils.pro
+++ b/piomxtextures_qmlutils/piomxtextures_qmlutils.pro
@@ -28,7 +28,7 @@ DEFINES += VERSION=\\\"$$VERSION\\\"
QT += quick qml multimedia
CONFIG += qt plugin
-CONFIG += -std=c++11
+QMAKE_CXXFLAGS += -std=c++11
INCLUDEPATH += \
$$_PRO_FILE_PWD_/../3rdparty/LightLogger \
diff --git a/piomxtextures_qmlutils/pot_videoprobe.cpp b/piomxtextures_qmlutils/pot_videoprobe.cpp
index 00bd491..490f6cf 100644
--- a/piomxtextures_qmlutils/pot_videoprobe.cpp
+++ b/piomxtextures_qmlutils/pot_videoprobe.cpp
@@ -36,9 +36,6 @@ POT_VideoProbe::POT_VideoProbe(QObject* parent) :
QVideoProbe(parent)
{
// Do nothing.
-
- connect(this, SIGNAL(videoFrameProbed(QVideoFrame)),
- this, SLOT(onVideoFrameProbed(QVideoFrame)));
}
/*------------------------------------------------------------------------------
@@ -70,11 +67,3 @@ void POT_VideoProbe::setSource(QObject* source)
emit sourceChanged();
}
-
-/*------------------------------------------------------------------------------
-| POT_VideoProbe::onVideoFrameProbed
-+-----------------------------------------------------------------------------*/
-void POT_VideoProbe::onVideoFrameProbed(const QVideoFrame &frame)
-{
- emit videoFrameDecoded();
-}
diff --git a/piomxtextures_qmlutils/pot_videoprobe.h b/piomxtextures_qmlutils/pot_videoprobe.h
index df28ba2..18aab31 100644
--- a/piomxtextures_qmlutils/pot_videoprobe.h
+++ b/piomxtextures_qmlutils/pot_videoprobe.h
@@ -47,10 +47,6 @@ class POT_VideoProbe : public QVideoProbe
signals:
void sourceChanged();
- void videoFrameDecoded();
-
-private slots:
- void onVideoFrameProbed(const QVideoFrame& frame);
private:
QObject* m_source;
diff --git a/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp b/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp
index 0396894..9b53ab5 100644
--- a/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp
+++ b/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp
@@ -40,6 +40,8 @@
#include
#include
+#include
+
#include
#include
#include
@@ -91,6 +93,10 @@ OpenMAXILPlayerControl::OpenMAXILPlayerControl(QObject *parent)
this, SIGNAL(metaDataChanged(QVariantMap)));
connect(m_mediaProcessor, SIGNAL(streamLengthChanged(qint64)),
this, SIGNAL(durationChanged(qint64)));
+ connect(m_mediaProcessor, SIGNAL(bufferStatusChanged(int)),
+ this, SIGNAL(bufferStatusChanged(int)));
+ connect(m_mediaProcessor, SIGNAL(availablePlaybackRangesChanged(QMediaTimeRange)),
+ this, SIGNAL(availablePlaybackRangesChanged(QMediaTimeRange)));
}
/*------------------------------------------------------------------------------
@@ -100,7 +106,7 @@ OpenMAXILPlayerControl::~OpenMAXILPlayerControl()
{
log_dtor_func;
- delete m_mediaProcessor;
+ m_mediaProcessor->deleteLater();
m_mediaProcessor = NULL;
}
@@ -111,6 +117,9 @@ void OpenMAXILPlayerControl::play()
{
logi_debug_func;
m_mediaProcessor->play();
+
+ // FIXME: This should be removed.
+ emit availablePlaybackRangesChanged(QMediaTimeRange(0, duration()));
}
/*------------------------------------------------------------------------------
@@ -224,7 +233,7 @@ QMediaTimeRange OpenMAXILPlayerControl::availablePlaybackRanges() const
log_debug_func;
// TODO: Implement.
- return QMediaTimeRange();
+ return QMediaTimeRange(0, duration());
}
/*------------------------------------------------------------------------------
@@ -235,7 +244,7 @@ int OpenMAXILPlayerControl::bufferStatus() const
log_debug_func;
// TODO: Implement.
- return 0;
+ return 100;
}
/*------------------------------------------------------------------------------
@@ -265,8 +274,7 @@ bool OpenMAXILPlayerControl::isSeekable() const
{
log_debug_func;
- // TODO: Implement.
- return false;
+ return m_mediaProcessor->isSeekable();
}
/*------------------------------------------------------------------------------
@@ -293,6 +301,7 @@ qreal OpenMAXILPlayerControl::playbackRate() const
void OpenMAXILPlayerControl::setPlaybackRate(qreal rate)
{
log_debug_func;
+ log_debug("Playback rate: %f.", rate);
// TODO: Implement.
}
diff --git a/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp b/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp
index 78ed867..d52958d 100644
--- a/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp
+++ b/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp
@@ -234,7 +234,7 @@ void OpenMAXILVideoRendererControl::onTexturesReady()
);
m_surfaceFormat = new QVideoSurfaceFormat(
texture->m_textureSize,
- QVideoFrame::Format_RGB565,
+ QVideoFrame::Format_ARGB32,
QAbstractVideoBuffer::GLTextureHandle
);
@@ -276,8 +276,15 @@ void OpenMAXILVideoRendererControl::onUpdateTriggered()
return;
if (UNLIKELY(!m_surface || !m_frame || !m_surfaceFormat))
return;
- if (UNLIKELY(!m_surface->isActive() && !m_surface->start(*m_surfaceFormat)))
- log_warn("Failed to start surface.");
+ if (UNLIKELY(!m_surface->isActive() && !m_surface->start(*m_surfaceFormat))) {
+ log_warn("Failed to start surface: %d.", m_surface->error());
+ QList fs = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle);
+ foreach (QVideoFrame::PixelFormat f, fs) {
+ log_warn("Supported format: %d.", f);
+ }
+
+ return;
+ }
const GLuint t = m_mediaProcessor->m_provider->getNextTexture();
diff --git a/piomxtextures_samples/loader.gif b/piomxtextures_samples/loader.gif
new file mode 100644
index 0000000..cc70a7a
Binary files /dev/null and b/piomxtextures_samples/loader.gif differ
diff --git a/piomxtextures_samples/piomxtextures_samples.pro b/piomxtextures_samples/piomxtextures_samples.pro
index 4f1303d..4416363 100644
--- a/piomxtextures_samples/piomxtextures_samples.pro
+++ b/piomxtextures_samples/piomxtextures_samples.pro
@@ -31,4 +31,5 @@ DISTFILES += \
audio_simple.qml \
video_concurrent.qml \
video_loop.qml \
- video_loop_position.qml
+ video_loop_position.qml \
+ webkit_simple.qml
diff --git a/piomxtextures_samples/video_probe.qml b/piomxtextures_samples/video_probe.qml
new file mode 100644
index 0000000..0a4991b
--- /dev/null
+++ b/piomxtextures_samples/video_probe.qml
@@ -0,0 +1,70 @@
+/*
+ * Project: PiOmxTextures
+ * Author: Luca Carlon
+ * Date: 03.19.2016
+ *
+ * Copyright (c) 2019 Luca Carlon. All rights reserved.
+ *
+ * This file is part of PiOmxTextures.
+ *
+ * PiOmxTextures is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PiOmxTextures is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PiOmxTextures. If not, see .
+ */
+
+import QtQuick 2.2
+import QtQml 2.0
+import QtQuick.Window 2.1
+import QtMultimedia 5.0
+import PiOmxTexturesQmlUtils 0.1
+
+Rectangle {
+ property string uri
+
+ id: root
+ objectName: "root"
+ visible: true
+ color: "black"
+
+ Component.onCompleted: {
+ var arguments = Qt.application.arguments;
+ if (arguments.length < 3) {
+ console.log("Too few arguments.");
+ Qt.quit();
+ }
+
+ uri = arguments[1];
+ }
+
+ VideoOutput {
+ id: myVideo
+ anchors.fill: parent
+ visible: true
+ source: mediaPlayer
+ }
+
+ MediaPlayer {
+ id: mediaPlayer
+ source: uri
+ autoPlay: true
+
+ onStopped: {
+ console.log("Looping...")
+ mediaPlayer.play()
+ }
+ }
+
+ POT_VideoProbe {
+ source: mediaPlayer
+ onVideoFrameProbed: console.log("Frame probed!")
+ }
+}
diff --git a/piomxtextures_samples/video_simple_buffering.qml b/piomxtextures_samples/video_simple_buffering.qml
new file mode 100644
index 0000000..ec61050
--- /dev/null
+++ b/piomxtextures_samples/video_simple_buffering.qml
@@ -0,0 +1,89 @@
+/*
+ * Project: PiOmxTextures
+ * Author: Luca Carlon
+ * Date: 08.22.2015
+ *
+ * Copyright (c) 2015 Luca Carlon. All rights reserved.
+ *
+ * This file is part of PiOmxTextures.
+ *
+ * PiOmxTextures is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PiOmxTextures is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PiOmxTextures. If not, see .
+ */
+
+import QtQuick 2.2
+import QtQml 2.0
+import QtQuick.Window 2.1
+import QtMultimedia 5.0
+
+/**
+ * This sample creates a Video surface including a MediaPlayer, plays continuously
+ * and asks for the current position every 10ms.
+ */
+Rectangle {
+ property string uri
+
+ id: root
+ objectName: "root"
+ visible: true
+ color: "black"
+
+ Component.onCompleted: {
+ var arguments = Qt.application.arguments;
+ if (arguments.length < 3) {
+ console.log("Too few arguments.");
+ Qt.quit();
+ }
+
+ uri = arguments[1]
+ }
+
+ Video {
+ id: myVideo
+ anchors.fill: parent
+ visible: true
+
+ source: uri
+ autoPlay: true
+
+ onStopped: {
+ console.log("Stopped.");
+ myVideo.seek(0);
+ myVideo.play();
+ }
+
+ onStatusChanged: {
+ console.log("Status changed to: " + status + ".");
+ }
+ }
+
+ AnimatedImage {
+ anchors.centerIn: parent
+ source: "loader.gif"
+ visible: myVideo.status == MediaPlayer.Buffering
+ }
+
+ Timer {
+ id: videoInterval
+ interval: 1000
+ repeat: true
+ running: myVideo.playbackState === MediaPlayer.PlayingState
+
+ onTriggered: {
+ console.log("Requesting position...");
+ var position = myVideo.position;
+
+ console.log("Position: " + position + ".");
+ }
+ }
+}
diff --git a/piomxtextures_samples/webkit_simple.qml b/piomxtextures_samples/webkit_simple.qml
new file mode 100644
index 0000000..edfb893
--- /dev/null
+++ b/piomxtextures_samples/webkit_simple.qml
@@ -0,0 +1,41 @@
+/*
+ * Project: PiOmxTextures
+ * Author: Luca Carlon
+ * Date: 10.08.2015
+ *
+ * Copyright (c) 2015 Luca Carlon. All rights reserved.
+ *
+ * This file is part of PiOmxTextures.
+ *
+ * PiOmxTextures is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PiOmxTextures is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PiOmxTextures. If not, see .
+ */
+
+import QtQuick 2.0
+import QtWebKit 3.0
+
+WebView {
+ id: main
+
+ Component.onCompleted: {
+ var arguments = Qt.application.arguments;
+ if (arguments.length < 3) {
+ console.log("Too few arguments.");
+ Qt.quit();
+ }
+
+ main.url = arguments[2]
+ }
+
+ url: "http://www.google.com"
+}
diff --git a/piomxtextures_src/omx_mediaprocessor.cpp b/piomxtextures_src/omx_mediaprocessor.cpp
index f91c06f..2ae9b58 100644
--- a/piomxtextures_src/omx_mediaprocessor.cpp
+++ b/piomxtextures_src/omx_mediaprocessor.cpp
@@ -155,7 +155,7 @@ OMX_MediaProcessor::OMX_MediaProcessor(OMX_EGLBufferProviderSh provider) :
m_provider(provider),
#define THREADED_GL
#ifdef THREADED_GL
- m_thread(new QThread),
+ m_thread(new OMX_QThread),
#else
m_thread(QOpenGLContext::globalShareContext()->thread()),
#endif
@@ -205,11 +205,16 @@ OMX_MediaProcessor::OMX_MediaProcessor(OMX_EGLBufferProviderSh provider) :
"OMX_MediaProcessor::OMX_MediaStatus");
const int gpu_mem = get_mem_gpu();
- const int min_gpu_mem = 256;
+ const int min_gpu_mem = 192;
if (gpu_mem > 0 && gpu_mem < min_gpu_mem)
LOG_WARNING(LOG_TAG, "Only %dM of gpu_mem is configured. Try running"
" \"sudo raspi-config\" and ensure that \"memory_split\" has "
"a value of %d or greater\n", gpu_mem, min_gpu_mem);
+ if (!QOpenGLContext::globalShareContext()) {
+ log_err("Failed to get shared context. Enable it.");
+ abort();
+ }
+
m_RBP->Initialize();
m_OMX->Initialize();
@@ -221,6 +226,7 @@ OMX_MediaProcessor::OMX_MediaProcessor(OMX_EGLBufferProviderSh provider) :
moveToThread(m_thread);
m_thread->start();
+ setVolume(1, true);
INVOKE("init", INVOKE_CONN);
}
@@ -262,7 +268,7 @@ OMX_MediaProcessor::~OMX_MediaProcessor()
+-----------------------------------------------------------------------------*/
QString OMX_MediaProcessor::filename()
{
- return m_filename;
+ return m_sourceUrl;
}
/*------------------------------------------------------------------------------
@@ -307,7 +313,7 @@ bool OMX_MediaProcessor::setFilenameInt(const QString& filename)
log_verbose_func;
QMutexLocker locker(&m_sendCmd);
- if (m_filename == filename)
+ if (m_sourceUrl == filename)
return true;
switch (m_state) {
@@ -324,15 +330,22 @@ bool OMX_MediaProcessor::setFilenameInt(const QString& filename)
}
LOG_VERBOSE(LOG_TAG, "Opening %s...", qPrintable(filename));
+ if (filename.isEmpty() || filename.isNull() || filename.size() <= 0) {
+ log_err("Empty media URL.");
+ m_sourceUrl = QString();
+ return false;
+ }
+
+ m_sourceUrl = filename;
// It seems that omxplayer expects path and not local URIs.
QUrl url(filename);
if (url.isLocalFile() && filename.startsWith("file://"))
- m_filename = url.path();
+ m_sourceUrl = url.path();
//m_omx_reader = new OMX_Reader;
- if (!m_omx_reader->Open(m_filename.toStdString(), true)) {
- log_err("Failed to open source %s.", qPrintable(m_filename));
+ if (!m_omx_reader->Open(m_sourceUrl.toStdString(), true)) {
+ log_err("Failed to open source %s.", qPrintable(m_sourceUrl));
return false;
}
@@ -341,7 +354,11 @@ bool OMX_MediaProcessor::setFilenameInt(const QString& filename)
// decides.
LOG_VERBOSE(LOG_TAG, "Copy metatada...");
convertMetaData();
+
emit metadataChanged(m_metadata);
+ emit streamLengthChanged(m_omx_reader->GetStreamLength());
+ //emit bufferStatusChanged(100);
+ //emit availablePlaybackRangesChanged(QMediaTimeRange(0, m_omx_reader->GetStreamLength()));
// Set the mute property according to current state.
m_player_audio->SetMuted(m_muted);
@@ -358,7 +375,6 @@ bool OMX_MediaProcessor::setFilenameInt(const QString& filename)
m_packetAfterSeek = false;
m_seekFlush = false;
- LOG_VERBOSE(LOG_TAG, "Initializing OMX clock...");
if (!m_av_clock->OMXInitialize())
return false;
@@ -381,16 +397,8 @@ bool OMX_MediaProcessor::setFilenameInt(const QString& filename)
m_omx_reader->SetActiveStream(OMXSTREAM_AUDIO, m_audio_index_use);
#endif
- // Seek on start?
-#if 0
- if (m_seek_pos !=0 && m_omx_reader->CanSeek()) {
- printf("Seeking start of video to %i seconds\n", m_seek_pos);
- m_omx_reader->SeekTime(m_seek_pos * 1000.0f, false, &startpts); // from seconds to DVD_TIME_BASE
- }
-#endif
-
if (m_has_video) {
- LOG_VERBOSE(LOG_TAG, "Opening video using OMX...");
+ log_verbose("Opening video using OMX...");
if (!m_player_video->Open(m_av_clock, *m_videoConfig))
return false;
}
@@ -416,6 +424,7 @@ bool OMX_MediaProcessor::setFilenameInt(const QString& filename)
m_subtitle_index = m_omx_reader->SubtitleStreamCount() - 1;
#endif
+ // omxplayer is doing this twice for some reason.
m_omx_reader->GetHints(OMXSTREAM_AUDIO, m_audioConfig->hints);
#if 0
@@ -440,13 +449,16 @@ bool OMX_MediaProcessor::setFilenameInt(const QString& filename)
else
m_audioConfig->device = "omx:hdmi";
- log_verbose("Opening audio using OMX...");
- log_verbose("Using %s output device...", m_audioConfig->device.c_str());
if (m_has_audio) {
- if (!m_player_audio->Open(m_av_clock, *m_audioConfig, m_omx_reader))
+ log_verbose("Opening audio using OMX...");
+ log_verbose("Using %s output device...", m_audioConfig->device.c_str());
+ if (!m_player_audio->Open(m_av_clock, *m_audioConfig, m_omx_reader)) {
+ log_warn("Failed to open audio.");
return false;
- if (m_has_audio)
- m_player_audio->SetCurrentVolume(m_volume, true);
+ }
+
+ //m_player_audio->SetCurrentVolume(m_volume, true);
+ //setVolume(1);
}
setState(STATE_STOPPED);
@@ -479,12 +491,16 @@ bool OMX_MediaProcessor::playInt()
setMediaStatus(MEDIA_STATUS_LOADED);
setState(STATE_PLAYING);
- m_av_clock->OMXPause();
- m_av_clock->OMXStateExecute();
- m_av_clock->OMXResume();
+ //m_av_clock->OMXPause();
+ //m_av_clock->OMXStateExecute();
+ //m_av_clock->OMXResume();
+
+ //m_av_clock->OMXReset(m_has_video, m_has_audio);
+ //m_av_clock->OMXStateExecute();
LOG_VERBOSE(LOG_TAG, "Starting thread.");
QtConcurrent::run(&m_tpool, this, &OMX_MediaProcessor::mediaDecoding);
+ return true;
}
default:
return false;
@@ -644,6 +660,15 @@ bool OMX_MediaProcessor::seek(qint64 position)
return true;
}
+/*------------------------------------------------------------------------------
+| OMX_MediaProcessor::isSeekable
++-----------------------------------------------------------------------------*/
+bool OMX_MediaProcessor::isSeekable() {
+ if (UNLIKELY(!m_omx_reader))
+ return false;
+ return m_omx_reader->CanSeek();
+}
+
/*------------------------------------------------------------------------------
| OMX_MediaProcessor::currentPosition
+-----------------------------------------------------------------------------*/
@@ -712,32 +737,40 @@ void OMX_MediaProcessor::mediaDecoding()
{
// See description in the qmakefile.
//#define ENABLE_PROFILE_MAIN_LOOP
-//#define ENABLE_PAUSE_FOR_BUFFERING
+#define ENABLE_PAUSE_FOR_BUFFERING
- LOG_VERBOSE(LOG_TAG, "Decoding thread started.");
+ log_verbose("Decoding thread started.");
emit playbackStarted();
// Prealloc.
#ifdef ENABLE_PAUSE_FOR_BUFFERING
- float stamp = 0;
- float audio_pts = 0;
- float video_pts = 0;
-
- float audio_fifo = 0;
- float video_fifo = 0;
- float threshold = 0;
- bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false;
- float m_threshold = 1.0f; //std::min(0.1f, audio_fifo_size * 0.1f);
+ float stamp = 0;
+ float audio_pts = 0;
+ float video_pts = 0;
+ float audio_fifo = 0;
+ float video_fifo = 0;
+ float threshold = 0;
+ float m_threshold = m_audioConfig->is_live ? 0.7f : 0.2f;
+
+ bool audio_fifo_low = false;
+ bool video_fifo_low = false;
+ bool audio_fifo_high = false;
+ bool video_fifo_high = false;
#endif // ENABLE_PAUSE_FOR_BUFFERING
- bool sentStarted = false;
- double last_seek_pos = 0;
+ bool sentStarted = true;
bool sendEos = false;
- double m_last_check_time = 0.0;
+
+ double last_seek_pos = 0;
+ double last_check_time = 0.0;
m_av_clock->OMXReset(m_has_video, m_has_audio);
m_av_clock->OMXStateExecute();
- sentStarted = true;
+
+#ifndef ENABLE_PAUSE_FOR_BUFFERING
+ // FIXME: This should not be placed here.
+ setMediaStatus(OMX_MediaStatus::MEDIA_STATUS_BUFFERED);
+#endif // ENABLE_PAUSE_FOR_BUFFERING
while (!m_pendingStop) {
#ifdef ENABLE_PROFILE_MAIN_LOOP
@@ -760,9 +793,9 @@ void OMX_MediaProcessor::mediaDecoding()
double now = m_av_clock->GetAbsoluteClock();
bool update = false;
- if (m_last_check_time == 0.0 || m_last_check_time + DVD_MSEC_TO_TIME(20) <= now) {
+ if (last_check_time == 0.0 || last_check_time + DVD_MSEC_TO_TIME(20) <= now) {
update = true;
- m_last_check_time = now;
+ last_check_time = now;
}
// If a request is pending then consider done here.
@@ -790,11 +823,8 @@ void OMX_MediaProcessor::mediaDecoding()
//seek_pos *= 1000.0;
- if(m_omx_reader->SeekTime((int)seek_pos, m_incrMs < 0.0f, &startpts))
- {
+ if (m_omx_reader->SeekTime((int)seek_pos, m_incrMs < 0.0f, &startpts)) {
unsigned t = (unsigned)(startpts*1e-6);
- //auto dur = m_omx_reader->GetStreamLength() / 1000;
-
log_info("Seek to: %02d:%02d:%02d", (t/3600), (t/60)%60, t%60);
flushStreams(startpts);
}
@@ -809,9 +839,8 @@ void OMX_MediaProcessor::mediaDecoding()
break;
}
- m_incrMs = 0;
-
#ifdef ENABLE_PAUSE_FOR_BUFFERING
+ setMediaStatus(OMX_MediaStatus::MEDIA_STATUS_BUFFERING);
m_av_clock->OMXPause();
#else
m_av_clock->OMXResume();
@@ -823,9 +852,10 @@ void OMX_MediaProcessor::mediaDecoding()
#endif
unsigned t = (unsigned)(startpts*1e-6);
- LOG_VERBOSE(LOG_TAG, "Seeked to: %02d:%02d:%02d", (t/3600), (t/60)%60, t%60);
+ log_verbose("Seeked to: %02d:%02d:%02d", (t/3600), (t/60)%60, t%60);
m_packetAfterSeek = false;
m_seekFlush = false;
+ m_incrMs = 0;
}
else if (UNLIKELY(m_packetAfterSeek && TRICKPLAY(m_av_clock->OMXPlaySpeed()))) {
double seek_pos = 0;
@@ -837,20 +867,18 @@ void OMX_MediaProcessor::mediaDecoding()
//seek_pos *= 1000.0;
-#if 1
if (m_omx_reader->SeekTime((int)seek_pos, m_av_clock->OMXPlaySpeed() < 0, &startpts))
{
; //FlushStreams(DVD_NOPTS_VALUE);
}
-#endif // 1
- CLog::Log(LOGDEBUG, "Seeked %.0f %.0f %.0f", DVD_MSEC_TO_TIME(seek_pos), startpts, m_av_clock->OMXMediaTime());
+ log_verbose("Seeked %.0f %.0f %.0f", DVD_MSEC_TO_TIME(seek_pos), startpts, m_av_clock->OMXMediaTime());
m_packetAfterSeek = false;
}
// TODO: Better error handling.
if (m_player_audio->Error()) {
- LOG_ERROR(LOG_TAG, "Audio player error. emergency exit!");
+ log_err("Audio player error. emergency exit!");
break;
}
@@ -877,6 +905,10 @@ void OMX_MediaProcessor::mediaDecoding()
audio_fifo = audio_pts == DVD_NOPTS_VALUE ? 0.0f : audio_pts / DVD_TIME_BASE - stamp * 1e-6;
video_fifo = video_pts == DVD_NOPTS_VALUE ? 0.0f : video_pts / DVD_TIME_BASE - stamp * 1e-6;
threshold = min(0.1f, (float)m_player_audio->GetCacheTotal()*0.1f);
+ audio_fifo_low = false;
+ video_fifo_low = false;
+ audio_fifo_high = false;
+ video_fifo_high = false;
#endif // ENABLE_PAUSE_FOR_BUFFERING
#if 0
@@ -923,14 +955,19 @@ void OMX_MediaProcessor::mediaDecoding()
video_fifo_high = !m_has_video || (video_pts != DVD_NOPTS_VALUE && video_fifo > m_threshold);
}
+#if 0
+ log_debug("Normal M:%.0f (A:%.0f V:%.0f) P:%d A:%.2f V:%.2f/T:%.2f (%d,%d,%d,%d) A:%d%% V:%d%% (%.2f,%.2f)\n", stamp, audio_pts, video_pts, m_av_clock->OMXIsPaused(),
+ audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_threshold, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high,
+ m_player_audio->GetLevel(), m_player_video->GetLevel(), m_player_audio->GetDelay(), (float)m_player_audio->GetCacheTotal());
+#endif
+
// Enable this to enable pause for buffering.
- if (m_state != STATE_PAUSED && (m_omx_reader->IsEof() || m_omx_pkt || TRICKPLAY(m_av_clock->OMXPlaySpeed()) || (audio_fifo_high && video_fifo_high)))
- {
- if (m_av_clock->OMXIsPaused())
- {
- CLog::Log(LOGDEBUG, "Resume %.2f,%.2f (%d,%d,%d,%d) EOF:%d PKT:%p\n", audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_omx_reader->IsEof(), m_omx_pkt);
- log_verbose("Pausing for buffering...");
- //m_av_clock->OMXStateExecute();
+ if (m_state != STATE_PAUSED && (m_omx_reader->IsEof() || m_omx_pkt || TRICKPLAY(m_av_clock->OMXPlaySpeed()) || (audio_fifo_high && video_fifo_high))) {
+ if (m_av_clock->OMXIsPaused()) {
+ log_verbose("Resume %.2f,%.2f (%d,%d,%d,%d) EOF:%d PKT:%p\n",
+ audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_omx_reader->IsEof(), m_omx_pkt);
+
+ setMediaStatus(OMX_MediaStatus::MEDIA_STATUS_BUFFERED);
m_av_clock->OMXResume();
}
}
@@ -940,9 +977,11 @@ void OMX_MediaProcessor::mediaDecoding()
{
if (m_state != STATE_PAUSED)
m_threshold = std::min(2.0f*m_threshold, 16.0f);
- CLog::Log(LOGDEBUG, "Pause %.2f,%.2f (%d,%d,%d,%d) %.2f\n", audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_threshold);
- log_verbose("Buffering completed. Resuming...");
+ log_verbose("Pause %.2f,%.2f (%d,%d,%d,%d) %.2f\n",
+ audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_threshold);
+
m_av_clock->OMXPause();
+ setMediaStatus(OMX_MediaStatus::MEDIA_STATUS_BUFFERING);
}
}
#endif
@@ -950,9 +989,9 @@ void OMX_MediaProcessor::mediaDecoding()
if (UNLIKELY(!sentStarted))
{
- CLog::Log(LOGDEBUG, "COMXPlayer::HandleMessages - player started RESET");
+ log_verbose("COMXPlayer::HandleMessages - player started RESET");
m_av_clock->OMXReset(m_has_video, m_has_audio);
- m_av_clock->OMXStateExecute();
+ //m_av_clock->OMXStateExecute();
sentStarted = true;
}
@@ -1056,9 +1095,9 @@ void OMX_MediaProcessor::mediaDecoding()
m_incrMs = -(mediaTime ? DVD_TIME_TO_MSEC(mediaTime) : last_seek_pos);
m_seekFlush = true;
- flushStreams(DVD_NOPTS_VALUE);
+ //flushStreams(DVD_NOPTS_VALUE);
m_provider->flush();
- m_player_video->Reset();
+ //m_player_video->Reset();
setState(STATE_STOPPED);
emit playbackCompleted();
diff --git a/piomxtextures_src/omx_mediaprocessor.h b/piomxtextures_src/omx_mediaprocessor.h
index e7029e4..a3fcf02 100644
--- a/piomxtextures_src/omx_mediaprocessor.h
+++ b/piomxtextures_src/omx_mediaprocessor.h
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
@@ -138,6 +139,7 @@ class OMX_MediaProcessor : public QObject
bool hasAudio();
bool hasVideo();
+ bool isSeekable();
qint64 streamLength();
@@ -167,13 +169,15 @@ public slots:
bool seek(qint64 position);
signals:
+ void streamLengthChanged(qint64 length);
void metadataChanged(const QVariantMap metadata);
void playbackStarted();
void playbackCompleted();
void errorOccurred(OMX_MediaProcessor::OMX_MediaProcessorError error);
void stateChanged(OMX_MediaProcessor::OMX_MediaProcessorState state);
void mediaStatusChanged(OMX_MediaProcessor::OMX_MediaStatus status);
- void streamLengthChanged(qint64 length);
+ void bufferStatusChanged(int percentage);
+ void availablePlaybackRangesChanged(QMediaTimeRange ranges);
private slots:
void init();
@@ -193,8 +197,8 @@ private slots:
void flushStreams(double pts);
void convertMetaData();
- QThread* m_thread;
- QString m_filename;
+ OMX_QThread* m_thread;
+ QString m_sourceUrl;
AVFormatContext* fmt_ctx;
AVStream* streamVideo;
diff --git a/piomxtextures_src/omx_omxplayer_logging.cpp b/piomxtextures_src/omx_omxplayer_logging.cpp
index 85b38fc..6097bee 100644
--- a/piomxtextures_src/omx_omxplayer_logging.cpp
+++ b/piomxtextures_src/omx_omxplayer_logging.cpp
@@ -53,6 +53,8 @@
#include "omx_logging.h"
+#define ENABLE_OMXPLAYER_LOGS
+
/*------------------------------------------------------------------------------
| definitions
+-----------------------------------------------------------------------------*/
diff --git a/piomxtextures_src/omxplayer_lib/OMXCore.cpp b/piomxtextures_src/omxplayer_lib/OMXCore.cpp
index 05cf56f..2fe5274 100644
--- a/piomxtextures_src/omxplayer_lib/OMXCore.cpp
+++ b/piomxtextures_src/omxplayer_lib/OMXCore.cpp
@@ -46,7 +46,7 @@
#define log_lock log_disabled
// lcarlon: temporary implementation.
-QMutex COMXCoreComponent::m_mxOmx(QMutex::Recursive);
+QSemaphore COMXCoreComponent::m_mxOmx(2);
/*------------------------------------------------------------------------------
| COMXCoreComponent::testOmx
@@ -55,32 +55,44 @@ bool COMXCoreComponent::testOmx()
{
// Try to lock and timeout in 1s.
log_debug("Testing OpenMAX health...");
- const bool alive = m_mxOmx.tryLock(1000);
+ const bool alive = m_mxOmx.tryAcquire();
if (alive)
- m_mxOmx.unlock();
+ m_mxOmx.release();
+
+ if (alive) {
+ log_debug("OpenMAX seems healthy :-)");
+ return true;
+ }
- if (alive)
- return log_debug("OpenMAX seems healthy :-)");
return log_warn("OpenMAX seems dead ;-(");
}
+#include
+//static QElapsedTimer g_elapsedLock;
+
/*------------------------------------------------------------------------------
| lock_mutex
+-----------------------------------------------------------------------------*/
-inline void lock_mutex(QMutex* m)
+inline void lock_mutex(QSemaphore* m)
{
log_lock("Waiting for lock %p...", m);
- m->lock();
+ m->acquire();
log_lock("Got lock %p...", m);
+
+ //g_elapsedLock.start();
}
/*------------------------------------------------------------------------------
| unlock_mutex
+-----------------------------------------------------------------------------*/
-inline void unlock_mutex(QMutex* m)
+inline void unlock_mutex(QSemaphore* m)
{
log_lock("Releasing lock %p...", m);
- m->unlock();
+ m->release();
+
+ //log_warn("Elpsed: %lld.", g_elapsedLock.elapsed());
+ //if (g_elapsedLock.elapsed() > 30)
+ // log_stacktrace(LC_LOG_INFO, 100);
}
#endif // OMX_THREAD_UNSAFE
@@ -875,7 +887,8 @@ OMX_ERRORTYPE COMXCoreComponent::FreeInputBuffers()
WaitForInputDone(1000);
pthread_mutex_lock(&m_omx_input_mutex);
- assert(m_omx_input_buffers.size() == m_omx_input_avaliable.size());
+ if (m_omx_input_buffers.size() != m_omx_input_avaliable.size())
+ log_err("m_omx_input_buffers.size() != m_omx_input_avaliable.size()");
m_omx_input_buffers.clear();
@@ -1284,22 +1297,28 @@ OMX_ERRORTYPE COMXCoreComponent::GetConfig(OMX_INDEXTYPE configIndex, OMX_PTR co
const
#endif // OMX_THREAD_UNSAFE
{
-#ifdef OMX_THREAD_UNSAFE
- // lcarlon
- QMutexLocker locker(&m_mxOmx);
-#endif // OMX_THREAD_UNSAFE
-
if(!m_handle)
return OMX_ErrorUndefined;
OMX_ERRORTYPE omx_err;
+#ifdef OMX_THREAD_UNSAFE
+ // lcarlon
+ lock_mutex(&m_mxOmx);
+#endif // OMX_THREAD_UNSAFE
+
omx_err = OMX_GetConfig(m_handle, configIndex, configStruct);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "COMXCoreComponent::GetConfig - %s failed with omx_err(0x%x)\n",
m_componentName.c_str(), omx_err);
}
+
+#ifdef OMX_THREAD_UNSAFE
+ // lcarlon
+ unlock_mutex(&m_mxOmx);
+#endif // OMX_THREAD_UNSAFE
+
return omx_err;
}
diff --git a/piomxtextures_src/omxplayer_lib/OMXCore.h b/piomxtextures_src/omxplayer_lib/OMXCore.h
index 85db721..9094dcd 100644
--- a/piomxtextures_src/omxplayer_lib/OMXCore.h
+++ b/piomxtextures_src/omxplayer_lib/OMXCore.h
@@ -33,10 +33,10 @@
#include
-//#define OMX_THREAD_UNSAFE
+#define OMX_THREAD_UNSAFE
#ifdef OMX_THREAD_UNSAFE
-#include
+#include
#endif // OMX_THREAD_UNSAFE
////////////////////////////////////////////////////////////////////////////////////////////
@@ -224,7 +224,7 @@ class COMXCoreComponent
bool m_resource_error;
#ifdef OMX_THREAD_UNSAFE
- static QMutex m_mxOmx;
+ static QSemaphore m_mxOmx;
#endif // OMX_THREAD_UNSAFE
// lcarlon: keep during merges.
diff --git a/piomxtextures_src/omxplayer_lib/linux/RBP.cpp b/piomxtextures_src/omxplayer_lib/linux/RBP.cpp
index 0fc0bbb..9ccf46b 100644
--- a/piomxtextures_src/omxplayer_lib/linux/RBP.cpp
+++ b/piomxtextures_src/omxplayer_lib/linux/RBP.cpp
@@ -24,6 +24,9 @@
#define CLASSNAME "CRBP"
+int CRBP::m_refcount = 0;
+QMutex CRBP::m_mutex;
+
CRBP::CRBP()
{
m_initialized = false;
@@ -38,17 +41,29 @@ CRBP::~CRBP()
bool CRBP::Initialize()
{
+ QMutexLocker l(&m_mutex);
+ if (m_refcount > 0)
+ return true;
+
m_initialized = m_DllBcmHost->Load();
if(!m_initialized)
return false;
+ log_info("bcm_host_init");
m_DllBcmHost->bcm_host_init();
+ m_refcount++;
return true;
}
void CRBP::Deinitialize()
{
+ QMutexLocker l(&m_mutex);
+ m_refcount--;
+ if (m_refcount > 0)
+ return;
+
+ log_info("bcm_host_deinit");
m_DllBcmHost->bcm_host_deinit();
if(m_initialized)
diff --git a/piomxtextures_src/omxplayer_lib/linux/RBP.h b/piomxtextures_src/omxplayer_lib/linux/RBP.h
index ed15e0c..2b75170 100644
--- a/piomxtextures_src/omxplayer_lib/linux/RBP.h
+++ b/piomxtextures_src/omxplayer_lib/linux/RBP.h
@@ -42,6 +42,10 @@
#define HAVE_VMCS_CONFIG
#endif
+#include
+
+#include "omx_logging.h"
+
#include "DllBCM.h"
class CRBP
@@ -56,6 +60,9 @@ class CRBP
private:
DllBcmHost *m_DllBcmHost;
bool m_initialized;
+
+ static int m_refcount;
+ static QMutex m_mutex;
};
extern CRBP g_RBP;
diff --git a/piomxtextures_src/piomxtextures_src.pri b/piomxtextures_src/piomxtextures_src.pri
index 516219e..78f9ea4 100644
--- a/piomxtextures_src/piomxtextures_src.pri
+++ b/piomxtextures_src/piomxtextures_src.pri
@@ -21,7 +21,7 @@
# along with PiOmxTextures. If not, see .
#
-QT += core core-private gui gui-private opengl quick quick-private
+QT += core core-private gui gui-private opengl quick quick-private multimedia
SRC=$$PWD
SRC_WRAPPER=$$SRC/omx_wrapper
diff --git a/piomxtextures_tools/ffmpeg_test.c b/piomxtextures_tools/ffmpeg_test.c
new file mode 100644
index 0000000..989c128
--- /dev/null
+++ b/piomxtextures_tools/ffmpeg_test.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014 Stefano Sabatini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/**
+ * @file
+ * libavformat AVIOContext API example.
+ *
+ * Make libavformat demuxer access media content through a custom
+ * AVIOContext read callback.
+ * @example avio_reading.c
+ */
+#include
+#include
+#include
+#include
+
+struct buffer_data {
+ uint8_t *ptr;
+ size_t size; ///< size left in the buffer
+};
+
+static int read_packet(void *opaque, uint8_t *buf, int buf_size)
+{
+ struct buffer_data *bd = (struct buffer_data *)opaque;
+ buf_size = FFMIN(buf_size, bd->size);
+ printf("ptr:%p size:%zu\n", bd->ptr, bd->size);
+ /* copy internal buffer data to buf */
+ memcpy(buf, bd->ptr, buf_size);
+ bd->ptr += buf_size;
+ bd->size -= buf_size;
+ return buf_size;
+}
+
+int test(int argc, char* const argv[])
+{
+ AVFormatContext *fmt_ctx = NULL;
+ AVIOContext *avio_ctx = NULL;
+ uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
+ size_t buffer_size, avio_ctx_buffer_size = 4096;
+ char *input_filename = NULL;
+ int ret = 0;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s input_file\n"
+ "API example program to show how to read from a custom buffer "
+ "accessed through AVIOContext.\n", argv[0]);
+ return 1;
+ }
+
+ input_filename = argv[1];
+
+ /* register codecs and formats and other lavf/lavc components*/
+ av_register_all();
+ av_log_set_level(AV_LOG_INFO);
+
+ if (!(fmt_ctx = avformat_alloc_context())) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ fmt_ctx->flags |= AVFMT_FLAG_NONBLOCK;
+
+ avio_ctx_buffer = (uint8_t*)av_malloc(avio_ctx_buffer_size);
+ if (!avio_ctx_buffer) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ ret = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open input\n");
+ goto end;
+ }
+
+ ret = avformat_find_stream_info(fmt_ctx, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not find stream information\n");
+ goto end;
+ }
+
+ av_dump_format(fmt_ctx, 0, input_filename, 0);
+
+end:
+ avformat_close_input(&fmt_ctx);
+ /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
+ if (avio_ctx) {
+ av_freep(&avio_ctx->buffer);
+ av_freep(&avio_ctx);
+ }
+ //av_file_unmap(buffer, buffer_size);
+ if (ret < 0) {
+ char error[1000];
+ char* s = av_make_error_string(error, 1000, ret);
+ fprintf(stderr, "Error occurred: %s\n", s);
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ char* const argv2[] = {"", argv[1]};
+ int i = 0;
+ for (i = 0; 1; i++) {
+ fprintf(stderr, "Iteration %d...\n", i);
+ test(2, argv2);
+ }
+
+ return 0;
+}