新增视频监控内核mpv
This commit is contained in:
@@ -40,6 +40,8 @@ SUBDIRS += imageswitch #图片开关控件
|
|||||||
#SUBDIRS += ffmpegdemo #视频流播放ffmpeg内核
|
#SUBDIRS += ffmpegdemo #视频流播放ffmpeg内核
|
||||||
#vlcdemo默认提供的win的lib,如果是win可以自行打开
|
#vlcdemo默认提供的win的lib,如果是win可以自行打开
|
||||||
#SUBDIRS += vlcdemo #视频流播放vlc内核
|
#SUBDIRS += vlcdemo #视频流播放vlc内核
|
||||||
|
#mpvdemo默认提供的win的lib,如果是win可以自行打开
|
||||||
|
#SUBDIRS += mpvdemo #视频流播放mpv内核
|
||||||
#designer项目只支持Qt4,如果是Qt4可以自行打开
|
#designer项目只支持Qt4,如果是Qt4可以自行打开
|
||||||
#SUBDIRS += designer #QtDesigner4源码
|
#SUBDIRS += designer #QtDesigner4源码
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
| 37 | live | 程序守护进程 |
|
| 37 | live | 程序守护进程 |
|
||||||
| 38 | designer | QtDesigner4源码 |
|
| 38 | designer | QtDesigner4源码 |
|
||||||
| 39 | netserver | 网络中转服务器 |
|
| 39 | netserver | 网络中转服务器 |
|
||||||
|
| 40 | mpvdemo | 视频流播放mpv内核 |
|
||||||
|
|
||||||
### 二、学习群
|
### 二、学习群
|
||||||
1. **Qt交流大会群 853086607(雨田哥)**
|
1. **Qt交流大会群 853086607(雨田哥)**
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
#include "ffmpeg.h"
|
#include "ffmpeg.h"
|
||||||
|
|
||||||
#pragma execution_character_set("utf-8")
|
|
||||||
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
|
||||||
#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
|
|
||||||
|
|
||||||
FFmpegThread::FFmpegThread(QObject *parent) : QThread(parent)
|
FFmpegThread::FFmpegThread(QObject *parent) : QThread(parent)
|
||||||
{
|
{
|
||||||
setObjectName("FFmpegThread");
|
setObjectName("FFmpegThread");
|
||||||
@@ -360,8 +356,8 @@ void FFmpegThread::stop()
|
|||||||
//实时视频显示窗体类
|
//实时视频显示窗体类
|
||||||
FFmpegWidget::FFmpegWidget(QWidget * parent) : QWidget(parent)
|
FFmpegWidget::FFmpegWidget(QWidget * parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
ffmpeg = new FFmpegThread(this);
|
thread = new FFmpegThread(this);
|
||||||
connect(ffmpeg, SIGNAL(receiveImage(QImage)), this, SLOT(updateImage(QImage)));
|
connect(thread, SIGNAL(receiveImage(QImage)), this, SLOT(updateImage(QImage)));
|
||||||
image = QImage();
|
image = QImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +386,7 @@ void FFmpegWidget::updateImage(const QImage &image)
|
|||||||
|
|
||||||
void FFmpegWidget::setUrl(const QString &url)
|
void FFmpegWidget::setUrl(const QString &url)
|
||||||
{
|
{
|
||||||
ffmpeg->setUrl(url);
|
thread->setUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpegWidget::open()
|
void FFmpegWidget::open()
|
||||||
@@ -398,27 +394,27 @@ void FFmpegWidget::open()
|
|||||||
//qDebug() << TIMEMS << "open video" << objectName();
|
//qDebug() << TIMEMS << "open video" << objectName();
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
ffmpeg->play();
|
thread->play();
|
||||||
ffmpeg->start();
|
thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpegWidget::pause()
|
void FFmpegWidget::pause()
|
||||||
{
|
{
|
||||||
ffmpeg->pause();
|
thread->pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpegWidget::next()
|
void FFmpegWidget::next()
|
||||||
{
|
{
|
||||||
ffmpeg->next();
|
thread->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpegWidget::close()
|
void FFmpegWidget::close()
|
||||||
{
|
{
|
||||||
//qDebug() << TIMEMS << "close video" << objectName();
|
//qDebug() << TIMEMS << "close video" << objectName();
|
||||||
if (ffmpeg->isRunning()) {
|
if (thread->isRunning()) {
|
||||||
ffmpeg->stop();
|
thread->stop();
|
||||||
ffmpeg->quit();
|
thread->quit();
|
||||||
ffmpeg->wait(500);
|
thread->wait(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTimer::singleShot(1, this, SLOT(clear()));
|
QTimer::singleShot(1, this, SLOT(clear()));
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ffmpeghead.h"
|
#include "ffmpeghead.h"
|
||||||
class FFmpegWidget;
|
|
||||||
|
|
||||||
class FFmpegThread : public QThread
|
class FFmpegThread : public QThread
|
||||||
{
|
{
|
||||||
@@ -81,8 +80,8 @@ protected:
|
|||||||
void paintEvent(QPaintEvent *);
|
void paintEvent(QPaintEvent *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FFmpegThread *ffmpeg; //实时视频采集对象
|
FFmpegThread *thread;
|
||||||
QImage image; //要显示的图片
|
QImage image;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
//接收图像并绘制
|
//接收图像并绘制
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
HEADERS += $$PWD/ffmpeghead.h
|
HEADERS += $$PWD/ffmpeghead.h
|
||||||
HEADERS += $$PWD/ffmpeg.h
|
HEADERS += $$PWD/ffmpeg.h
|
||||||
SOURCES += $$PWD/ffmpeg.cpp
|
SOURCES += $$PWD/ffmpeg.cpp
|
||||||
|
|
||||||
#如果用的是ffmpeg4内核请将ffmpeg3改成ffmpeg4,两种内核不兼容,头文件也不一样
|
#如果用的是ffmpeg4内核请将ffmpeg3改成ffmpeg4,两种内核不兼容,头文件也不一样
|
||||||
DEFINES += ffmpeg3
|
DEFINES += ffmpeg3
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
//必须加以下内容,否则编译不能通过,为了兼容C和C99标准
|
#ifndef FFMPEGHEAD_H
|
||||||
|
#define FFMPEGHEAD_H
|
||||||
|
|
||||||
|
//必须加以下内容,否则编译不能通过,为了兼容C和C99标准
|
||||||
#ifndef INT64_C
|
#ifndef INT64_C
|
||||||
#define INT64_C
|
#define INT64_C
|
||||||
#define UINT64_C
|
#define UINT64_C
|
||||||
@@ -15,6 +18,7 @@ extern "C" {
|
|||||||
#include "libavutil/ffversion.h"
|
#include "libavutil/ffversion.h"
|
||||||
#include "libavcodec/avcodec.h"
|
#include "libavcodec/avcodec.h"
|
||||||
#include "libswscale/swscale.h"
|
#include "libswscale/swscale.h"
|
||||||
|
#include "libswresample/swresample.h"
|
||||||
#include "libavformat/avformat.h"
|
#include "libavformat/avformat.h"
|
||||||
#include "libavfilter/avfilter.h"
|
#include "libavfilter/avfilter.h"
|
||||||
|
|
||||||
@@ -27,3 +31,16 @@ extern "C" {
|
|||||||
#include "libavutil/hwcontext_qsv.h"
|
#include "libavutil/hwcontext_qsv.h"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "qdatetime.h"
|
||||||
|
#pragma execution_character_set("utf-8")
|
||||||
|
|
||||||
|
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
||||||
|
#define TIME qPrintable(QTime::currentTime().toString("HH:mm:ss"))
|
||||||
|
#define QDATE qPrintable(QDate::currentDate().toString("yyyy-MM-dd"))
|
||||||
|
#define QTIME qPrintable(QTime::currentTime().toString("HH-mm-ss"))
|
||||||
|
#define DATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
|
||||||
|
#define STRDATETIMEMS qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss-zzz"))
|
||||||
|
|
||||||
|
#endif // FFMPEGHEAD_H
|
||||||
|
|||||||
@@ -6,12 +6,4 @@
|
|||||||
2. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
|
2. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
|
||||||
3. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
|
3. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
|
||||||
4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
|
4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
|
||||||
5. ֪<><D6AA><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
|
5. ֪<><D6AA><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
|
||||||
|
|
||||||
1. <20><><EFBFBD>߳<EFBFBD>ʵʱ<CAB5><CAB1><EFBFBD><EFBFBD>
|
|
||||||
2. ͬʱ<CDAC><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>
|
|
||||||
3. ֧<><D6A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Qt<51>汾<EFBFBD><E6B1BE><EFBFBD><EFBFBD>ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
4. <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CDB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>룬<EFBFBD><EBA3AC>չ<EFBFBD><D5B9>ǿ
|
|
||||||
5. <20><>ѡffmpeg3<67><33>ffmpeg4<67><34><EFBFBD><EFBFBD><EFBFBD>汾
|
|
||||||
6. <20><>ѡ32λ<32><CEBB>64λ<34><CEBB>ffmpeg<65><67>
|
|
||||||
7. ע<>;<EFBFBD><CDBE><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
@@ -2,9 +2,7 @@
|
|||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "ui_widget.h"
|
#include "ui_widget.h"
|
||||||
|
|
||||||
Widget::Widget(QWidget *parent)
|
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
|
||||||
: QWidget(parent)
|
|
||||||
, ui(new Ui::Widget)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@@ -17,6 +15,7 @@ Widget::Widget(QWidget *parent)
|
|||||||
urls << "rtsp://192.168.1.247:554/av0_0";
|
urls << "rtsp://192.168.1.247:554/av0_0";
|
||||||
urls << "rtsp://192.168.1.247:554/av0_1";
|
urls << "rtsp://192.168.1.247:554/av0_1";
|
||||||
ui->cboxUrl->addItems(urls);
|
ui->cboxUrl->addItems(urls);
|
||||||
|
ui->cboxUrl->setCurrentIndex(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget::~Widget()
|
Widget::~Widget()
|
||||||
@@ -29,10 +28,10 @@ void Widget::on_btnOpen_clicked()
|
|||||||
if (ui->btnOpen->text() == "打开") {
|
if (ui->btnOpen->text() == "打开") {
|
||||||
ui->btnOpen->setText("关闭");
|
ui->btnOpen->setText("关闭");
|
||||||
QString url = ui->cboxUrl->currentText().trimmed();
|
QString url = ui->cboxUrl->currentText().trimmed();
|
||||||
ui->ffmpegWidget->setUrl(url);
|
ui->playWidget->setUrl(url);
|
||||||
ui->ffmpegWidget->open();
|
ui->playWidget->open();
|
||||||
} else {
|
} else {
|
||||||
ui->btnOpen->setText("打开");
|
ui->btnOpen->setText("打开");
|
||||||
ui->ffmpegWidget->close();
|
ui->playWidget->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="FFmpegWidget" name="ffmpegWidget" native="true">
|
<widget class="FFmpegWidget" name="playWidget" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
|||||||
43
mpvdemo/main.cpp
Normal file
43
mpvdemo/main.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma execution_character_set("utf-8")
|
||||||
|
#include "widget.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QTextCodec>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
|
QFont font;
|
||||||
|
font.setFamily("MicroSoft Yahei");
|
||||||
|
font.setPixelSize(12);
|
||||||
|
a.setFont(font);
|
||||||
|
|
||||||
|
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
|
||||||
|
#if _MSC_VER
|
||||||
|
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||||
|
#else
|
||||||
|
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||||
|
#endif
|
||||||
|
QTextCodec::setCodecForLocale(codec);
|
||||||
|
QTextCodec::setCodecForCStrings(codec);
|
||||||
|
QTextCodec::setCodecForTr(codec);
|
||||||
|
#else
|
||||||
|
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||||
|
QTextCodec::setCodecForLocale(codec);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Widget w;
|
||||||
|
w.setWindowTitle("视频流播放mpv内核 (QQ: 517216493)");
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
//居中显示窗体
|
||||||
|
QDesktopWidget deskWidget;
|
||||||
|
int deskWidth = deskWidget.availableGeometry().width();
|
||||||
|
int deskHeight = deskWidget.availableGeometry().height();
|
||||||
|
QPoint movePoint(deskWidth / 2 - w.width() / 2, deskHeight / 2 - w.height() / 2);
|
||||||
|
w.move(movePoint);
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
1979
mpvdemo/mpv/include/client.h
Normal file
1979
mpvdemo/mpv/include/client.h
Normal file
File diff suppressed because it is too large
Load Diff
339
mpvdemo/mpv/include/opengl_cb.h
Normal file
339
mpvdemo/mpv/include/opengl_cb.h
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
/* Copyright (C) 2017 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_OPENGL_CB_H_
|
||||||
|
#define MPV_CLIENT_API_OPENGL_CB_H_
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#if !MPV_ENABLE_DEPRECATED
|
||||||
|
#error "This header and all API provided by it is deprecated. Use render.h instead."
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* Warning: this API is deprecated. A very similar API is provided by render.h
|
||||||
|
* and render_gl.h. The deprecated API is emulated with the new API.
|
||||||
|
*
|
||||||
|
* This API can be used to make mpv render into a foreign OpenGL context. It
|
||||||
|
* can be used to handle video display.
|
||||||
|
*
|
||||||
|
* The renderer needs to be explicitly initialized with mpv_opengl_cb_init_gl(),
|
||||||
|
* and then video can be drawn with mpv_opengl_cb_draw(). The user thread can
|
||||||
|
* be notified by new frames with mpv_opengl_cb_set_update_callback().
|
||||||
|
*
|
||||||
|
* You can output and embed video without this API by setting the mpv "wid"
|
||||||
|
* option to a native window handle (see "Embedding the video window" section
|
||||||
|
* in the client.h header). In general, using the opengl-cb API is recommended,
|
||||||
|
* because window embedding can cause various issues, especially with GUI
|
||||||
|
* toolkits and certain platforms.
|
||||||
|
*
|
||||||
|
* OpenGL interop
|
||||||
|
* --------------
|
||||||
|
*
|
||||||
|
* This assumes the OpenGL context lives on a certain thread controlled by the
|
||||||
|
* API user. The following functions require access to the OpenGL context:
|
||||||
|
* mpv_opengl_cb_init_gl
|
||||||
|
* mpv_opengl_cb_draw
|
||||||
|
* mpv_opengl_cb_uninit_gl
|
||||||
|
*
|
||||||
|
* The OpenGL context is indirectly accessed through the OpenGL function
|
||||||
|
* pointers returned by the get_proc_address callback in mpv_opengl_cb_init_gl.
|
||||||
|
* Generally, mpv will not load the system OpenGL library when using this API.
|
||||||
|
*
|
||||||
|
* Only "desktop" OpenGL version 2.1 and later and OpenGL ES version 2.0 and
|
||||||
|
* later are supported. With OpenGL 2.1, the GL_ARB_texture_rg is required. The
|
||||||
|
* renderer was written for the OpenGL 3.x core profile, with additional support
|
||||||
|
* for OpenGL 2.1 and OpenGL ES 2.0.
|
||||||
|
*
|
||||||
|
* Note that some hardware decoding interop API (as set with the "hwdec" option)
|
||||||
|
* may actually access some sort of host API, such as EGL.
|
||||||
|
*
|
||||||
|
* OpenGL state
|
||||||
|
* ------------
|
||||||
|
*
|
||||||
|
* OpenGL has a large amount of implicit state. All the mpv functions mentioned
|
||||||
|
* above expect that the OpenGL state is reasonably set to OpenGL standard
|
||||||
|
* defaults. Likewise, mpv will attempt to leave the OpenGL context with
|
||||||
|
* standard defaults. The following state is excluded from this:
|
||||||
|
*
|
||||||
|
* - the glViewport state
|
||||||
|
* - the glScissor state (but GL_SCISSOR_TEST is in its default value)
|
||||||
|
* - glBlendFuncSeparate() state (but GL_BLEND is in its default value)
|
||||||
|
* - glClearColor() state
|
||||||
|
* - mpv may overwrite the callback set with glDebugMessageCallback()
|
||||||
|
* - mpv always disables GL_DITHER at init
|
||||||
|
*
|
||||||
|
* Messing with the state could be avoided by creating shared OpenGL contexts,
|
||||||
|
* but this is avoided for the sake of compatibility and interoperability.
|
||||||
|
*
|
||||||
|
* On OpenGL 2.1, mpv will strictly call functions like glGenTextures() to
|
||||||
|
* create OpenGL objects. You will have to do the same. This ensures that
|
||||||
|
* objects created by mpv and the API users don't clash. Also, legacy state
|
||||||
|
* must be either in its defaults, or not interfere with core state.
|
||||||
|
*
|
||||||
|
* Threading
|
||||||
|
* ---------
|
||||||
|
*
|
||||||
|
* The mpv_opengl_cb_* functions can be called from any thread, under the
|
||||||
|
* following conditions:
|
||||||
|
* - only one of the mpv_opengl_cb_* functions can be called at the same time
|
||||||
|
* (unless they belong to different mpv cores created by mpv_create())
|
||||||
|
* - for functions which need an OpenGL context (see above) the OpenGL context
|
||||||
|
* must be "current" in the current thread, and it must be the same context
|
||||||
|
* as used with mpv_opengl_cb_init_gl()
|
||||||
|
* - never can be called from within the callbacks set with
|
||||||
|
* mpv_set_wakeup_callback() or mpv_opengl_cb_set_update_callback()
|
||||||
|
*
|
||||||
|
* Context and handle lifecycle
|
||||||
|
* ----------------------------
|
||||||
|
*
|
||||||
|
* Video initialization will fail if the OpenGL context was not initialized yet
|
||||||
|
* (with mpv_opengl_cb_init_gl()). Likewise, mpv_opengl_cb_uninit_gl() will
|
||||||
|
* disable video.
|
||||||
|
*
|
||||||
|
* When the mpv core is destroyed (e.g. via mpv_terminate_destroy()), the OpenGL
|
||||||
|
* context must have been uninitialized. If this doesn't happen, undefined
|
||||||
|
* behavior will result.
|
||||||
|
*
|
||||||
|
* Hardware decoding
|
||||||
|
* -----------------
|
||||||
|
*
|
||||||
|
* Hardware decoding via opengl_cb is fully supported, but requires some
|
||||||
|
* additional setup. (At least if direct hardware decoding modes are wanted,
|
||||||
|
* instead of copying back surface data from GPU to CPU RAM.)
|
||||||
|
*
|
||||||
|
* While "normal" mpv loads the OpenGL hardware decoding interop on demand,
|
||||||
|
* this can't be done with opengl_cb for internal technical reasons. Instead,
|
||||||
|
* it loads them by default, even if hardware decoding is not going to be used.
|
||||||
|
* In older mpv releases, this had to be done by setting the
|
||||||
|
* "opengl-hwdec-interop" or "hwdec-preload" options before calling
|
||||||
|
* mpv_opengl_cb_init_gl(). You can still use the newer "gpu-hwdec-interop"
|
||||||
|
* option to prevent loading of interop, or to load only a specific interop.
|
||||||
|
*
|
||||||
|
* There may be certain requirements on the OpenGL implementation:
|
||||||
|
* - Windows: ANGLE is required (although in theory GL/DX interop could be used)
|
||||||
|
* - Intel/Linux: EGL is required, and also a glMPGetNativeDisplay() callback
|
||||||
|
* must be provided (see sections below)
|
||||||
|
* - nVidia/Linux: Both GLX and EGL should work (GLX is required if vdpau is
|
||||||
|
* used, e.g. due to old drivers.)
|
||||||
|
* - OSX: CGL is required (CGLGetCurrentContext() returning non-NULL)
|
||||||
|
* - iOS: EAGL is required (EAGLContext.currentContext returning non-nil)
|
||||||
|
*
|
||||||
|
* Once these things are setup, hardware decoding can be enabled/disabled at
|
||||||
|
* any time by setting the "hwdec" property.
|
||||||
|
*
|
||||||
|
* Special windowing system interop considerations
|
||||||
|
* ------------------------------------------------
|
||||||
|
*
|
||||||
|
* In some cases, libmpv needs to have access to the windowing system's handles.
|
||||||
|
* This can be a pointer to a X11 "Display" for example. Usually this is needed
|
||||||
|
* only for hardware decoding.
|
||||||
|
*
|
||||||
|
* You can communicate these handles to libmpv by adding a pseudo-OpenGL
|
||||||
|
* extension "GL_MP_MPGetNativeDisplay" to the additional extension string when
|
||||||
|
* calling mpv_opengl_cb_init_gl(). The get_proc_address callback should resolve
|
||||||
|
* a function named "glMPGetNativeDisplay", which has the signature:
|
||||||
|
*
|
||||||
|
* void* GLAPIENTRY glMPGetNativeDisplay(const char* name)
|
||||||
|
*
|
||||||
|
* See below what names are defined. Usually, libmpv will use the native handle
|
||||||
|
* up until mpv_opengl_cb_uninit_gl() is called. If the name is not anything
|
||||||
|
* you know/expected, return NULL from the function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Legacy - not supported anymore.
|
||||||
|
struct mpv_opengl_cb_window_pos {
|
||||||
|
int x; // left coordinates of window (usually 0)
|
||||||
|
int y; // top coordinates of window (usually 0)
|
||||||
|
int width; // width of GL window
|
||||||
|
int height; // height of GL window
|
||||||
|
};
|
||||||
|
|
||||||
|
// Legacy - not supported anymore.
|
||||||
|
struct mpv_opengl_cb_drm_params {
|
||||||
|
// DRM fd (int). set this to -1 if invalid.
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
// currently used crtc id
|
||||||
|
int crtc_id;
|
||||||
|
|
||||||
|
// currently used connector id
|
||||||
|
int connector_id;
|
||||||
|
|
||||||
|
// pointer to the drmModeAtomicReq that is being used for the renderloop.
|
||||||
|
// This atomic request pointer should be usually created at every renderloop.
|
||||||
|
struct _drmModeAtomicReq *atomic_request;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nVidia/Linux via VDPAU requires GLX, which does not have this problem (the
|
||||||
|
* GLX API can return the current X11 Display).
|
||||||
|
*
|
||||||
|
* Windowing system interop on MS win32
|
||||||
|
* ------------------------------------
|
||||||
|
*
|
||||||
|
* You should use ANGLE, and make sure your application and libmpv are linked
|
||||||
|
* to the same ANGLE DLLs. libmpv will pick the device context (needed for
|
||||||
|
* hardware decoding) from the current ANGLE EGL context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque context, returned by mpv_get_sub_api(MPV_SUB_API_OPENGL_CB).
|
||||||
|
*
|
||||||
|
* A context is bound to the mpv_handle it was retrieved from. The context
|
||||||
|
* will always be the same (for the same mpv_handle), and is valid until the
|
||||||
|
* mpv_handle it belongs to is released.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_cb_context mpv_opengl_cb_context;
|
||||||
|
|
||||||
|
typedef void (*mpv_opengl_cb_update_fn)(void *cb_ctx);
|
||||||
|
typedef void *(*mpv_opengl_cb_get_proc_address_fn)(void *fn_ctx, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callback that notifies you when a new video frame is available, or
|
||||||
|
* if the video display configuration somehow changed and requires a redraw.
|
||||||
|
* Similar to mpv_set_wakeup_callback(), you must not call any mpv API from
|
||||||
|
* the callback, and all the other listed restrictions apply (such as not
|
||||||
|
* exiting the callback by throwing exceptions).
|
||||||
|
*
|
||||||
|
* @param callback callback(callback_ctx) is called if the frame should be
|
||||||
|
* redrawn
|
||||||
|
* @param callback_ctx opaque argument to the callback
|
||||||
|
*/
|
||||||
|
void mpv_opengl_cb_set_update_callback(mpv_opengl_cb_context *ctx,
|
||||||
|
mpv_opengl_cb_update_fn callback,
|
||||||
|
void *callback_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the mpv OpenGL state. This retrieves OpenGL function pointers via
|
||||||
|
* get_proc_address, and creates OpenGL objects needed by mpv internally. It
|
||||||
|
* will also call APIs needed for rendering hardware decoded video in OpenGL,
|
||||||
|
* according to the mpv "hwdec" option.
|
||||||
|
*
|
||||||
|
* You must free the associated state at some point by calling the
|
||||||
|
* mpv_opengl_cb_uninit_gl() function. Not doing so may result in memory leaks
|
||||||
|
* or worse.
|
||||||
|
*
|
||||||
|
* @param exts optional _additional_ extension string, can be NULL
|
||||||
|
* @param get_proc_address callback used to retrieve function pointers to OpenGL
|
||||||
|
* functions. This is used for both standard functions
|
||||||
|
* and extension functions. (The extension string is
|
||||||
|
* checked whether extensions are really available.)
|
||||||
|
* The callback will be called from this function only
|
||||||
|
* (it is not stored and never used later).
|
||||||
|
* Usually, GL context APIs do this for you (e.g. with
|
||||||
|
* glXGetProcAddressARB or wglGetProcAddress), but
|
||||||
|
* some APIs do not always return pointers for all
|
||||||
|
* standard functions (even if present); in this case
|
||||||
|
* you have to compensate by looking up these functions
|
||||||
|
* yourself.
|
||||||
|
* @param get_proc_address_ctx arbitrary opaque user context passed to the
|
||||||
|
* get_proc_address callback
|
||||||
|
* @return error code (same as normal mpv_* API), including but not limited to:
|
||||||
|
* MPV_ERROR_UNSUPPORTED: the OpenGL version is not supported
|
||||||
|
* (or required extensions are missing)
|
||||||
|
* MPV_ERROR_INVALID_PARAMETER: the OpenGL state was already initialized
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_init_gl(mpv_opengl_cb_context *ctx, const char *exts,
|
||||||
|
mpv_opengl_cb_get_proc_address_fn get_proc_address,
|
||||||
|
void *get_proc_address_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render video. Requires that the OpenGL state is initialized.
|
||||||
|
*
|
||||||
|
* The video will use the full provided framebuffer. Options like "panscan" are
|
||||||
|
* applied to determine which part of the video should be visible and how the
|
||||||
|
* video should be scaled. You can change these options at runtime by using the
|
||||||
|
* mpv property API.
|
||||||
|
*
|
||||||
|
* The renderer will reconfigure itself every time the output rectangle/size
|
||||||
|
* is changed. (If you want to do animations, it might be better to do the
|
||||||
|
* animation on a FBO instead.)
|
||||||
|
*
|
||||||
|
* This function implicitly pulls a video frame from the internal queue and
|
||||||
|
* renders it. If no new frame is available, the previous frame is redrawn.
|
||||||
|
* The update callback set with mpv_opengl_cb_set_update_callback() notifies
|
||||||
|
* you when a new frame was added.
|
||||||
|
*
|
||||||
|
* @param fbo The framebuffer object to render on. Because the renderer might
|
||||||
|
* manage multiple FBOs internally for the purpose of video
|
||||||
|
* postprocessing, it will always bind and unbind FBOs itself. If
|
||||||
|
* you want mpv to render on the main framebuffer, pass 0.
|
||||||
|
* @param w Width of the framebuffer. This is either the video size if the fbo
|
||||||
|
* parameter is 0, or the allocated size of the texture backing the
|
||||||
|
* fbo. The renderer will always use the full size of the fbo.
|
||||||
|
* @param h Height of the framebuffer. Same as with the w parameter, except
|
||||||
|
* that this parameter can be negative. In this case, the video
|
||||||
|
* frame will be rendered flipped.
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int w, int h);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. Use mpv_opengl_cb_draw(). This function is equivalent to:
|
||||||
|
*
|
||||||
|
* int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4])
|
||||||
|
* { return mpv_opengl_cb_draw(ctx, fbo, vp[2], vp[3]); }
|
||||||
|
*
|
||||||
|
* vp[0] and vp[1] used to have a meaning, but are ignored in newer versions.
|
||||||
|
*
|
||||||
|
* This function will be removed in the future without version bump (this API
|
||||||
|
* was never marked as stable).
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the renderer that a frame was flipped at the given time. This is
|
||||||
|
* optional, but can help the player to achieve better timing.
|
||||||
|
*
|
||||||
|
* Note that calling this at least once informs libmpv that you will use this
|
||||||
|
* function. If you use it inconsistently, expect bad video playback.
|
||||||
|
*
|
||||||
|
* If this is called while no video or no OpenGL is initialized, it is ignored.
|
||||||
|
*
|
||||||
|
* @param time The mpv time (using mpv_get_time_us()) at which the flip call
|
||||||
|
* returned. If 0 is passed, mpv_get_time_us() is used instead.
|
||||||
|
* Currently, this parameter is ignored.
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_report_flip(mpv_opengl_cb_context *ctx, int64_t time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the mpv OpenGL state.
|
||||||
|
*
|
||||||
|
* If video is still active (e.g. a file playing), video will be disabled
|
||||||
|
* forcefully.
|
||||||
|
*
|
||||||
|
* Calling this multiple times is ok.
|
||||||
|
*
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_uninit_gl(mpv_opengl_cb_context *ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* else #if MPV_ENABLE_DEPRECATED */
|
||||||
|
|
||||||
|
#endif
|
||||||
626
mpvdemo/mpv/include/render.h
Normal file
626
mpvdemo/mpv/include/render.h
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
/* Copyright (C) 2018 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_RENDER_H_
|
||||||
|
#define MPV_CLIENT_API_RENDER_H_
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* This API can be used to make mpv render using supported graphic APIs (such
|
||||||
|
* as OpenGL). It can be used to handle video display.
|
||||||
|
*
|
||||||
|
* The renderer needs to be created with mpv_render_context_create() before
|
||||||
|
* you start playback (or otherwise cause a VO to be created). Then (with most
|
||||||
|
* backends) mpv_render_context_render() can be used to explicitly render the
|
||||||
|
* current video frame. Use mpv_render_context_set_update_callback() to get
|
||||||
|
* notified when there is a new frame to draw.
|
||||||
|
*
|
||||||
|
* Preferably rendering should be done in a separate thread. If you call
|
||||||
|
* normal libmpv API functions on the renderer thread, deadlocks can result
|
||||||
|
* (these are made non-fatal with timeouts, but user experience will obviously
|
||||||
|
* suffer). See "Threading" section below.
|
||||||
|
*
|
||||||
|
* You can output and embed video without this API by setting the mpv "wid"
|
||||||
|
* option to a native window handle (see "Embedding the video window" section
|
||||||
|
* in the client.h header). In general, using the render API is recommended,
|
||||||
|
* because window embedding can cause various issues, especially with GUI
|
||||||
|
* toolkits and certain platforms.
|
||||||
|
*
|
||||||
|
* Supported backends
|
||||||
|
* ------------------
|
||||||
|
*
|
||||||
|
* OpenGL: via MPV_RENDER_API_TYPE_OPENGL, see render_gl.h header.
|
||||||
|
*
|
||||||
|
* Threading
|
||||||
|
* ---------
|
||||||
|
*
|
||||||
|
* You are recommended to do rendering on a separate thread than normal libmpv
|
||||||
|
* use.
|
||||||
|
*
|
||||||
|
* The mpv_render_* functions can be called from any thread, under the
|
||||||
|
* following conditions:
|
||||||
|
* - only one of the mpv_render_* functions can be called at the same time
|
||||||
|
* (unless they belong to different mpv cores created by mpv_create())
|
||||||
|
* - never can be called from within the callbacks set with
|
||||||
|
* mpv_set_wakeup_callback() or mpv_render_context_set_update_callback()
|
||||||
|
* - if the OpenGL backend is used, for all functions the OpenGL context
|
||||||
|
* must be "current" in the calling thread, and it must be the same OpenGL
|
||||||
|
* context as the mpv_render_context was created with. Otherwise, undefined
|
||||||
|
* behavior will occur.
|
||||||
|
* - the thread does not call libmpv API functions other than the mpv_render_*
|
||||||
|
* functions, except APIs which are declared as safe (see below). Likewise,
|
||||||
|
* there must be no lock or wait dependency from the render thread to a
|
||||||
|
* thread using other libmpv functions. Basically, the situation that your
|
||||||
|
* render thread waits for a "not safe" libmpv API function to return must
|
||||||
|
* not happen. If you ignore this requirement, deadlocks can happen, which
|
||||||
|
* are made non-fatal with timeouts; then playback quality will be degraded,
|
||||||
|
* and the message
|
||||||
|
* mpv_render_context_render() not being called or stuck.
|
||||||
|
* is logged. If you set MPV_RENDER_PARAM_ADVANCED_CONTROL, you promise that
|
||||||
|
* this won't happen, and must absolutely guarantee it, or a real deadlock
|
||||||
|
* will freeze the mpv core thread forever.
|
||||||
|
*
|
||||||
|
* libmpv functions which are safe to call from a render thread are:
|
||||||
|
* - functions marked with "Safe to be called from mpv render API threads."
|
||||||
|
* - client.h functions which don't have an explicit or implicit mpv_handle
|
||||||
|
* parameter
|
||||||
|
* - mpv_render_* functions; but only for the same mpv_render_context pointer.
|
||||||
|
* If the pointer is different, mpv_render_context_free() is not safe. (The
|
||||||
|
* reason is that if MPV_RENDER_PARAM_ADVANCED_CONTROL is set, it may have
|
||||||
|
* to process still queued requests from the core, which it can do only for
|
||||||
|
* the current context, while requests for other contexts would deadlock.
|
||||||
|
* Also, it may have to wait and block for the core to terminate the video
|
||||||
|
* chain to make sure no resources are used after context destruction.)
|
||||||
|
* - if the mpv_handle parameter refers to a different mpv core than the one
|
||||||
|
* you're rendering for (very obscure, but allowed)
|
||||||
|
*
|
||||||
|
* Note about old libmpv version:
|
||||||
|
*
|
||||||
|
* Before API version 1.105 (basically in mpv 0.29.x), simply enabling
|
||||||
|
* MPV_RENDER_PARAM_ADVANCED_CONTROL could cause deadlock issues. This can
|
||||||
|
* be worked around by setting the "vd-lavc-dr" option to "no".
|
||||||
|
* In addition, you were required to call all mpv_render*() API functions
|
||||||
|
* from the same thread on which mpv_render_context_create() was originally
|
||||||
|
* run (for the same the mpv_render_context). Not honoring it led to UB
|
||||||
|
* (deadlocks, use of invalid pthread_t handles), even if you moved your GL
|
||||||
|
* context to a different thread correctly.
|
||||||
|
* These problems were addressed in API version 1.105 (mpv 0.30.0).
|
||||||
|
*
|
||||||
|
* Context and handle lifecycle
|
||||||
|
* ----------------------------
|
||||||
|
*
|
||||||
|
* Video initialization will fail if the render context was not initialized yet
|
||||||
|
* (with mpv_render_context_create()), or it will revert to a VO that creates
|
||||||
|
* its own window.
|
||||||
|
*
|
||||||
|
* Currently, there can be only 1 mpv_render_context at a time per mpv core.
|
||||||
|
*
|
||||||
|
* Calling mpv_render_context_free() while a VO is using the render context is
|
||||||
|
* active will disable video.
|
||||||
|
*
|
||||||
|
* You must free the context with mpv_render_context_free() before the mpv core
|
||||||
|
* is destroyed. If this doesn't happen, undefined behavior will result.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque context, returned by mpv_render_context_create().
|
||||||
|
*/
|
||||||
|
typedef struct mpv_render_context mpv_render_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for mpv_render_param (which is used in a few places such as
|
||||||
|
* mpv_render_context_create().
|
||||||
|
*
|
||||||
|
* Also see mpv_render_param for conventions and how to use it.
|
||||||
|
*/
|
||||||
|
typedef enum mpv_render_param_type {
|
||||||
|
/**
|
||||||
|
* Not a valid value, but also used to terminate a params array. Its value
|
||||||
|
* is always guaranteed to be 0 (even if the ABI changes in the future).
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_INVALID = 0,
|
||||||
|
/**
|
||||||
|
* The render API to use. Valid for mpv_render_context_create().
|
||||||
|
*
|
||||||
|
* Type: char*
|
||||||
|
*
|
||||||
|
* Defined APIs:
|
||||||
|
*
|
||||||
|
* MPV_RENDER_API_TYPE_OPENGL:
|
||||||
|
* OpenGL desktop 2.1 or later (preferably core profile compatible to
|
||||||
|
* OpenGL 3.2), or OpenGLES 2.0 or later.
|
||||||
|
* Providing MPV_RENDER_PARAM_OPENGL_INIT_PARAMS is required.
|
||||||
|
* It is expected that an OpenGL context is valid and "current" when
|
||||||
|
* calling mpv_render_* functions (unless specified otherwise). It
|
||||||
|
* must be the same context for the same mpv_render_context.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_API_TYPE = 1,
|
||||||
|
/**
|
||||||
|
* Required parameters for initializing the OpenGL renderer. Valid for
|
||||||
|
* mpv_render_context_create().
|
||||||
|
* Type: mpv_opengl_init_params*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_OPENGL_INIT_PARAMS = 2,
|
||||||
|
/**
|
||||||
|
* Describes a GL render target. Valid for mpv_render_context_render().
|
||||||
|
* Type: mpv_opengl_fbo*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_OPENGL_FBO = 3,
|
||||||
|
/**
|
||||||
|
* Control flipped rendering. Valid for mpv_render_context_render().
|
||||||
|
* Type: int*
|
||||||
|
* If the value is set to 0, render normally. Otherwise, render it flipped,
|
||||||
|
* which is needed e.g. when rendering to an OpenGL default framebuffer
|
||||||
|
* (which has a flipped coordinate system).
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_FLIP_Y = 4,
|
||||||
|
/**
|
||||||
|
* Control surface depth. Valid for mpv_render_context_render().
|
||||||
|
* Type: int*
|
||||||
|
* This implies the depth of the surface passed to the render function in
|
||||||
|
* bits per channel. If omitted or set to 0, the renderer will assume 8.
|
||||||
|
* Typically used to control dithering.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DEPTH = 5,
|
||||||
|
/**
|
||||||
|
* ICC profile blob. Valid for mpv_render_context_set_parameter().
|
||||||
|
* Type: mpv_byte_array*
|
||||||
|
* Set an ICC profile for use with the "icc-profile-auto" option. (If the
|
||||||
|
* option is not enabled, the ICC data will not be used.)
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_ICC_PROFILE = 6,
|
||||||
|
/**
|
||||||
|
* Ambient light in lux. Valid for mpv_render_context_set_parameter().
|
||||||
|
* Type: int*
|
||||||
|
* This can be used for automatic gamma correction.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_AMBIENT_LIGHT = 7,
|
||||||
|
/**
|
||||||
|
* X11 Display, sometimes used for hwdec. Valid for
|
||||||
|
* mpv_render_context_create(). The Display must stay valid for the lifetime
|
||||||
|
* of the mpv_render_context.
|
||||||
|
* Type: Display*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_X11_DISPLAY = 8,
|
||||||
|
/**
|
||||||
|
* Wayland display, sometimes used for hwdec. Valid for
|
||||||
|
* mpv_render_context_create(). The wl_display must stay valid for the
|
||||||
|
* lifetime of the mpv_render_context.
|
||||||
|
* Type: struct wl_display*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_WL_DISPLAY = 9,
|
||||||
|
/**
|
||||||
|
* Better control about rendering and enabling some advanced features. Valid
|
||||||
|
* for mpv_render_context_create().
|
||||||
|
*
|
||||||
|
* This conflates multiple requirements the API user promises to abide if
|
||||||
|
* this option is enabled:
|
||||||
|
*
|
||||||
|
* - The API user's render thread, which is calling the mpv_render_*()
|
||||||
|
* functions, never waits for the core. Otherwise deadlocks can happen.
|
||||||
|
* See "Threading" section.
|
||||||
|
* - The callback set with mpv_render_context_set_update_callback() can now
|
||||||
|
* be called even if there is no new frame. The API user should call the
|
||||||
|
* mpv_render_context_update() function, and interpret the return value
|
||||||
|
* for whether a new frame should be rendered.
|
||||||
|
* - Correct functionality is impossible if the update callback is not set,
|
||||||
|
* or not set soon enough after mpv_render_context_create() (the core can
|
||||||
|
* block while waiting for you to call mpv_render_context_update(), and
|
||||||
|
* if the update callback is not correctly set, it will deadlock, or
|
||||||
|
* block for too long).
|
||||||
|
*
|
||||||
|
* In general, setting this option will enable the following features (and
|
||||||
|
* possibly more):
|
||||||
|
*
|
||||||
|
* - "Direct rendering", which means the player decodes directly to a
|
||||||
|
* texture, which saves a copy per video frame ("vd-lavc-dr" option
|
||||||
|
* needs to be enabled, and the rendering backend as well as the
|
||||||
|
* underlying GPU API/driver needs to have support for it).
|
||||||
|
* - Rendering screenshots with the GPU API if supported by the backend
|
||||||
|
* (instead of using a suboptimal software fallback via libswscale).
|
||||||
|
*
|
||||||
|
* Warning: do not just add this without reading the "Threading" section
|
||||||
|
* above, and then wondering that deadlocks happen. The
|
||||||
|
* requirements are tricky. But also note that even if advanced
|
||||||
|
* control is disabled, not adhering to the rules will lead to
|
||||||
|
* playback problems. Enabling advanced controls simply makes
|
||||||
|
* violating these rules fatal.
|
||||||
|
*
|
||||||
|
* Type: int*: 0 for disable (default), 1 for enable
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_ADVANCED_CONTROL = 10,
|
||||||
|
/**
|
||||||
|
* Return information about the next frame to render. Valid for
|
||||||
|
* mpv_render_context_get_info().
|
||||||
|
*
|
||||||
|
* Type: mpv_render_frame_info*
|
||||||
|
*
|
||||||
|
* It strictly returns information about the _next_ frame. The implication
|
||||||
|
* is that e.g. mpv_render_context_update()'s return value will have
|
||||||
|
* MPV_RENDER_UPDATE_FRAME set, and the user is supposed to call
|
||||||
|
* mpv_render_context_render(). If there is no next frame, then the
|
||||||
|
* return value will have is_valid set to 0.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_NEXT_FRAME_INFO = 11,
|
||||||
|
/**
|
||||||
|
* Enable or disable video timing. Valid for mpv_render_context_render().
|
||||||
|
*
|
||||||
|
* Type: int*: 0 for disable, 1 for enable (default)
|
||||||
|
*
|
||||||
|
* When video is timed to audio, the player attempts to render video a bit
|
||||||
|
* ahead, and then do a blocking wait until the target display time is
|
||||||
|
* reached. This blocks mpv_render_context_render() for up to the amount
|
||||||
|
* specified with the "video-timing-offset" global option. You can set
|
||||||
|
* this parameter to 0 to disable this kind of waiting. If you do, it's
|
||||||
|
* recommended to use the target time value in mpv_render_frame_info to
|
||||||
|
* wait yourself, or to set the "video-timing-offset" to 0 instead.
|
||||||
|
*
|
||||||
|
* Disabling this without doing anything in addition will result in A/V sync
|
||||||
|
* being slightly off.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME = 12,
|
||||||
|
/**
|
||||||
|
* Use to skip rendering in mpv_render_context_render().
|
||||||
|
*
|
||||||
|
* Type: int*: 0 for rendering (default), 1 for skipping
|
||||||
|
*
|
||||||
|
* If this is set, you don't need to pass a target surface to the render
|
||||||
|
* function (and if you do, it's completely ignored). This can still call
|
||||||
|
* into the lower level APIs (i.e. if you use OpenGL, the OpenGL context
|
||||||
|
* must be set).
|
||||||
|
*
|
||||||
|
* Be aware that the render API will consider this frame as having been
|
||||||
|
* rendered. All other normal rules also apply, for example about whether
|
||||||
|
* you have to call mpv_render_context_report_swap(). It also does timing
|
||||||
|
* in the same way.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_SKIP_RENDERING = 13,
|
||||||
|
/**
|
||||||
|
* Deprecated. Not supported. Use MPV_RENDER_PARAM_DRM_DISPLAY_V2 instead.
|
||||||
|
* Type : struct mpv_opengl_drm_params*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DRM_DISPLAY = 14,
|
||||||
|
/**
|
||||||
|
* DRM draw surface size, contains draw surface dimensions.
|
||||||
|
* Valid for mpv_render_context_create().
|
||||||
|
* Type : struct mpv_opengl_drm_draw_surface_size*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE = 15,
|
||||||
|
/**
|
||||||
|
* DRM display, contains drm display handles.
|
||||||
|
* Valid for mpv_render_context_create().
|
||||||
|
* Type : struct mpv_opengl_drm_params_v2*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DRM_DISPLAY_V2 = 16,
|
||||||
|
} mpv_render_param_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For backwards compatibility with the old naming of
|
||||||
|
* MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE
|
||||||
|
*/
|
||||||
|
#define MPV_RENDER_PARAM_DRM_OSD_SIZE MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to pass arbitrary parameters to some mpv_render_* functions. The
|
||||||
|
* meaning of the data parameter is determined by the type, and each
|
||||||
|
* MPV_RENDER_PARAM_* documents what type the value must point to.
|
||||||
|
*
|
||||||
|
* Each value documents the required data type as the pointer you cast to
|
||||||
|
* void* and set on mpv_render_param.data. For example, if MPV_RENDER_PARAM_FOO
|
||||||
|
* documents the type as Something* , then the code should look like this:
|
||||||
|
*
|
||||||
|
* Something foo = {...};
|
||||||
|
* mpv_render_param param;
|
||||||
|
* param.type = MPV_RENDER_PARAM_FOO;
|
||||||
|
* param.data = & foo;
|
||||||
|
*
|
||||||
|
* Normally, the data field points to exactly 1 object. If the type is char*,
|
||||||
|
* it points to a 0-terminated string.
|
||||||
|
*
|
||||||
|
* In all cases (unless documented otherwise) the pointers need to remain
|
||||||
|
* valid during the call only. Unless otherwise documented, the API functions
|
||||||
|
* will not write to the params array or any data pointed to it.
|
||||||
|
*
|
||||||
|
* As a convention, parameter arrays are always terminated by type==0. There
|
||||||
|
* is no specific order of the parameters required. The order of the 2 fields in
|
||||||
|
* this struct is guaranteed (even after ABI changes).
|
||||||
|
*/
|
||||||
|
typedef struct mpv_render_param {
|
||||||
|
enum mpv_render_param_type type;
|
||||||
|
void *data;
|
||||||
|
} mpv_render_param;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined values for MPV_RENDER_PARAM_API_TYPE.
|
||||||
|
*/
|
||||||
|
#define MPV_RENDER_API_TYPE_OPENGL "opengl"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags used in mpv_render_frame_info.flags. Each value represents a bit in it.
|
||||||
|
*/
|
||||||
|
typedef enum mpv_render_frame_info_flag {
|
||||||
|
/**
|
||||||
|
* Set if there is actually a next frame. If unset, there is no next frame
|
||||||
|
* yet, and other flags and fields that require a frame to be queued will
|
||||||
|
* be unset.
|
||||||
|
*
|
||||||
|
* This is set for _any_ kind of frame, even for redraw requests.
|
||||||
|
*
|
||||||
|
* Note that when this is unset, it simply means no new frame was
|
||||||
|
* decoded/queued yet, not necessarily that the end of the video was
|
||||||
|
* reached. A new frame can be queued after some time.
|
||||||
|
*
|
||||||
|
* If the return value of mpv_render_context_render() had the
|
||||||
|
* MPV_RENDER_UPDATE_FRAME flag set, this flag will usually be set as well,
|
||||||
|
* unless the frame is rendered, or discarded by other asynchronous events.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_PRESENT = 1 << 0,
|
||||||
|
/**
|
||||||
|
* If set, the frame is not an actual new video frame, but a redraw request.
|
||||||
|
* For example if the video is paused, and an option that affects video
|
||||||
|
* rendering was changed (or any other reason), an update request can be
|
||||||
|
* issued and this flag will be set.
|
||||||
|
*
|
||||||
|
* Typically, redraw frames will not be subject to video timing.
|
||||||
|
*
|
||||||
|
* Implies MPV_RENDER_FRAME_INFO_PRESENT.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_REDRAW = 1 << 1,
|
||||||
|
/**
|
||||||
|
* If set, this is supposed to reproduce the previous frame perfectly. This
|
||||||
|
* is usually used for certain "video-sync" options ("display-..." modes).
|
||||||
|
* Typically the renderer will blit the video from a FBO. Unset otherwise.
|
||||||
|
*
|
||||||
|
* Implies MPV_RENDER_FRAME_INFO_PRESENT.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_REPEAT = 1 << 2,
|
||||||
|
/**
|
||||||
|
* If set, the player timing code expects that the user thread blocks on
|
||||||
|
* vsync (by either delaying the render call, or by making a call to
|
||||||
|
* mpv_render_context_report_swap() at vsync time).
|
||||||
|
*
|
||||||
|
* Implies MPV_RENDER_FRAME_INFO_PRESENT.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_BLOCK_VSYNC = 1 << 3,
|
||||||
|
} mpv_render_frame_info_flag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the next video frame that will be rendered. Can be
|
||||||
|
* retrieved with MPV_RENDER_PARAM_NEXT_FRAME_INFO.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_render_frame_info {
|
||||||
|
/**
|
||||||
|
* A bitset of mpv_render_frame_info_flag values (i.e. multiple flags are
|
||||||
|
* combined with bitwise or).
|
||||||
|
*/
|
||||||
|
uint64_t flags;
|
||||||
|
/**
|
||||||
|
* Absolute time at which the frame is supposed to be displayed. This is in
|
||||||
|
* the same unit and base as the time returned by mpv_get_time_us(). For
|
||||||
|
* frames that are redrawn, or if vsync locked video timing is used (see
|
||||||
|
* "video-sync" option), then this can be 0. The "video-timing-offset"
|
||||||
|
* option determines how much "headroom" the render thread gets (but a high
|
||||||
|
* enough frame rate can reduce it anyway). mpv_render_context_render() will
|
||||||
|
* normally block until the time is elapsed, unless you pass it
|
||||||
|
* MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME = 0.
|
||||||
|
*/
|
||||||
|
int64_t target_time;
|
||||||
|
} mpv_render_frame_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the renderer state. Depending on the backend used, this will
|
||||||
|
* access the underlying GPU API and initialize its own objects.
|
||||||
|
*
|
||||||
|
* You must free the context with mpv_render_context_free(). Not doing so before
|
||||||
|
* the mpv core is destroyed may result in memory leaks or crashes.
|
||||||
|
*
|
||||||
|
* Currently, only at most 1 context can exists per mpv core (it represents the
|
||||||
|
* main video output).
|
||||||
|
*
|
||||||
|
* You should pass the following parameters:
|
||||||
|
* - MPV_RENDER_PARAM_API_TYPE to select the underlying backend/GPU API.
|
||||||
|
* - Backend-specific init parameter, like MPV_RENDER_PARAM_OPENGL_INIT_PARAMS.
|
||||||
|
* - Setting MPV_RENDER_PARAM_ADVANCED_CONTROL and following its rules is
|
||||||
|
* strongly recommended.
|
||||||
|
* - If you want to use hwdec, possibly hwdec interop resources.
|
||||||
|
*
|
||||||
|
* @param res set to the context (on success) or NULL (on failure). The value
|
||||||
|
* is never read and always overwritten.
|
||||||
|
* @param mpv handle used to get the core (the mpv_render_context won't depend
|
||||||
|
* on this specific handle, only the core referenced by it)
|
||||||
|
* @param params an array of parameters, terminated by type==0. It's left
|
||||||
|
* unspecified what happens with unknown parameters. At least
|
||||||
|
* MPV_RENDER_PARAM_API_TYPE is required, and most backends will
|
||||||
|
* require another backend-specific parameter.
|
||||||
|
* @return error code, including but not limited to:
|
||||||
|
* MPV_ERROR_UNSUPPORTED: the OpenGL version is not supported
|
||||||
|
* (or required extensions are missing)
|
||||||
|
* MPV_ERROR_NOT_IMPLEMENTED: an unknown API type was provided, or
|
||||||
|
* support for the requested API was not
|
||||||
|
* built in the used libmpv binary.
|
||||||
|
* MPV_ERROR_INVALID_PARAMETER: at least one of the provided parameters was
|
||||||
|
* not valid.
|
||||||
|
*/
|
||||||
|
int mpv_render_context_create(mpv_render_context **res, mpv_handle *mpv,
|
||||||
|
mpv_render_param *params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to change a single parameter. Not all backends and parameter types
|
||||||
|
* support all kinds of changes.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
* @param param the parameter type and data that should be set
|
||||||
|
* @return error code. If a parameter could actually be changed, this returns
|
||||||
|
* success, otherwise an error code depending on the parameter type
|
||||||
|
* and situation.
|
||||||
|
*/
|
||||||
|
int mpv_render_context_set_parameter(mpv_render_context *ctx,
|
||||||
|
mpv_render_param param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve information from the render context. This is NOT a counterpart to
|
||||||
|
* mpv_render_context_set_parameter(), because you generally can't read
|
||||||
|
* parameters set with it, and this function is not meant for this purpose.
|
||||||
|
* Instead, this is for communicating information from the renderer back to the
|
||||||
|
* user. See mpv_render_param_type; entries which support this function
|
||||||
|
* explicitly mention it, and for other entries you can assume it will fail.
|
||||||
|
*
|
||||||
|
* You pass param with param.type set and param.data pointing to a variable
|
||||||
|
* of the required data type. The function will then overwrite that variable
|
||||||
|
* with the returned value (at least on success).
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
* @param param the parameter type and data that should be retrieved
|
||||||
|
* @return error code. If a parameter could actually be retrieved, this returns
|
||||||
|
* success, otherwise an error code depending on the parameter type
|
||||||
|
* and situation. MPV_ERROR_NOT_IMPLEMENTED is used for unknown
|
||||||
|
* param.type, or if retrieving it is not supported.
|
||||||
|
*/
|
||||||
|
int mpv_render_context_get_info(mpv_render_context *ctx,
|
||||||
|
mpv_render_param param);
|
||||||
|
|
||||||
|
typedef void (*mpv_render_update_fn)(void *cb_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callback that notifies you when a new video frame is available, or
|
||||||
|
* if the video display configuration somehow changed and requires a redraw.
|
||||||
|
* Similar to mpv_set_wakeup_callback(), you must not call any mpv API from
|
||||||
|
* the callback, and all the other listed restrictions apply (such as not
|
||||||
|
* exiting the callback by throwing exceptions).
|
||||||
|
*
|
||||||
|
* This can be called from any thread, except from an update callback. In case
|
||||||
|
* of the OpenGL backend, no OpenGL state or API is accessed.
|
||||||
|
*
|
||||||
|
* Calling this will raise an update callback immediately.
|
||||||
|
*
|
||||||
|
* @param callback callback(callback_ctx) is called if the frame should be
|
||||||
|
* redrawn
|
||||||
|
* @param callback_ctx opaque argument to the callback
|
||||||
|
*/
|
||||||
|
void mpv_render_context_set_update_callback(mpv_render_context *ctx,
|
||||||
|
mpv_render_update_fn callback,
|
||||||
|
void *callback_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The API user is supposed to call this when the update callback was invoked
|
||||||
|
* (like all mpv_render_* functions, this has to happen on the render thread,
|
||||||
|
* and _not_ from the update callback itself).
|
||||||
|
*
|
||||||
|
* This is optional if MPV_RENDER_PARAM_ADVANCED_CONTROL was not set (default).
|
||||||
|
* Otherwise, it's a hard requirement that this is called after each update
|
||||||
|
* callback. If multiple update callback happened, and the function could not
|
||||||
|
* be called sooner, it's OK to call it once after the last callback.
|
||||||
|
*
|
||||||
|
* If an update callback happens during or after this function, the function
|
||||||
|
* must be called again at the soonest possible time.
|
||||||
|
*
|
||||||
|
* If MPV_RENDER_PARAM_ADVANCED_CONTROL was set, this will do additional work
|
||||||
|
* such as allocating textures for the video decoder.
|
||||||
|
*
|
||||||
|
* @return a bitset of mpv_render_update_flag values (i.e. multiple flags are
|
||||||
|
* combined with bitwise or). Typically, this will tell the API user
|
||||||
|
* what should happen next. E.g. if the MPV_RENDER_UPDATE_FRAME flag is
|
||||||
|
* set, mpv_render_context_render() should be called. If flags unknown
|
||||||
|
* to the API user are set, or if the return value is 0, nothing needs
|
||||||
|
* to be done.
|
||||||
|
*/
|
||||||
|
uint64_t mpv_render_context_update(mpv_render_context *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags returned by mpv_render_context_update(). Each value represents a bit
|
||||||
|
* in the function's return value.
|
||||||
|
*/
|
||||||
|
typedef enum mpv_render_update_flag {
|
||||||
|
/**
|
||||||
|
* A new video frame must be rendered. mpv_render_context_render() must be
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_UPDATE_FRAME = 1 << 0,
|
||||||
|
} mpv_render_context_flag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render video.
|
||||||
|
*
|
||||||
|
* Typically renders the video to a target surface provided via mpv_render_param
|
||||||
|
* (the details depend on the backend in use). Options like "panscan" are
|
||||||
|
* applied to determine which part of the video should be visible and how the
|
||||||
|
* video should be scaled. You can change these options at runtime by using the
|
||||||
|
* mpv property API.
|
||||||
|
*
|
||||||
|
* The renderer will reconfigure itself every time the target surface
|
||||||
|
* configuration (such as size) is changed.
|
||||||
|
*
|
||||||
|
* This function implicitly pulls a video frame from the internal queue and
|
||||||
|
* renders it. If no new frame is available, the previous frame is redrawn.
|
||||||
|
* The update callback set with mpv_render_context_set_update_callback()
|
||||||
|
* notifies you when a new frame was added. The details potentially depend on
|
||||||
|
* the backends and the provided parameters.
|
||||||
|
*
|
||||||
|
* Generally, libmpv will invoke your update callback some time before the video
|
||||||
|
* frame should be shown, and then lets this function block until the supposed
|
||||||
|
* display time. This will limit your rendering to video FPS. You can prevent
|
||||||
|
* this by setting the "video-timing-offset" global option to 0. (This applies
|
||||||
|
* only to "audio" video sync mode.)
|
||||||
|
*
|
||||||
|
* You should pass the following parameters:
|
||||||
|
* - Backend-specific target object, such as MPV_RENDER_PARAM_OPENGL_FBO.
|
||||||
|
* - Possibly transformations, such as MPV_RENDER_PARAM_FLIP_Y.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
* @param params an array of parameters, terminated by type==0. Which parameters
|
||||||
|
* are required depends on the backend. It's left unspecified what
|
||||||
|
* happens with unknown parameters.
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_render_context_render(mpv_render_context *ctx, mpv_render_param *params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the renderer that a frame was flipped at the given time. This is
|
||||||
|
* optional, but can help the player to achieve better timing.
|
||||||
|
*
|
||||||
|
* Note that calling this at least once informs libmpv that you will use this
|
||||||
|
* function. If you use it inconsistently, expect bad video playback.
|
||||||
|
*
|
||||||
|
* If this is called while no video is initialized, it is ignored.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
*/
|
||||||
|
void mpv_render_context_report_swap(mpv_render_context *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the mpv renderer state.
|
||||||
|
*
|
||||||
|
* If video is still active (e.g. a file playing), video will be disabled
|
||||||
|
* forcefully.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context. After this function returns, this is not
|
||||||
|
* a valid pointer anymore. NULL is also allowed and does nothing.
|
||||||
|
*/
|
||||||
|
void mpv_render_context_free(mpv_render_context *ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
216
mpvdemo/mpv/include/render_gl.h
Normal file
216
mpvdemo/mpv/include/render_gl.h
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/* Copyright (C) 2018 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_RENDER_GL_H_
|
||||||
|
#define MPV_CLIENT_API_RENDER_GL_H_
|
||||||
|
|
||||||
|
#include "render.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenGL backend
|
||||||
|
* --------------
|
||||||
|
*
|
||||||
|
* This header contains definitions for using OpenGL with the render.h API.
|
||||||
|
*
|
||||||
|
* OpenGL interop
|
||||||
|
* --------------
|
||||||
|
*
|
||||||
|
* The OpenGL backend has some special rules, because OpenGL itself uses
|
||||||
|
* implicit per-thread contexts, which causes additional API problems.
|
||||||
|
*
|
||||||
|
* This assumes the OpenGL context lives on a certain thread controlled by the
|
||||||
|
* API user. All mpv_render_* APIs have to be assumed to implicitly use the
|
||||||
|
* OpenGL context if you pass a mpv_render_context using the OpenGL backend,
|
||||||
|
* unless specified otherwise.
|
||||||
|
*
|
||||||
|
* The OpenGL context is indirectly accessed through the OpenGL function
|
||||||
|
* pointers returned by the get_proc_address callback in mpv_opengl_init_params.
|
||||||
|
* Generally, mpv will not load the system OpenGL library when using this API.
|
||||||
|
*
|
||||||
|
* OpenGL state
|
||||||
|
* ------------
|
||||||
|
*
|
||||||
|
* OpenGL has a large amount of implicit state. All the mpv functions mentioned
|
||||||
|
* above expect that the OpenGL state is reasonably set to OpenGL standard
|
||||||
|
* defaults. Likewise, mpv will attempt to leave the OpenGL context with
|
||||||
|
* standard defaults. The following state is excluded from this:
|
||||||
|
*
|
||||||
|
* - the glViewport state
|
||||||
|
* - the glScissor state (but GL_SCISSOR_TEST is in its default value)
|
||||||
|
* - glBlendFuncSeparate() state (but GL_BLEND is in its default value)
|
||||||
|
* - glClearColor() state
|
||||||
|
* - mpv may overwrite the callback set with glDebugMessageCallback()
|
||||||
|
* - mpv always disables GL_DITHER at init
|
||||||
|
*
|
||||||
|
* Messing with the state could be avoided by creating shared OpenGL contexts,
|
||||||
|
* but this is avoided for the sake of compatibility and interoperability.
|
||||||
|
*
|
||||||
|
* On OpenGL 2.1, mpv will strictly call functions like glGenTextures() to
|
||||||
|
* create OpenGL objects. You will have to do the same. This ensures that
|
||||||
|
* objects created by mpv and the API users don't clash. Also, legacy state
|
||||||
|
* must be either in its defaults, or not interfere with core state.
|
||||||
|
*
|
||||||
|
* API use
|
||||||
|
* -------
|
||||||
|
*
|
||||||
|
* The mpv_render_* API is used. That API supports multiple backends, and this
|
||||||
|
* section documents specifics for the OpenGL backend.
|
||||||
|
*
|
||||||
|
* Use mpv_render_context_create() with MPV_RENDER_PARAM_API_TYPE set to
|
||||||
|
* MPV_RENDER_API_TYPE_OPENGL, and MPV_RENDER_PARAM_OPENGL_INIT_PARAMS provided.
|
||||||
|
*
|
||||||
|
* Call mpv_render_context_render() with MPV_RENDER_PARAM_OPENGL_FBO to render
|
||||||
|
* the video frame to an FBO.
|
||||||
|
*
|
||||||
|
* Hardware decoding
|
||||||
|
* -----------------
|
||||||
|
*
|
||||||
|
* Hardware decoding via this API is fully supported, but requires some
|
||||||
|
* additional setup. (At least if direct hardware decoding modes are wanted,
|
||||||
|
* instead of copying back surface data from GPU to CPU RAM.)
|
||||||
|
*
|
||||||
|
* There may be certain requirements on the OpenGL implementation:
|
||||||
|
*
|
||||||
|
* - Windows: ANGLE is required (although in theory GL/DX interop could be used)
|
||||||
|
* - Intel/Linux: EGL is required, and also the native display resource needs
|
||||||
|
* to be provided (e.g. MPV_RENDER_PARAM_X11_DISPLAY for X11 and
|
||||||
|
* MPV_RENDER_PARAM_WL_DISPLAY for Wayland)
|
||||||
|
* - nVidia/Linux: Both GLX and EGL should work (GLX is required if vdpau is
|
||||||
|
* used, e.g. due to old drivers.)
|
||||||
|
* - OSX: CGL is required (CGLGetCurrentContext() returning non-NULL)
|
||||||
|
* - iOS: EAGL is required (EAGLContext.currentContext returning non-nil)
|
||||||
|
*
|
||||||
|
* Once these things are setup, hardware decoding can be enabled/disabled at
|
||||||
|
* any time by setting the "hwdec" property.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For initializing the mpv OpenGL state via MPV_RENDER_PARAM_OPENGL_INIT_PARAMS.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_init_params {
|
||||||
|
/**
|
||||||
|
* This retrieves OpenGL function pointers, and will use them in subsequent
|
||||||
|
* operation.
|
||||||
|
* Usually, you can simply call the GL context APIs from this callback (e.g.
|
||||||
|
* glXGetProcAddressARB or wglGetProcAddress), but some APIs do not always
|
||||||
|
* return pointers for all standard functions (even if present); in this
|
||||||
|
* case you have to compensate by looking up these functions yourself when
|
||||||
|
* libmpv wants to resolve them through this callback.
|
||||||
|
* libmpv will not normally attempt to resolve GL functions on its own, nor
|
||||||
|
* does it link to GL libraries directly.
|
||||||
|
*/
|
||||||
|
void *(*get_proc_address)(void *ctx, const char *name);
|
||||||
|
/**
|
||||||
|
* Value passed as ctx parameter to get_proc_address().
|
||||||
|
*/
|
||||||
|
void *get_proc_address_ctx;
|
||||||
|
/**
|
||||||
|
* This should not be used. It is deprecated and will be removed or ignored
|
||||||
|
* when the opengl_cb API is removed.
|
||||||
|
*/
|
||||||
|
const char *extra_exts;
|
||||||
|
} mpv_opengl_init_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For MPV_RENDER_PARAM_OPENGL_FBO.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_fbo {
|
||||||
|
/**
|
||||||
|
* Framebuffer object name. This must be either a valid FBO generated by
|
||||||
|
* glGenFramebuffers() that is complete and color-renderable, or 0. If the
|
||||||
|
* value is 0, this refers to the OpenGL default framebuffer.
|
||||||
|
*/
|
||||||
|
int fbo;
|
||||||
|
/**
|
||||||
|
* Valid dimensions. This must refer to the size of the framebuffer. This
|
||||||
|
* must always be set.
|
||||||
|
*/
|
||||||
|
int w, h;
|
||||||
|
/**
|
||||||
|
* Underlying texture internal format (e.g. GL_RGBA8), or 0 if unknown. If
|
||||||
|
* this is the default framebuffer, this can be an equivalent.
|
||||||
|
*/
|
||||||
|
int internal_format;
|
||||||
|
} mpv_opengl_fbo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. For MPV_RENDER_PARAM_DRM_DISPLAY.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_drm_params {
|
||||||
|
int fd;
|
||||||
|
int crtc_id;
|
||||||
|
int connector_id;
|
||||||
|
struct _drmModeAtomicReq **atomic_request_ptr;
|
||||||
|
int render_fd;
|
||||||
|
} mpv_opengl_drm_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_drm_draw_surface_size {
|
||||||
|
/**
|
||||||
|
* size of the draw plane surface in pixels.
|
||||||
|
*/
|
||||||
|
int width, height;
|
||||||
|
} mpv_opengl_drm_draw_surface_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For MPV_RENDER_PARAM_DRM_DISPLAY_V2.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_drm_params_v2 {
|
||||||
|
/**
|
||||||
|
* DRM fd (int). Set to -1 if invalid.
|
||||||
|
*/
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used crtc id
|
||||||
|
*/
|
||||||
|
int crtc_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used connector id
|
||||||
|
*/
|
||||||
|
int connector_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to a drmModeAtomicReq pointer that is being used for the renderloop.
|
||||||
|
* This pointer should hold a pointer to the atomic request pointer
|
||||||
|
* The atomic request pointer is usually changed at every renderloop.
|
||||||
|
*/
|
||||||
|
struct _drmModeAtomicReq **atomic_request_ptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DRM render node. Used for VAAPI interop.
|
||||||
|
* Set to -1 if invalid.
|
||||||
|
*/
|
||||||
|
int render_fd;
|
||||||
|
} mpv_opengl_drm_params_v2;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For backwards compatibility with the old naming of mpv_opengl_drm_draw_surface_size
|
||||||
|
*/
|
||||||
|
#define mpv_opengl_drm_osd_size mpv_opengl_drm_draw_surface_size
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
240
mpvdemo/mpv/include/stream_cb.h
Normal file
240
mpvdemo/mpv/include/stream_cb.h
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
/* Copyright (C) 2017 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_STREAM_CB_H_
|
||||||
|
#define MPV_CLIENT_API_STREAM_CB_H_
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning: this API is not stable yet.
|
||||||
|
*
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* This API can be used to make mpv read from a stream with a custom
|
||||||
|
* implementation. This interface is inspired by funopen on BSD and
|
||||||
|
* fopencookie on linux. The stream is backed by user-defined callbacks
|
||||||
|
* which can implement customized open, read, seek, size and close behaviors.
|
||||||
|
*
|
||||||
|
* Usage
|
||||||
|
* -----
|
||||||
|
*
|
||||||
|
* Register your stream callbacks with the mpv_stream_cb_add_ro() function. You
|
||||||
|
* have to provide a mpv_stream_cb_open_ro_fn callback to it (open_fn argument).
|
||||||
|
*
|
||||||
|
* Once registered, you can `loadfile myprotocol://myfile`. Your open_fn will be
|
||||||
|
* invoked with the URI and you must fill out the provided mpv_stream_cb_info
|
||||||
|
* struct. This includes your stream callbacks (like read_fn), and an opaque
|
||||||
|
* cookie, which will be passed as the first argument to all the remaining
|
||||||
|
* stream callbacks.
|
||||||
|
*
|
||||||
|
* Note that your custom callbacks must not invoke libmpv APIs as that would
|
||||||
|
* cause a deadlock. (Unless you call a different mpv_handle than the one the
|
||||||
|
* callback was registered for, and the mpv_handles refer to different mpv
|
||||||
|
* instances.)
|
||||||
|
*
|
||||||
|
* Stream lifetime
|
||||||
|
* ---------------
|
||||||
|
*
|
||||||
|
* A stream remains valid until its close callback has been called. It's up to
|
||||||
|
* libmpv to call the close callback, and the libmpv user cannot close it
|
||||||
|
* directly with the stream_cb API.
|
||||||
|
*
|
||||||
|
* For example, if you consider your custom stream to become suddenly invalid
|
||||||
|
* (maybe because the underlying stream died), libmpv will continue using your
|
||||||
|
* stream. All you can do is returning errors from each callback, until libmpv
|
||||||
|
* gives up and closes it.
|
||||||
|
*
|
||||||
|
* Protocol registration and lifetime
|
||||||
|
* ----------------------------------
|
||||||
|
*
|
||||||
|
* Protocols remain registered until the mpv instance is terminated. This means
|
||||||
|
* in particular that it can outlive the mpv_handle that was used to register
|
||||||
|
* it, but once mpv_terminate_destroy() is called, your registered callbacks
|
||||||
|
* will not be called again.
|
||||||
|
*
|
||||||
|
* Protocol unregistration is finished after the mpv core has been destroyed
|
||||||
|
* (e.g. after mpv_terminate_destroy() has returned).
|
||||||
|
*
|
||||||
|
* If you do not call mpv_terminate_destroy() yourself (e.g. plugin-style code),
|
||||||
|
* you will have to deal with the registration or even streams outliving your
|
||||||
|
* code. Here are some possible ways to do this:
|
||||||
|
* - call mpv_terminate_destroy(), which destroys the core, and will make sure
|
||||||
|
* all streams are closed once this function returns
|
||||||
|
* - you refcount all resources your stream "cookies" reference, so that it
|
||||||
|
* doesn't matter if streams live longer than expected
|
||||||
|
* - create "cancellation" semantics: after your protocol has been unregistered,
|
||||||
|
* notify all your streams that are still opened, and make them drop all
|
||||||
|
* referenced resources - then return errors from the stream callbacks as
|
||||||
|
* long as the stream is still opened
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read callback used to implement a custom stream. The semantics of the
|
||||||
|
* callback match read(2) in blocking mode. Short reads are allowed (you can
|
||||||
|
* return less bytes than requested, and libmpv will retry reading the rest
|
||||||
|
* with another call). If no data can be immediately read, the callback must
|
||||||
|
* block until there is new data. A return of 0 will be interpreted as final
|
||||||
|
* EOF, although libmpv might retry the read, or seek to a different position.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
* @param buf buffer to read data into
|
||||||
|
* @param size of the buffer
|
||||||
|
* @return number of bytes read into the buffer
|
||||||
|
* @return 0 on EOF
|
||||||
|
* @return -1 on error
|
||||||
|
*/
|
||||||
|
typedef int64_t (*mpv_stream_cb_read_fn)(void *cookie, char *buf, uint64_t nbytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* Note that mpv will issue a seek to position 0 immediately after opening. This
|
||||||
|
* is used to test whether the stream is seekable (since seekability might
|
||||||
|
* depend on the URI contents, not just the protocol). Return
|
||||||
|
* MPV_ERROR_UNSUPPORTED if seeking is not implemented for this stream. This
|
||||||
|
* seek also serves to establish the fact that streams start at position 0.
|
||||||
|
*
|
||||||
|
* This callback can be NULL, in which it behaves as if always returning
|
||||||
|
* MPV_ERROR_UNSUPPORTED.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
* @param offset target absolut stream position
|
||||||
|
* @return the resulting offset of the stream
|
||||||
|
* MPV_ERROR_UNSUPPORTED or MPV_ERROR_GENERIC if the seek failed
|
||||||
|
*/
|
||||||
|
typedef int64_t (*mpv_stream_cb_seek_fn)(void *cookie, int64_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* Return MPV_ERROR_UNSUPPORTED if no size is known.
|
||||||
|
*
|
||||||
|
* This callback can be NULL, in which it behaves as if always returning
|
||||||
|
* MPV_ERROR_UNSUPPORTED.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
* @return the total size in bytes of the stream
|
||||||
|
*/
|
||||||
|
typedef int64_t (*mpv_stream_cb_size_fn)(void *cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
*/
|
||||||
|
typedef void (*mpv_stream_cb_close_fn)(void *cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* This callback is used to interrupt any current or future read and seek
|
||||||
|
* operations. It will be called from a separate thread than the demux
|
||||||
|
* thread, and should not block.
|
||||||
|
*
|
||||||
|
* This callback can be NULL.
|
||||||
|
*
|
||||||
|
* Available since API 1.106.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
*/
|
||||||
|
typedef void (*mpv_stream_cb_cancel_fn)(void *cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See mpv_stream_cb_open_ro_fn callback.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_stream_cb_info {
|
||||||
|
/**
|
||||||
|
* Opaque user-provided value, which will be passed to the other callbacks.
|
||||||
|
* The close callback will be called to release the cookie. It is not
|
||||||
|
* interpreted by mpv. It doesn't even need to be a valid pointer.
|
||||||
|
*
|
||||||
|
* The user sets this in the mpv_stream_cb_open_ro_fn callback.
|
||||||
|
*/
|
||||||
|
void *cookie;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callbacks set by the user in the mpv_stream_cb_open_ro_fn callback. Some
|
||||||
|
* of them are optional, and can be left unset.
|
||||||
|
*
|
||||||
|
* The following callbacks are mandatory: read_fn, close_fn
|
||||||
|
*/
|
||||||
|
mpv_stream_cb_read_fn read_fn;
|
||||||
|
mpv_stream_cb_seek_fn seek_fn;
|
||||||
|
mpv_stream_cb_size_fn size_fn;
|
||||||
|
mpv_stream_cb_close_fn close_fn;
|
||||||
|
mpv_stream_cb_cancel_fn cancel_fn; /* since API 1.106 */
|
||||||
|
} mpv_stream_cb_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open callback used to implement a custom read-only (ro) stream. The user
|
||||||
|
* must set the callback fields in the passed info struct. The cookie field
|
||||||
|
* also can be set to store state associated to the stream instance.
|
||||||
|
*
|
||||||
|
* Note that the info struct is valid only for the duration of this callback.
|
||||||
|
* You can't change the callbacks or the pointer to the cookie at a later point.
|
||||||
|
*
|
||||||
|
* Each stream instance created by the open callback can have different
|
||||||
|
* callbacks.
|
||||||
|
*
|
||||||
|
* The close_fn callback will terminate the stream instance. The pointers to
|
||||||
|
* your callbacks and cookie will be discarded, and the callbacks will not be
|
||||||
|
* called again.
|
||||||
|
*
|
||||||
|
* @param user_data opaque user data provided via mpv_stream_cb_add()
|
||||||
|
* @param uri name of the stream to be opened (with protocol prefix)
|
||||||
|
* @param info fields which the user should fill
|
||||||
|
* @return 0 on success, MPV_ERROR_LOADING_FAILED if the URI cannot be opened.
|
||||||
|
*/
|
||||||
|
typedef int (*mpv_stream_cb_open_ro_fn)(void *user_data, char *uri,
|
||||||
|
mpv_stream_cb_info *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a custom stream protocol. This will register a protocol handler under
|
||||||
|
* the given protocol prefix, and invoke the given callbacks if an URI with the
|
||||||
|
* matching protocol prefix is opened.
|
||||||
|
*
|
||||||
|
* The "ro" is for read-only - only read-only streams can be registered with
|
||||||
|
* this function.
|
||||||
|
*
|
||||||
|
* The callback remains registered until the mpv core is registered.
|
||||||
|
*
|
||||||
|
* If a custom stream with the same name is already registered, then the
|
||||||
|
* MPV_ERROR_INVALID_PARAMETER error is returned.
|
||||||
|
*
|
||||||
|
* @param protocol protocol prefix, for example "foo" for "foo://" URIs
|
||||||
|
* @param user_data opaque pointer passed into the mpv_stream_cb_open_fn
|
||||||
|
* callback.
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_stream_cb_add_ro(mpv_handle *ctx, const char *protocol, void *user_data,
|
||||||
|
mpv_stream_cb_open_ro_fn open_fn);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
1979
mpvdemo/mpv/include64/client.h
Normal file
1979
mpvdemo/mpv/include64/client.h
Normal file
File diff suppressed because it is too large
Load Diff
339
mpvdemo/mpv/include64/opengl_cb.h
Normal file
339
mpvdemo/mpv/include64/opengl_cb.h
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
/* Copyright (C) 2017 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_OPENGL_CB_H_
|
||||||
|
#define MPV_CLIENT_API_OPENGL_CB_H_
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#if !MPV_ENABLE_DEPRECATED
|
||||||
|
#error "This header and all API provided by it is deprecated. Use render.h instead."
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* Warning: this API is deprecated. A very similar API is provided by render.h
|
||||||
|
* and render_gl.h. The deprecated API is emulated with the new API.
|
||||||
|
*
|
||||||
|
* This API can be used to make mpv render into a foreign OpenGL context. It
|
||||||
|
* can be used to handle video display.
|
||||||
|
*
|
||||||
|
* The renderer needs to be explicitly initialized with mpv_opengl_cb_init_gl(),
|
||||||
|
* and then video can be drawn with mpv_opengl_cb_draw(). The user thread can
|
||||||
|
* be notified by new frames with mpv_opengl_cb_set_update_callback().
|
||||||
|
*
|
||||||
|
* You can output and embed video without this API by setting the mpv "wid"
|
||||||
|
* option to a native window handle (see "Embedding the video window" section
|
||||||
|
* in the client.h header). In general, using the opengl-cb API is recommended,
|
||||||
|
* because window embedding can cause various issues, especially with GUI
|
||||||
|
* toolkits and certain platforms.
|
||||||
|
*
|
||||||
|
* OpenGL interop
|
||||||
|
* --------------
|
||||||
|
*
|
||||||
|
* This assumes the OpenGL context lives on a certain thread controlled by the
|
||||||
|
* API user. The following functions require access to the OpenGL context:
|
||||||
|
* mpv_opengl_cb_init_gl
|
||||||
|
* mpv_opengl_cb_draw
|
||||||
|
* mpv_opengl_cb_uninit_gl
|
||||||
|
*
|
||||||
|
* The OpenGL context is indirectly accessed through the OpenGL function
|
||||||
|
* pointers returned by the get_proc_address callback in mpv_opengl_cb_init_gl.
|
||||||
|
* Generally, mpv will not load the system OpenGL library when using this API.
|
||||||
|
*
|
||||||
|
* Only "desktop" OpenGL version 2.1 and later and OpenGL ES version 2.0 and
|
||||||
|
* later are supported. With OpenGL 2.1, the GL_ARB_texture_rg is required. The
|
||||||
|
* renderer was written for the OpenGL 3.x core profile, with additional support
|
||||||
|
* for OpenGL 2.1 and OpenGL ES 2.0.
|
||||||
|
*
|
||||||
|
* Note that some hardware decoding interop API (as set with the "hwdec" option)
|
||||||
|
* may actually access some sort of host API, such as EGL.
|
||||||
|
*
|
||||||
|
* OpenGL state
|
||||||
|
* ------------
|
||||||
|
*
|
||||||
|
* OpenGL has a large amount of implicit state. All the mpv functions mentioned
|
||||||
|
* above expect that the OpenGL state is reasonably set to OpenGL standard
|
||||||
|
* defaults. Likewise, mpv will attempt to leave the OpenGL context with
|
||||||
|
* standard defaults. The following state is excluded from this:
|
||||||
|
*
|
||||||
|
* - the glViewport state
|
||||||
|
* - the glScissor state (but GL_SCISSOR_TEST is in its default value)
|
||||||
|
* - glBlendFuncSeparate() state (but GL_BLEND is in its default value)
|
||||||
|
* - glClearColor() state
|
||||||
|
* - mpv may overwrite the callback set with glDebugMessageCallback()
|
||||||
|
* - mpv always disables GL_DITHER at init
|
||||||
|
*
|
||||||
|
* Messing with the state could be avoided by creating shared OpenGL contexts,
|
||||||
|
* but this is avoided for the sake of compatibility and interoperability.
|
||||||
|
*
|
||||||
|
* On OpenGL 2.1, mpv will strictly call functions like glGenTextures() to
|
||||||
|
* create OpenGL objects. You will have to do the same. This ensures that
|
||||||
|
* objects created by mpv and the API users don't clash. Also, legacy state
|
||||||
|
* must be either in its defaults, or not interfere with core state.
|
||||||
|
*
|
||||||
|
* Threading
|
||||||
|
* ---------
|
||||||
|
*
|
||||||
|
* The mpv_opengl_cb_* functions can be called from any thread, under the
|
||||||
|
* following conditions:
|
||||||
|
* - only one of the mpv_opengl_cb_* functions can be called at the same time
|
||||||
|
* (unless they belong to different mpv cores created by mpv_create())
|
||||||
|
* - for functions which need an OpenGL context (see above) the OpenGL context
|
||||||
|
* must be "current" in the current thread, and it must be the same context
|
||||||
|
* as used with mpv_opengl_cb_init_gl()
|
||||||
|
* - never can be called from within the callbacks set with
|
||||||
|
* mpv_set_wakeup_callback() or mpv_opengl_cb_set_update_callback()
|
||||||
|
*
|
||||||
|
* Context and handle lifecycle
|
||||||
|
* ----------------------------
|
||||||
|
*
|
||||||
|
* Video initialization will fail if the OpenGL context was not initialized yet
|
||||||
|
* (with mpv_opengl_cb_init_gl()). Likewise, mpv_opengl_cb_uninit_gl() will
|
||||||
|
* disable video.
|
||||||
|
*
|
||||||
|
* When the mpv core is destroyed (e.g. via mpv_terminate_destroy()), the OpenGL
|
||||||
|
* context must have been uninitialized. If this doesn't happen, undefined
|
||||||
|
* behavior will result.
|
||||||
|
*
|
||||||
|
* Hardware decoding
|
||||||
|
* -----------------
|
||||||
|
*
|
||||||
|
* Hardware decoding via opengl_cb is fully supported, but requires some
|
||||||
|
* additional setup. (At least if direct hardware decoding modes are wanted,
|
||||||
|
* instead of copying back surface data from GPU to CPU RAM.)
|
||||||
|
*
|
||||||
|
* While "normal" mpv loads the OpenGL hardware decoding interop on demand,
|
||||||
|
* this can't be done with opengl_cb for internal technical reasons. Instead,
|
||||||
|
* it loads them by default, even if hardware decoding is not going to be used.
|
||||||
|
* In older mpv releases, this had to be done by setting the
|
||||||
|
* "opengl-hwdec-interop" or "hwdec-preload" options before calling
|
||||||
|
* mpv_opengl_cb_init_gl(). You can still use the newer "gpu-hwdec-interop"
|
||||||
|
* option to prevent loading of interop, or to load only a specific interop.
|
||||||
|
*
|
||||||
|
* There may be certain requirements on the OpenGL implementation:
|
||||||
|
* - Windows: ANGLE is required (although in theory GL/DX interop could be used)
|
||||||
|
* - Intel/Linux: EGL is required, and also a glMPGetNativeDisplay() callback
|
||||||
|
* must be provided (see sections below)
|
||||||
|
* - nVidia/Linux: Both GLX and EGL should work (GLX is required if vdpau is
|
||||||
|
* used, e.g. due to old drivers.)
|
||||||
|
* - OSX: CGL is required (CGLGetCurrentContext() returning non-NULL)
|
||||||
|
* - iOS: EAGL is required (EAGLContext.currentContext returning non-nil)
|
||||||
|
*
|
||||||
|
* Once these things are setup, hardware decoding can be enabled/disabled at
|
||||||
|
* any time by setting the "hwdec" property.
|
||||||
|
*
|
||||||
|
* Special windowing system interop considerations
|
||||||
|
* ------------------------------------------------
|
||||||
|
*
|
||||||
|
* In some cases, libmpv needs to have access to the windowing system's handles.
|
||||||
|
* This can be a pointer to a X11 "Display" for example. Usually this is needed
|
||||||
|
* only for hardware decoding.
|
||||||
|
*
|
||||||
|
* You can communicate these handles to libmpv by adding a pseudo-OpenGL
|
||||||
|
* extension "GL_MP_MPGetNativeDisplay" to the additional extension string when
|
||||||
|
* calling mpv_opengl_cb_init_gl(). The get_proc_address callback should resolve
|
||||||
|
* a function named "glMPGetNativeDisplay", which has the signature:
|
||||||
|
*
|
||||||
|
* void* GLAPIENTRY glMPGetNativeDisplay(const char* name)
|
||||||
|
*
|
||||||
|
* See below what names are defined. Usually, libmpv will use the native handle
|
||||||
|
* up until mpv_opengl_cb_uninit_gl() is called. If the name is not anything
|
||||||
|
* you know/expected, return NULL from the function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Legacy - not supported anymore.
|
||||||
|
struct mpv_opengl_cb_window_pos {
|
||||||
|
int x; // left coordinates of window (usually 0)
|
||||||
|
int y; // top coordinates of window (usually 0)
|
||||||
|
int width; // width of GL window
|
||||||
|
int height; // height of GL window
|
||||||
|
};
|
||||||
|
|
||||||
|
// Legacy - not supported anymore.
|
||||||
|
struct mpv_opengl_cb_drm_params {
|
||||||
|
// DRM fd (int). set this to -1 if invalid.
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
// currently used crtc id
|
||||||
|
int crtc_id;
|
||||||
|
|
||||||
|
// currently used connector id
|
||||||
|
int connector_id;
|
||||||
|
|
||||||
|
// pointer to the drmModeAtomicReq that is being used for the renderloop.
|
||||||
|
// This atomic request pointer should be usually created at every renderloop.
|
||||||
|
struct _drmModeAtomicReq *atomic_request;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nVidia/Linux via VDPAU requires GLX, which does not have this problem (the
|
||||||
|
* GLX API can return the current X11 Display).
|
||||||
|
*
|
||||||
|
* Windowing system interop on MS win32
|
||||||
|
* ------------------------------------
|
||||||
|
*
|
||||||
|
* You should use ANGLE, and make sure your application and libmpv are linked
|
||||||
|
* to the same ANGLE DLLs. libmpv will pick the device context (needed for
|
||||||
|
* hardware decoding) from the current ANGLE EGL context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque context, returned by mpv_get_sub_api(MPV_SUB_API_OPENGL_CB).
|
||||||
|
*
|
||||||
|
* A context is bound to the mpv_handle it was retrieved from. The context
|
||||||
|
* will always be the same (for the same mpv_handle), and is valid until the
|
||||||
|
* mpv_handle it belongs to is released.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_cb_context mpv_opengl_cb_context;
|
||||||
|
|
||||||
|
typedef void (*mpv_opengl_cb_update_fn)(void *cb_ctx);
|
||||||
|
typedef void *(*mpv_opengl_cb_get_proc_address_fn)(void *fn_ctx, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callback that notifies you when a new video frame is available, or
|
||||||
|
* if the video display configuration somehow changed and requires a redraw.
|
||||||
|
* Similar to mpv_set_wakeup_callback(), you must not call any mpv API from
|
||||||
|
* the callback, and all the other listed restrictions apply (such as not
|
||||||
|
* exiting the callback by throwing exceptions).
|
||||||
|
*
|
||||||
|
* @param callback callback(callback_ctx) is called if the frame should be
|
||||||
|
* redrawn
|
||||||
|
* @param callback_ctx opaque argument to the callback
|
||||||
|
*/
|
||||||
|
void mpv_opengl_cb_set_update_callback(mpv_opengl_cb_context *ctx,
|
||||||
|
mpv_opengl_cb_update_fn callback,
|
||||||
|
void *callback_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the mpv OpenGL state. This retrieves OpenGL function pointers via
|
||||||
|
* get_proc_address, and creates OpenGL objects needed by mpv internally. It
|
||||||
|
* will also call APIs needed for rendering hardware decoded video in OpenGL,
|
||||||
|
* according to the mpv "hwdec" option.
|
||||||
|
*
|
||||||
|
* You must free the associated state at some point by calling the
|
||||||
|
* mpv_opengl_cb_uninit_gl() function. Not doing so may result in memory leaks
|
||||||
|
* or worse.
|
||||||
|
*
|
||||||
|
* @param exts optional _additional_ extension string, can be NULL
|
||||||
|
* @param get_proc_address callback used to retrieve function pointers to OpenGL
|
||||||
|
* functions. This is used for both standard functions
|
||||||
|
* and extension functions. (The extension string is
|
||||||
|
* checked whether extensions are really available.)
|
||||||
|
* The callback will be called from this function only
|
||||||
|
* (it is not stored and never used later).
|
||||||
|
* Usually, GL context APIs do this for you (e.g. with
|
||||||
|
* glXGetProcAddressARB or wglGetProcAddress), but
|
||||||
|
* some APIs do not always return pointers for all
|
||||||
|
* standard functions (even if present); in this case
|
||||||
|
* you have to compensate by looking up these functions
|
||||||
|
* yourself.
|
||||||
|
* @param get_proc_address_ctx arbitrary opaque user context passed to the
|
||||||
|
* get_proc_address callback
|
||||||
|
* @return error code (same as normal mpv_* API), including but not limited to:
|
||||||
|
* MPV_ERROR_UNSUPPORTED: the OpenGL version is not supported
|
||||||
|
* (or required extensions are missing)
|
||||||
|
* MPV_ERROR_INVALID_PARAMETER: the OpenGL state was already initialized
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_init_gl(mpv_opengl_cb_context *ctx, const char *exts,
|
||||||
|
mpv_opengl_cb_get_proc_address_fn get_proc_address,
|
||||||
|
void *get_proc_address_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render video. Requires that the OpenGL state is initialized.
|
||||||
|
*
|
||||||
|
* The video will use the full provided framebuffer. Options like "panscan" are
|
||||||
|
* applied to determine which part of the video should be visible and how the
|
||||||
|
* video should be scaled. You can change these options at runtime by using the
|
||||||
|
* mpv property API.
|
||||||
|
*
|
||||||
|
* The renderer will reconfigure itself every time the output rectangle/size
|
||||||
|
* is changed. (If you want to do animations, it might be better to do the
|
||||||
|
* animation on a FBO instead.)
|
||||||
|
*
|
||||||
|
* This function implicitly pulls a video frame from the internal queue and
|
||||||
|
* renders it. If no new frame is available, the previous frame is redrawn.
|
||||||
|
* The update callback set with mpv_opengl_cb_set_update_callback() notifies
|
||||||
|
* you when a new frame was added.
|
||||||
|
*
|
||||||
|
* @param fbo The framebuffer object to render on. Because the renderer might
|
||||||
|
* manage multiple FBOs internally for the purpose of video
|
||||||
|
* postprocessing, it will always bind and unbind FBOs itself. If
|
||||||
|
* you want mpv to render on the main framebuffer, pass 0.
|
||||||
|
* @param w Width of the framebuffer. This is either the video size if the fbo
|
||||||
|
* parameter is 0, or the allocated size of the texture backing the
|
||||||
|
* fbo. The renderer will always use the full size of the fbo.
|
||||||
|
* @param h Height of the framebuffer. Same as with the w parameter, except
|
||||||
|
* that this parameter can be negative. In this case, the video
|
||||||
|
* frame will be rendered flipped.
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int w, int h);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. Use mpv_opengl_cb_draw(). This function is equivalent to:
|
||||||
|
*
|
||||||
|
* int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4])
|
||||||
|
* { return mpv_opengl_cb_draw(ctx, fbo, vp[2], vp[3]); }
|
||||||
|
*
|
||||||
|
* vp[0] and vp[1] used to have a meaning, but are ignored in newer versions.
|
||||||
|
*
|
||||||
|
* This function will be removed in the future without version bump (this API
|
||||||
|
* was never marked as stable).
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the renderer that a frame was flipped at the given time. This is
|
||||||
|
* optional, but can help the player to achieve better timing.
|
||||||
|
*
|
||||||
|
* Note that calling this at least once informs libmpv that you will use this
|
||||||
|
* function. If you use it inconsistently, expect bad video playback.
|
||||||
|
*
|
||||||
|
* If this is called while no video or no OpenGL is initialized, it is ignored.
|
||||||
|
*
|
||||||
|
* @param time The mpv time (using mpv_get_time_us()) at which the flip call
|
||||||
|
* returned. If 0 is passed, mpv_get_time_us() is used instead.
|
||||||
|
* Currently, this parameter is ignored.
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_report_flip(mpv_opengl_cb_context *ctx, int64_t time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the mpv OpenGL state.
|
||||||
|
*
|
||||||
|
* If video is still active (e.g. a file playing), video will be disabled
|
||||||
|
* forcefully.
|
||||||
|
*
|
||||||
|
* Calling this multiple times is ok.
|
||||||
|
*
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_opengl_cb_uninit_gl(mpv_opengl_cb_context *ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* else #if MPV_ENABLE_DEPRECATED */
|
||||||
|
|
||||||
|
#endif
|
||||||
626
mpvdemo/mpv/include64/render.h
Normal file
626
mpvdemo/mpv/include64/render.h
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
/* Copyright (C) 2018 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_RENDER_H_
|
||||||
|
#define MPV_CLIENT_API_RENDER_H_
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* This API can be used to make mpv render using supported graphic APIs (such
|
||||||
|
* as OpenGL). It can be used to handle video display.
|
||||||
|
*
|
||||||
|
* The renderer needs to be created with mpv_render_context_create() before
|
||||||
|
* you start playback (or otherwise cause a VO to be created). Then (with most
|
||||||
|
* backends) mpv_render_context_render() can be used to explicitly render the
|
||||||
|
* current video frame. Use mpv_render_context_set_update_callback() to get
|
||||||
|
* notified when there is a new frame to draw.
|
||||||
|
*
|
||||||
|
* Preferably rendering should be done in a separate thread. If you call
|
||||||
|
* normal libmpv API functions on the renderer thread, deadlocks can result
|
||||||
|
* (these are made non-fatal with timeouts, but user experience will obviously
|
||||||
|
* suffer). See "Threading" section below.
|
||||||
|
*
|
||||||
|
* You can output and embed video without this API by setting the mpv "wid"
|
||||||
|
* option to a native window handle (see "Embedding the video window" section
|
||||||
|
* in the client.h header). In general, using the render API is recommended,
|
||||||
|
* because window embedding can cause various issues, especially with GUI
|
||||||
|
* toolkits and certain platforms.
|
||||||
|
*
|
||||||
|
* Supported backends
|
||||||
|
* ------------------
|
||||||
|
*
|
||||||
|
* OpenGL: via MPV_RENDER_API_TYPE_OPENGL, see render_gl.h header.
|
||||||
|
*
|
||||||
|
* Threading
|
||||||
|
* ---------
|
||||||
|
*
|
||||||
|
* You are recommended to do rendering on a separate thread than normal libmpv
|
||||||
|
* use.
|
||||||
|
*
|
||||||
|
* The mpv_render_* functions can be called from any thread, under the
|
||||||
|
* following conditions:
|
||||||
|
* - only one of the mpv_render_* functions can be called at the same time
|
||||||
|
* (unless they belong to different mpv cores created by mpv_create())
|
||||||
|
* - never can be called from within the callbacks set with
|
||||||
|
* mpv_set_wakeup_callback() or mpv_render_context_set_update_callback()
|
||||||
|
* - if the OpenGL backend is used, for all functions the OpenGL context
|
||||||
|
* must be "current" in the calling thread, and it must be the same OpenGL
|
||||||
|
* context as the mpv_render_context was created with. Otherwise, undefined
|
||||||
|
* behavior will occur.
|
||||||
|
* - the thread does not call libmpv API functions other than the mpv_render_*
|
||||||
|
* functions, except APIs which are declared as safe (see below). Likewise,
|
||||||
|
* there must be no lock or wait dependency from the render thread to a
|
||||||
|
* thread using other libmpv functions. Basically, the situation that your
|
||||||
|
* render thread waits for a "not safe" libmpv API function to return must
|
||||||
|
* not happen. If you ignore this requirement, deadlocks can happen, which
|
||||||
|
* are made non-fatal with timeouts; then playback quality will be degraded,
|
||||||
|
* and the message
|
||||||
|
* mpv_render_context_render() not being called or stuck.
|
||||||
|
* is logged. If you set MPV_RENDER_PARAM_ADVANCED_CONTROL, you promise that
|
||||||
|
* this won't happen, and must absolutely guarantee it, or a real deadlock
|
||||||
|
* will freeze the mpv core thread forever.
|
||||||
|
*
|
||||||
|
* libmpv functions which are safe to call from a render thread are:
|
||||||
|
* - functions marked with "Safe to be called from mpv render API threads."
|
||||||
|
* - client.h functions which don't have an explicit or implicit mpv_handle
|
||||||
|
* parameter
|
||||||
|
* - mpv_render_* functions; but only for the same mpv_render_context pointer.
|
||||||
|
* If the pointer is different, mpv_render_context_free() is not safe. (The
|
||||||
|
* reason is that if MPV_RENDER_PARAM_ADVANCED_CONTROL is set, it may have
|
||||||
|
* to process still queued requests from the core, which it can do only for
|
||||||
|
* the current context, while requests for other contexts would deadlock.
|
||||||
|
* Also, it may have to wait and block for the core to terminate the video
|
||||||
|
* chain to make sure no resources are used after context destruction.)
|
||||||
|
* - if the mpv_handle parameter refers to a different mpv core than the one
|
||||||
|
* you're rendering for (very obscure, but allowed)
|
||||||
|
*
|
||||||
|
* Note about old libmpv version:
|
||||||
|
*
|
||||||
|
* Before API version 1.105 (basically in mpv 0.29.x), simply enabling
|
||||||
|
* MPV_RENDER_PARAM_ADVANCED_CONTROL could cause deadlock issues. This can
|
||||||
|
* be worked around by setting the "vd-lavc-dr" option to "no".
|
||||||
|
* In addition, you were required to call all mpv_render*() API functions
|
||||||
|
* from the same thread on which mpv_render_context_create() was originally
|
||||||
|
* run (for the same the mpv_render_context). Not honoring it led to UB
|
||||||
|
* (deadlocks, use of invalid pthread_t handles), even if you moved your GL
|
||||||
|
* context to a different thread correctly.
|
||||||
|
* These problems were addressed in API version 1.105 (mpv 0.30.0).
|
||||||
|
*
|
||||||
|
* Context and handle lifecycle
|
||||||
|
* ----------------------------
|
||||||
|
*
|
||||||
|
* Video initialization will fail if the render context was not initialized yet
|
||||||
|
* (with mpv_render_context_create()), or it will revert to a VO that creates
|
||||||
|
* its own window.
|
||||||
|
*
|
||||||
|
* Currently, there can be only 1 mpv_render_context at a time per mpv core.
|
||||||
|
*
|
||||||
|
* Calling mpv_render_context_free() while a VO is using the render context is
|
||||||
|
* active will disable video.
|
||||||
|
*
|
||||||
|
* You must free the context with mpv_render_context_free() before the mpv core
|
||||||
|
* is destroyed. If this doesn't happen, undefined behavior will result.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque context, returned by mpv_render_context_create().
|
||||||
|
*/
|
||||||
|
typedef struct mpv_render_context mpv_render_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for mpv_render_param (which is used in a few places such as
|
||||||
|
* mpv_render_context_create().
|
||||||
|
*
|
||||||
|
* Also see mpv_render_param for conventions and how to use it.
|
||||||
|
*/
|
||||||
|
typedef enum mpv_render_param_type {
|
||||||
|
/**
|
||||||
|
* Not a valid value, but also used to terminate a params array. Its value
|
||||||
|
* is always guaranteed to be 0 (even if the ABI changes in the future).
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_INVALID = 0,
|
||||||
|
/**
|
||||||
|
* The render API to use. Valid for mpv_render_context_create().
|
||||||
|
*
|
||||||
|
* Type: char*
|
||||||
|
*
|
||||||
|
* Defined APIs:
|
||||||
|
*
|
||||||
|
* MPV_RENDER_API_TYPE_OPENGL:
|
||||||
|
* OpenGL desktop 2.1 or later (preferably core profile compatible to
|
||||||
|
* OpenGL 3.2), or OpenGLES 2.0 or later.
|
||||||
|
* Providing MPV_RENDER_PARAM_OPENGL_INIT_PARAMS is required.
|
||||||
|
* It is expected that an OpenGL context is valid and "current" when
|
||||||
|
* calling mpv_render_* functions (unless specified otherwise). It
|
||||||
|
* must be the same context for the same mpv_render_context.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_API_TYPE = 1,
|
||||||
|
/**
|
||||||
|
* Required parameters for initializing the OpenGL renderer. Valid for
|
||||||
|
* mpv_render_context_create().
|
||||||
|
* Type: mpv_opengl_init_params*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_OPENGL_INIT_PARAMS = 2,
|
||||||
|
/**
|
||||||
|
* Describes a GL render target. Valid for mpv_render_context_render().
|
||||||
|
* Type: mpv_opengl_fbo*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_OPENGL_FBO = 3,
|
||||||
|
/**
|
||||||
|
* Control flipped rendering. Valid for mpv_render_context_render().
|
||||||
|
* Type: int*
|
||||||
|
* If the value is set to 0, render normally. Otherwise, render it flipped,
|
||||||
|
* which is needed e.g. when rendering to an OpenGL default framebuffer
|
||||||
|
* (which has a flipped coordinate system).
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_FLIP_Y = 4,
|
||||||
|
/**
|
||||||
|
* Control surface depth. Valid for mpv_render_context_render().
|
||||||
|
* Type: int*
|
||||||
|
* This implies the depth of the surface passed to the render function in
|
||||||
|
* bits per channel. If omitted or set to 0, the renderer will assume 8.
|
||||||
|
* Typically used to control dithering.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DEPTH = 5,
|
||||||
|
/**
|
||||||
|
* ICC profile blob. Valid for mpv_render_context_set_parameter().
|
||||||
|
* Type: mpv_byte_array*
|
||||||
|
* Set an ICC profile for use with the "icc-profile-auto" option. (If the
|
||||||
|
* option is not enabled, the ICC data will not be used.)
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_ICC_PROFILE = 6,
|
||||||
|
/**
|
||||||
|
* Ambient light in lux. Valid for mpv_render_context_set_parameter().
|
||||||
|
* Type: int*
|
||||||
|
* This can be used for automatic gamma correction.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_AMBIENT_LIGHT = 7,
|
||||||
|
/**
|
||||||
|
* X11 Display, sometimes used for hwdec. Valid for
|
||||||
|
* mpv_render_context_create(). The Display must stay valid for the lifetime
|
||||||
|
* of the mpv_render_context.
|
||||||
|
* Type: Display*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_X11_DISPLAY = 8,
|
||||||
|
/**
|
||||||
|
* Wayland display, sometimes used for hwdec. Valid for
|
||||||
|
* mpv_render_context_create(). The wl_display must stay valid for the
|
||||||
|
* lifetime of the mpv_render_context.
|
||||||
|
* Type: struct wl_display*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_WL_DISPLAY = 9,
|
||||||
|
/**
|
||||||
|
* Better control about rendering and enabling some advanced features. Valid
|
||||||
|
* for mpv_render_context_create().
|
||||||
|
*
|
||||||
|
* This conflates multiple requirements the API user promises to abide if
|
||||||
|
* this option is enabled:
|
||||||
|
*
|
||||||
|
* - The API user's render thread, which is calling the mpv_render_*()
|
||||||
|
* functions, never waits for the core. Otherwise deadlocks can happen.
|
||||||
|
* See "Threading" section.
|
||||||
|
* - The callback set with mpv_render_context_set_update_callback() can now
|
||||||
|
* be called even if there is no new frame. The API user should call the
|
||||||
|
* mpv_render_context_update() function, and interpret the return value
|
||||||
|
* for whether a new frame should be rendered.
|
||||||
|
* - Correct functionality is impossible if the update callback is not set,
|
||||||
|
* or not set soon enough after mpv_render_context_create() (the core can
|
||||||
|
* block while waiting for you to call mpv_render_context_update(), and
|
||||||
|
* if the update callback is not correctly set, it will deadlock, or
|
||||||
|
* block for too long).
|
||||||
|
*
|
||||||
|
* In general, setting this option will enable the following features (and
|
||||||
|
* possibly more):
|
||||||
|
*
|
||||||
|
* - "Direct rendering", which means the player decodes directly to a
|
||||||
|
* texture, which saves a copy per video frame ("vd-lavc-dr" option
|
||||||
|
* needs to be enabled, and the rendering backend as well as the
|
||||||
|
* underlying GPU API/driver needs to have support for it).
|
||||||
|
* - Rendering screenshots with the GPU API if supported by the backend
|
||||||
|
* (instead of using a suboptimal software fallback via libswscale).
|
||||||
|
*
|
||||||
|
* Warning: do not just add this without reading the "Threading" section
|
||||||
|
* above, and then wondering that deadlocks happen. The
|
||||||
|
* requirements are tricky. But also note that even if advanced
|
||||||
|
* control is disabled, not adhering to the rules will lead to
|
||||||
|
* playback problems. Enabling advanced controls simply makes
|
||||||
|
* violating these rules fatal.
|
||||||
|
*
|
||||||
|
* Type: int*: 0 for disable (default), 1 for enable
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_ADVANCED_CONTROL = 10,
|
||||||
|
/**
|
||||||
|
* Return information about the next frame to render. Valid for
|
||||||
|
* mpv_render_context_get_info().
|
||||||
|
*
|
||||||
|
* Type: mpv_render_frame_info*
|
||||||
|
*
|
||||||
|
* It strictly returns information about the _next_ frame. The implication
|
||||||
|
* is that e.g. mpv_render_context_update()'s return value will have
|
||||||
|
* MPV_RENDER_UPDATE_FRAME set, and the user is supposed to call
|
||||||
|
* mpv_render_context_render(). If there is no next frame, then the
|
||||||
|
* return value will have is_valid set to 0.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_NEXT_FRAME_INFO = 11,
|
||||||
|
/**
|
||||||
|
* Enable or disable video timing. Valid for mpv_render_context_render().
|
||||||
|
*
|
||||||
|
* Type: int*: 0 for disable, 1 for enable (default)
|
||||||
|
*
|
||||||
|
* When video is timed to audio, the player attempts to render video a bit
|
||||||
|
* ahead, and then do a blocking wait until the target display time is
|
||||||
|
* reached. This blocks mpv_render_context_render() for up to the amount
|
||||||
|
* specified with the "video-timing-offset" global option. You can set
|
||||||
|
* this parameter to 0 to disable this kind of waiting. If you do, it's
|
||||||
|
* recommended to use the target time value in mpv_render_frame_info to
|
||||||
|
* wait yourself, or to set the "video-timing-offset" to 0 instead.
|
||||||
|
*
|
||||||
|
* Disabling this without doing anything in addition will result in A/V sync
|
||||||
|
* being slightly off.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME = 12,
|
||||||
|
/**
|
||||||
|
* Use to skip rendering in mpv_render_context_render().
|
||||||
|
*
|
||||||
|
* Type: int*: 0 for rendering (default), 1 for skipping
|
||||||
|
*
|
||||||
|
* If this is set, you don't need to pass a target surface to the render
|
||||||
|
* function (and if you do, it's completely ignored). This can still call
|
||||||
|
* into the lower level APIs (i.e. if you use OpenGL, the OpenGL context
|
||||||
|
* must be set).
|
||||||
|
*
|
||||||
|
* Be aware that the render API will consider this frame as having been
|
||||||
|
* rendered. All other normal rules also apply, for example about whether
|
||||||
|
* you have to call mpv_render_context_report_swap(). It also does timing
|
||||||
|
* in the same way.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_SKIP_RENDERING = 13,
|
||||||
|
/**
|
||||||
|
* Deprecated. Not supported. Use MPV_RENDER_PARAM_DRM_DISPLAY_V2 instead.
|
||||||
|
* Type : struct mpv_opengl_drm_params*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DRM_DISPLAY = 14,
|
||||||
|
/**
|
||||||
|
* DRM draw surface size, contains draw surface dimensions.
|
||||||
|
* Valid for mpv_render_context_create().
|
||||||
|
* Type : struct mpv_opengl_drm_draw_surface_size*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE = 15,
|
||||||
|
/**
|
||||||
|
* DRM display, contains drm display handles.
|
||||||
|
* Valid for mpv_render_context_create().
|
||||||
|
* Type : struct mpv_opengl_drm_params_v2*
|
||||||
|
*/
|
||||||
|
MPV_RENDER_PARAM_DRM_DISPLAY_V2 = 16,
|
||||||
|
} mpv_render_param_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For backwards compatibility with the old naming of
|
||||||
|
* MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE
|
||||||
|
*/
|
||||||
|
#define MPV_RENDER_PARAM_DRM_OSD_SIZE MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to pass arbitrary parameters to some mpv_render_* functions. The
|
||||||
|
* meaning of the data parameter is determined by the type, and each
|
||||||
|
* MPV_RENDER_PARAM_* documents what type the value must point to.
|
||||||
|
*
|
||||||
|
* Each value documents the required data type as the pointer you cast to
|
||||||
|
* void* and set on mpv_render_param.data. For example, if MPV_RENDER_PARAM_FOO
|
||||||
|
* documents the type as Something* , then the code should look like this:
|
||||||
|
*
|
||||||
|
* Something foo = {...};
|
||||||
|
* mpv_render_param param;
|
||||||
|
* param.type = MPV_RENDER_PARAM_FOO;
|
||||||
|
* param.data = & foo;
|
||||||
|
*
|
||||||
|
* Normally, the data field points to exactly 1 object. If the type is char*,
|
||||||
|
* it points to a 0-terminated string.
|
||||||
|
*
|
||||||
|
* In all cases (unless documented otherwise) the pointers need to remain
|
||||||
|
* valid during the call only. Unless otherwise documented, the API functions
|
||||||
|
* will not write to the params array or any data pointed to it.
|
||||||
|
*
|
||||||
|
* As a convention, parameter arrays are always terminated by type==0. There
|
||||||
|
* is no specific order of the parameters required. The order of the 2 fields in
|
||||||
|
* this struct is guaranteed (even after ABI changes).
|
||||||
|
*/
|
||||||
|
typedef struct mpv_render_param {
|
||||||
|
enum mpv_render_param_type type;
|
||||||
|
void *data;
|
||||||
|
} mpv_render_param;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined values for MPV_RENDER_PARAM_API_TYPE.
|
||||||
|
*/
|
||||||
|
#define MPV_RENDER_API_TYPE_OPENGL "opengl"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags used in mpv_render_frame_info.flags. Each value represents a bit in it.
|
||||||
|
*/
|
||||||
|
typedef enum mpv_render_frame_info_flag {
|
||||||
|
/**
|
||||||
|
* Set if there is actually a next frame. If unset, there is no next frame
|
||||||
|
* yet, and other flags and fields that require a frame to be queued will
|
||||||
|
* be unset.
|
||||||
|
*
|
||||||
|
* This is set for _any_ kind of frame, even for redraw requests.
|
||||||
|
*
|
||||||
|
* Note that when this is unset, it simply means no new frame was
|
||||||
|
* decoded/queued yet, not necessarily that the end of the video was
|
||||||
|
* reached. A new frame can be queued after some time.
|
||||||
|
*
|
||||||
|
* If the return value of mpv_render_context_render() had the
|
||||||
|
* MPV_RENDER_UPDATE_FRAME flag set, this flag will usually be set as well,
|
||||||
|
* unless the frame is rendered, or discarded by other asynchronous events.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_PRESENT = 1 << 0,
|
||||||
|
/**
|
||||||
|
* If set, the frame is not an actual new video frame, but a redraw request.
|
||||||
|
* For example if the video is paused, and an option that affects video
|
||||||
|
* rendering was changed (or any other reason), an update request can be
|
||||||
|
* issued and this flag will be set.
|
||||||
|
*
|
||||||
|
* Typically, redraw frames will not be subject to video timing.
|
||||||
|
*
|
||||||
|
* Implies MPV_RENDER_FRAME_INFO_PRESENT.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_REDRAW = 1 << 1,
|
||||||
|
/**
|
||||||
|
* If set, this is supposed to reproduce the previous frame perfectly. This
|
||||||
|
* is usually used for certain "video-sync" options ("display-..." modes).
|
||||||
|
* Typically the renderer will blit the video from a FBO. Unset otherwise.
|
||||||
|
*
|
||||||
|
* Implies MPV_RENDER_FRAME_INFO_PRESENT.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_REPEAT = 1 << 2,
|
||||||
|
/**
|
||||||
|
* If set, the player timing code expects that the user thread blocks on
|
||||||
|
* vsync (by either delaying the render call, or by making a call to
|
||||||
|
* mpv_render_context_report_swap() at vsync time).
|
||||||
|
*
|
||||||
|
* Implies MPV_RENDER_FRAME_INFO_PRESENT.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_FRAME_INFO_BLOCK_VSYNC = 1 << 3,
|
||||||
|
} mpv_render_frame_info_flag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the next video frame that will be rendered. Can be
|
||||||
|
* retrieved with MPV_RENDER_PARAM_NEXT_FRAME_INFO.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_render_frame_info {
|
||||||
|
/**
|
||||||
|
* A bitset of mpv_render_frame_info_flag values (i.e. multiple flags are
|
||||||
|
* combined with bitwise or).
|
||||||
|
*/
|
||||||
|
uint64_t flags;
|
||||||
|
/**
|
||||||
|
* Absolute time at which the frame is supposed to be displayed. This is in
|
||||||
|
* the same unit and base as the time returned by mpv_get_time_us(). For
|
||||||
|
* frames that are redrawn, or if vsync locked video timing is used (see
|
||||||
|
* "video-sync" option), then this can be 0. The "video-timing-offset"
|
||||||
|
* option determines how much "headroom" the render thread gets (but a high
|
||||||
|
* enough frame rate can reduce it anyway). mpv_render_context_render() will
|
||||||
|
* normally block until the time is elapsed, unless you pass it
|
||||||
|
* MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME = 0.
|
||||||
|
*/
|
||||||
|
int64_t target_time;
|
||||||
|
} mpv_render_frame_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the renderer state. Depending on the backend used, this will
|
||||||
|
* access the underlying GPU API and initialize its own objects.
|
||||||
|
*
|
||||||
|
* You must free the context with mpv_render_context_free(). Not doing so before
|
||||||
|
* the mpv core is destroyed may result in memory leaks or crashes.
|
||||||
|
*
|
||||||
|
* Currently, only at most 1 context can exists per mpv core (it represents the
|
||||||
|
* main video output).
|
||||||
|
*
|
||||||
|
* You should pass the following parameters:
|
||||||
|
* - MPV_RENDER_PARAM_API_TYPE to select the underlying backend/GPU API.
|
||||||
|
* - Backend-specific init parameter, like MPV_RENDER_PARAM_OPENGL_INIT_PARAMS.
|
||||||
|
* - Setting MPV_RENDER_PARAM_ADVANCED_CONTROL and following its rules is
|
||||||
|
* strongly recommended.
|
||||||
|
* - If you want to use hwdec, possibly hwdec interop resources.
|
||||||
|
*
|
||||||
|
* @param res set to the context (on success) or NULL (on failure). The value
|
||||||
|
* is never read and always overwritten.
|
||||||
|
* @param mpv handle used to get the core (the mpv_render_context won't depend
|
||||||
|
* on this specific handle, only the core referenced by it)
|
||||||
|
* @param params an array of parameters, terminated by type==0. It's left
|
||||||
|
* unspecified what happens with unknown parameters. At least
|
||||||
|
* MPV_RENDER_PARAM_API_TYPE is required, and most backends will
|
||||||
|
* require another backend-specific parameter.
|
||||||
|
* @return error code, including but not limited to:
|
||||||
|
* MPV_ERROR_UNSUPPORTED: the OpenGL version is not supported
|
||||||
|
* (or required extensions are missing)
|
||||||
|
* MPV_ERROR_NOT_IMPLEMENTED: an unknown API type was provided, or
|
||||||
|
* support for the requested API was not
|
||||||
|
* built in the used libmpv binary.
|
||||||
|
* MPV_ERROR_INVALID_PARAMETER: at least one of the provided parameters was
|
||||||
|
* not valid.
|
||||||
|
*/
|
||||||
|
int mpv_render_context_create(mpv_render_context **res, mpv_handle *mpv,
|
||||||
|
mpv_render_param *params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to change a single parameter. Not all backends and parameter types
|
||||||
|
* support all kinds of changes.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
* @param param the parameter type and data that should be set
|
||||||
|
* @return error code. If a parameter could actually be changed, this returns
|
||||||
|
* success, otherwise an error code depending on the parameter type
|
||||||
|
* and situation.
|
||||||
|
*/
|
||||||
|
int mpv_render_context_set_parameter(mpv_render_context *ctx,
|
||||||
|
mpv_render_param param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve information from the render context. This is NOT a counterpart to
|
||||||
|
* mpv_render_context_set_parameter(), because you generally can't read
|
||||||
|
* parameters set with it, and this function is not meant for this purpose.
|
||||||
|
* Instead, this is for communicating information from the renderer back to the
|
||||||
|
* user. See mpv_render_param_type; entries which support this function
|
||||||
|
* explicitly mention it, and for other entries you can assume it will fail.
|
||||||
|
*
|
||||||
|
* You pass param with param.type set and param.data pointing to a variable
|
||||||
|
* of the required data type. The function will then overwrite that variable
|
||||||
|
* with the returned value (at least on success).
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
* @param param the parameter type and data that should be retrieved
|
||||||
|
* @return error code. If a parameter could actually be retrieved, this returns
|
||||||
|
* success, otherwise an error code depending on the parameter type
|
||||||
|
* and situation. MPV_ERROR_NOT_IMPLEMENTED is used for unknown
|
||||||
|
* param.type, or if retrieving it is not supported.
|
||||||
|
*/
|
||||||
|
int mpv_render_context_get_info(mpv_render_context *ctx,
|
||||||
|
mpv_render_param param);
|
||||||
|
|
||||||
|
typedef void (*mpv_render_update_fn)(void *cb_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callback that notifies you when a new video frame is available, or
|
||||||
|
* if the video display configuration somehow changed and requires a redraw.
|
||||||
|
* Similar to mpv_set_wakeup_callback(), you must not call any mpv API from
|
||||||
|
* the callback, and all the other listed restrictions apply (such as not
|
||||||
|
* exiting the callback by throwing exceptions).
|
||||||
|
*
|
||||||
|
* This can be called from any thread, except from an update callback. In case
|
||||||
|
* of the OpenGL backend, no OpenGL state or API is accessed.
|
||||||
|
*
|
||||||
|
* Calling this will raise an update callback immediately.
|
||||||
|
*
|
||||||
|
* @param callback callback(callback_ctx) is called if the frame should be
|
||||||
|
* redrawn
|
||||||
|
* @param callback_ctx opaque argument to the callback
|
||||||
|
*/
|
||||||
|
void mpv_render_context_set_update_callback(mpv_render_context *ctx,
|
||||||
|
mpv_render_update_fn callback,
|
||||||
|
void *callback_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The API user is supposed to call this when the update callback was invoked
|
||||||
|
* (like all mpv_render_* functions, this has to happen on the render thread,
|
||||||
|
* and _not_ from the update callback itself).
|
||||||
|
*
|
||||||
|
* This is optional if MPV_RENDER_PARAM_ADVANCED_CONTROL was not set (default).
|
||||||
|
* Otherwise, it's a hard requirement that this is called after each update
|
||||||
|
* callback. If multiple update callback happened, and the function could not
|
||||||
|
* be called sooner, it's OK to call it once after the last callback.
|
||||||
|
*
|
||||||
|
* If an update callback happens during or after this function, the function
|
||||||
|
* must be called again at the soonest possible time.
|
||||||
|
*
|
||||||
|
* If MPV_RENDER_PARAM_ADVANCED_CONTROL was set, this will do additional work
|
||||||
|
* such as allocating textures for the video decoder.
|
||||||
|
*
|
||||||
|
* @return a bitset of mpv_render_update_flag values (i.e. multiple flags are
|
||||||
|
* combined with bitwise or). Typically, this will tell the API user
|
||||||
|
* what should happen next. E.g. if the MPV_RENDER_UPDATE_FRAME flag is
|
||||||
|
* set, mpv_render_context_render() should be called. If flags unknown
|
||||||
|
* to the API user are set, or if the return value is 0, nothing needs
|
||||||
|
* to be done.
|
||||||
|
*/
|
||||||
|
uint64_t mpv_render_context_update(mpv_render_context *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags returned by mpv_render_context_update(). Each value represents a bit
|
||||||
|
* in the function's return value.
|
||||||
|
*/
|
||||||
|
typedef enum mpv_render_update_flag {
|
||||||
|
/**
|
||||||
|
* A new video frame must be rendered. mpv_render_context_render() must be
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
MPV_RENDER_UPDATE_FRAME = 1 << 0,
|
||||||
|
} mpv_render_context_flag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render video.
|
||||||
|
*
|
||||||
|
* Typically renders the video to a target surface provided via mpv_render_param
|
||||||
|
* (the details depend on the backend in use). Options like "panscan" are
|
||||||
|
* applied to determine which part of the video should be visible and how the
|
||||||
|
* video should be scaled. You can change these options at runtime by using the
|
||||||
|
* mpv property API.
|
||||||
|
*
|
||||||
|
* The renderer will reconfigure itself every time the target surface
|
||||||
|
* configuration (such as size) is changed.
|
||||||
|
*
|
||||||
|
* This function implicitly pulls a video frame from the internal queue and
|
||||||
|
* renders it. If no new frame is available, the previous frame is redrawn.
|
||||||
|
* The update callback set with mpv_render_context_set_update_callback()
|
||||||
|
* notifies you when a new frame was added. The details potentially depend on
|
||||||
|
* the backends and the provided parameters.
|
||||||
|
*
|
||||||
|
* Generally, libmpv will invoke your update callback some time before the video
|
||||||
|
* frame should be shown, and then lets this function block until the supposed
|
||||||
|
* display time. This will limit your rendering to video FPS. You can prevent
|
||||||
|
* this by setting the "video-timing-offset" global option to 0. (This applies
|
||||||
|
* only to "audio" video sync mode.)
|
||||||
|
*
|
||||||
|
* You should pass the following parameters:
|
||||||
|
* - Backend-specific target object, such as MPV_RENDER_PARAM_OPENGL_FBO.
|
||||||
|
* - Possibly transformations, such as MPV_RENDER_PARAM_FLIP_Y.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
* @param params an array of parameters, terminated by type==0. Which parameters
|
||||||
|
* are required depends on the backend. It's left unspecified what
|
||||||
|
* happens with unknown parameters.
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_render_context_render(mpv_render_context *ctx, mpv_render_param *params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the renderer that a frame was flipped at the given time. This is
|
||||||
|
* optional, but can help the player to achieve better timing.
|
||||||
|
*
|
||||||
|
* Note that calling this at least once informs libmpv that you will use this
|
||||||
|
* function. If you use it inconsistently, expect bad video playback.
|
||||||
|
*
|
||||||
|
* If this is called while no video is initialized, it is ignored.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context
|
||||||
|
*/
|
||||||
|
void mpv_render_context_report_swap(mpv_render_context *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the mpv renderer state.
|
||||||
|
*
|
||||||
|
* If video is still active (e.g. a file playing), video will be disabled
|
||||||
|
* forcefully.
|
||||||
|
*
|
||||||
|
* @param ctx a valid render context. After this function returns, this is not
|
||||||
|
* a valid pointer anymore. NULL is also allowed and does nothing.
|
||||||
|
*/
|
||||||
|
void mpv_render_context_free(mpv_render_context *ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
216
mpvdemo/mpv/include64/render_gl.h
Normal file
216
mpvdemo/mpv/include64/render_gl.h
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/* Copyright (C) 2018 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_RENDER_GL_H_
|
||||||
|
#define MPV_CLIENT_API_RENDER_GL_H_
|
||||||
|
|
||||||
|
#include "render.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenGL backend
|
||||||
|
* --------------
|
||||||
|
*
|
||||||
|
* This header contains definitions for using OpenGL with the render.h API.
|
||||||
|
*
|
||||||
|
* OpenGL interop
|
||||||
|
* --------------
|
||||||
|
*
|
||||||
|
* The OpenGL backend has some special rules, because OpenGL itself uses
|
||||||
|
* implicit per-thread contexts, which causes additional API problems.
|
||||||
|
*
|
||||||
|
* This assumes the OpenGL context lives on a certain thread controlled by the
|
||||||
|
* API user. All mpv_render_* APIs have to be assumed to implicitly use the
|
||||||
|
* OpenGL context if you pass a mpv_render_context using the OpenGL backend,
|
||||||
|
* unless specified otherwise.
|
||||||
|
*
|
||||||
|
* The OpenGL context is indirectly accessed through the OpenGL function
|
||||||
|
* pointers returned by the get_proc_address callback in mpv_opengl_init_params.
|
||||||
|
* Generally, mpv will not load the system OpenGL library when using this API.
|
||||||
|
*
|
||||||
|
* OpenGL state
|
||||||
|
* ------------
|
||||||
|
*
|
||||||
|
* OpenGL has a large amount of implicit state. All the mpv functions mentioned
|
||||||
|
* above expect that the OpenGL state is reasonably set to OpenGL standard
|
||||||
|
* defaults. Likewise, mpv will attempt to leave the OpenGL context with
|
||||||
|
* standard defaults. The following state is excluded from this:
|
||||||
|
*
|
||||||
|
* - the glViewport state
|
||||||
|
* - the glScissor state (but GL_SCISSOR_TEST is in its default value)
|
||||||
|
* - glBlendFuncSeparate() state (but GL_BLEND is in its default value)
|
||||||
|
* - glClearColor() state
|
||||||
|
* - mpv may overwrite the callback set with glDebugMessageCallback()
|
||||||
|
* - mpv always disables GL_DITHER at init
|
||||||
|
*
|
||||||
|
* Messing with the state could be avoided by creating shared OpenGL contexts,
|
||||||
|
* but this is avoided for the sake of compatibility and interoperability.
|
||||||
|
*
|
||||||
|
* On OpenGL 2.1, mpv will strictly call functions like glGenTextures() to
|
||||||
|
* create OpenGL objects. You will have to do the same. This ensures that
|
||||||
|
* objects created by mpv and the API users don't clash. Also, legacy state
|
||||||
|
* must be either in its defaults, or not interfere with core state.
|
||||||
|
*
|
||||||
|
* API use
|
||||||
|
* -------
|
||||||
|
*
|
||||||
|
* The mpv_render_* API is used. That API supports multiple backends, and this
|
||||||
|
* section documents specifics for the OpenGL backend.
|
||||||
|
*
|
||||||
|
* Use mpv_render_context_create() with MPV_RENDER_PARAM_API_TYPE set to
|
||||||
|
* MPV_RENDER_API_TYPE_OPENGL, and MPV_RENDER_PARAM_OPENGL_INIT_PARAMS provided.
|
||||||
|
*
|
||||||
|
* Call mpv_render_context_render() with MPV_RENDER_PARAM_OPENGL_FBO to render
|
||||||
|
* the video frame to an FBO.
|
||||||
|
*
|
||||||
|
* Hardware decoding
|
||||||
|
* -----------------
|
||||||
|
*
|
||||||
|
* Hardware decoding via this API is fully supported, but requires some
|
||||||
|
* additional setup. (At least if direct hardware decoding modes are wanted,
|
||||||
|
* instead of copying back surface data from GPU to CPU RAM.)
|
||||||
|
*
|
||||||
|
* There may be certain requirements on the OpenGL implementation:
|
||||||
|
*
|
||||||
|
* - Windows: ANGLE is required (although in theory GL/DX interop could be used)
|
||||||
|
* - Intel/Linux: EGL is required, and also the native display resource needs
|
||||||
|
* to be provided (e.g. MPV_RENDER_PARAM_X11_DISPLAY for X11 and
|
||||||
|
* MPV_RENDER_PARAM_WL_DISPLAY for Wayland)
|
||||||
|
* - nVidia/Linux: Both GLX and EGL should work (GLX is required if vdpau is
|
||||||
|
* used, e.g. due to old drivers.)
|
||||||
|
* - OSX: CGL is required (CGLGetCurrentContext() returning non-NULL)
|
||||||
|
* - iOS: EAGL is required (EAGLContext.currentContext returning non-nil)
|
||||||
|
*
|
||||||
|
* Once these things are setup, hardware decoding can be enabled/disabled at
|
||||||
|
* any time by setting the "hwdec" property.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For initializing the mpv OpenGL state via MPV_RENDER_PARAM_OPENGL_INIT_PARAMS.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_init_params {
|
||||||
|
/**
|
||||||
|
* This retrieves OpenGL function pointers, and will use them in subsequent
|
||||||
|
* operation.
|
||||||
|
* Usually, you can simply call the GL context APIs from this callback (e.g.
|
||||||
|
* glXGetProcAddressARB or wglGetProcAddress), but some APIs do not always
|
||||||
|
* return pointers for all standard functions (even if present); in this
|
||||||
|
* case you have to compensate by looking up these functions yourself when
|
||||||
|
* libmpv wants to resolve them through this callback.
|
||||||
|
* libmpv will not normally attempt to resolve GL functions on its own, nor
|
||||||
|
* does it link to GL libraries directly.
|
||||||
|
*/
|
||||||
|
void *(*get_proc_address)(void *ctx, const char *name);
|
||||||
|
/**
|
||||||
|
* Value passed as ctx parameter to get_proc_address().
|
||||||
|
*/
|
||||||
|
void *get_proc_address_ctx;
|
||||||
|
/**
|
||||||
|
* This should not be used. It is deprecated and will be removed or ignored
|
||||||
|
* when the opengl_cb API is removed.
|
||||||
|
*/
|
||||||
|
const char *extra_exts;
|
||||||
|
} mpv_opengl_init_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For MPV_RENDER_PARAM_OPENGL_FBO.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_fbo {
|
||||||
|
/**
|
||||||
|
* Framebuffer object name. This must be either a valid FBO generated by
|
||||||
|
* glGenFramebuffers() that is complete and color-renderable, or 0. If the
|
||||||
|
* value is 0, this refers to the OpenGL default framebuffer.
|
||||||
|
*/
|
||||||
|
int fbo;
|
||||||
|
/**
|
||||||
|
* Valid dimensions. This must refer to the size of the framebuffer. This
|
||||||
|
* must always be set.
|
||||||
|
*/
|
||||||
|
int w, h;
|
||||||
|
/**
|
||||||
|
* Underlying texture internal format (e.g. GL_RGBA8), or 0 if unknown. If
|
||||||
|
* this is the default framebuffer, this can be an equivalent.
|
||||||
|
*/
|
||||||
|
int internal_format;
|
||||||
|
} mpv_opengl_fbo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. For MPV_RENDER_PARAM_DRM_DISPLAY.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_drm_params {
|
||||||
|
int fd;
|
||||||
|
int crtc_id;
|
||||||
|
int connector_id;
|
||||||
|
struct _drmModeAtomicReq **atomic_request_ptr;
|
||||||
|
int render_fd;
|
||||||
|
} mpv_opengl_drm_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_drm_draw_surface_size {
|
||||||
|
/**
|
||||||
|
* size of the draw plane surface in pixels.
|
||||||
|
*/
|
||||||
|
int width, height;
|
||||||
|
} mpv_opengl_drm_draw_surface_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For MPV_RENDER_PARAM_DRM_DISPLAY_V2.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_opengl_drm_params_v2 {
|
||||||
|
/**
|
||||||
|
* DRM fd (int). Set to -1 if invalid.
|
||||||
|
*/
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used crtc id
|
||||||
|
*/
|
||||||
|
int crtc_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used connector id
|
||||||
|
*/
|
||||||
|
int connector_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to a drmModeAtomicReq pointer that is being used for the renderloop.
|
||||||
|
* This pointer should hold a pointer to the atomic request pointer
|
||||||
|
* The atomic request pointer is usually changed at every renderloop.
|
||||||
|
*/
|
||||||
|
struct _drmModeAtomicReq **atomic_request_ptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DRM render node. Used for VAAPI interop.
|
||||||
|
* Set to -1 if invalid.
|
||||||
|
*/
|
||||||
|
int render_fd;
|
||||||
|
} mpv_opengl_drm_params_v2;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For backwards compatibility with the old naming of mpv_opengl_drm_draw_surface_size
|
||||||
|
*/
|
||||||
|
#define mpv_opengl_drm_osd_size mpv_opengl_drm_draw_surface_size
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
240
mpvdemo/mpv/include64/stream_cb.h
Normal file
240
mpvdemo/mpv/include64/stream_cb.h
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
/* Copyright (C) 2017 the mpv developers
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPV_CLIENT_API_STREAM_CB_H_
|
||||||
|
#define MPV_CLIENT_API_STREAM_CB_H_
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning: this API is not stable yet.
|
||||||
|
*
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* This API can be used to make mpv read from a stream with a custom
|
||||||
|
* implementation. This interface is inspired by funopen on BSD and
|
||||||
|
* fopencookie on linux. The stream is backed by user-defined callbacks
|
||||||
|
* which can implement customized open, read, seek, size and close behaviors.
|
||||||
|
*
|
||||||
|
* Usage
|
||||||
|
* -----
|
||||||
|
*
|
||||||
|
* Register your stream callbacks with the mpv_stream_cb_add_ro() function. You
|
||||||
|
* have to provide a mpv_stream_cb_open_ro_fn callback to it (open_fn argument).
|
||||||
|
*
|
||||||
|
* Once registered, you can `loadfile myprotocol://myfile`. Your open_fn will be
|
||||||
|
* invoked with the URI and you must fill out the provided mpv_stream_cb_info
|
||||||
|
* struct. This includes your stream callbacks (like read_fn), and an opaque
|
||||||
|
* cookie, which will be passed as the first argument to all the remaining
|
||||||
|
* stream callbacks.
|
||||||
|
*
|
||||||
|
* Note that your custom callbacks must not invoke libmpv APIs as that would
|
||||||
|
* cause a deadlock. (Unless you call a different mpv_handle than the one the
|
||||||
|
* callback was registered for, and the mpv_handles refer to different mpv
|
||||||
|
* instances.)
|
||||||
|
*
|
||||||
|
* Stream lifetime
|
||||||
|
* ---------------
|
||||||
|
*
|
||||||
|
* A stream remains valid until its close callback has been called. It's up to
|
||||||
|
* libmpv to call the close callback, and the libmpv user cannot close it
|
||||||
|
* directly with the stream_cb API.
|
||||||
|
*
|
||||||
|
* For example, if you consider your custom stream to become suddenly invalid
|
||||||
|
* (maybe because the underlying stream died), libmpv will continue using your
|
||||||
|
* stream. All you can do is returning errors from each callback, until libmpv
|
||||||
|
* gives up and closes it.
|
||||||
|
*
|
||||||
|
* Protocol registration and lifetime
|
||||||
|
* ----------------------------------
|
||||||
|
*
|
||||||
|
* Protocols remain registered until the mpv instance is terminated. This means
|
||||||
|
* in particular that it can outlive the mpv_handle that was used to register
|
||||||
|
* it, but once mpv_terminate_destroy() is called, your registered callbacks
|
||||||
|
* will not be called again.
|
||||||
|
*
|
||||||
|
* Protocol unregistration is finished after the mpv core has been destroyed
|
||||||
|
* (e.g. after mpv_terminate_destroy() has returned).
|
||||||
|
*
|
||||||
|
* If you do not call mpv_terminate_destroy() yourself (e.g. plugin-style code),
|
||||||
|
* you will have to deal with the registration or even streams outliving your
|
||||||
|
* code. Here are some possible ways to do this:
|
||||||
|
* - call mpv_terminate_destroy(), which destroys the core, and will make sure
|
||||||
|
* all streams are closed once this function returns
|
||||||
|
* - you refcount all resources your stream "cookies" reference, so that it
|
||||||
|
* doesn't matter if streams live longer than expected
|
||||||
|
* - create "cancellation" semantics: after your protocol has been unregistered,
|
||||||
|
* notify all your streams that are still opened, and make them drop all
|
||||||
|
* referenced resources - then return errors from the stream callbacks as
|
||||||
|
* long as the stream is still opened
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read callback used to implement a custom stream. The semantics of the
|
||||||
|
* callback match read(2) in blocking mode. Short reads are allowed (you can
|
||||||
|
* return less bytes than requested, and libmpv will retry reading the rest
|
||||||
|
* with another call). If no data can be immediately read, the callback must
|
||||||
|
* block until there is new data. A return of 0 will be interpreted as final
|
||||||
|
* EOF, although libmpv might retry the read, or seek to a different position.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
* @param buf buffer to read data into
|
||||||
|
* @param size of the buffer
|
||||||
|
* @return number of bytes read into the buffer
|
||||||
|
* @return 0 on EOF
|
||||||
|
* @return -1 on error
|
||||||
|
*/
|
||||||
|
typedef int64_t (*mpv_stream_cb_read_fn)(void *cookie, char *buf, uint64_t nbytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* Note that mpv will issue a seek to position 0 immediately after opening. This
|
||||||
|
* is used to test whether the stream is seekable (since seekability might
|
||||||
|
* depend on the URI contents, not just the protocol). Return
|
||||||
|
* MPV_ERROR_UNSUPPORTED if seeking is not implemented for this stream. This
|
||||||
|
* seek also serves to establish the fact that streams start at position 0.
|
||||||
|
*
|
||||||
|
* This callback can be NULL, in which it behaves as if always returning
|
||||||
|
* MPV_ERROR_UNSUPPORTED.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
* @param offset target absolut stream position
|
||||||
|
* @return the resulting offset of the stream
|
||||||
|
* MPV_ERROR_UNSUPPORTED or MPV_ERROR_GENERIC if the seek failed
|
||||||
|
*/
|
||||||
|
typedef int64_t (*mpv_stream_cb_seek_fn)(void *cookie, int64_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* Return MPV_ERROR_UNSUPPORTED if no size is known.
|
||||||
|
*
|
||||||
|
* This callback can be NULL, in which it behaves as if always returning
|
||||||
|
* MPV_ERROR_UNSUPPORTED.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
* @return the total size in bytes of the stream
|
||||||
|
*/
|
||||||
|
typedef int64_t (*mpv_stream_cb_size_fn)(void *cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
*/
|
||||||
|
typedef void (*mpv_stream_cb_close_fn)(void *cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel callback used to implement a custom stream.
|
||||||
|
*
|
||||||
|
* This callback is used to interrupt any current or future read and seek
|
||||||
|
* operations. It will be called from a separate thread than the demux
|
||||||
|
* thread, and should not block.
|
||||||
|
*
|
||||||
|
* This callback can be NULL.
|
||||||
|
*
|
||||||
|
* Available since API 1.106.
|
||||||
|
*
|
||||||
|
* @param cookie opaque cookie identifying the stream,
|
||||||
|
* returned from mpv_stream_cb_open_fn
|
||||||
|
*/
|
||||||
|
typedef void (*mpv_stream_cb_cancel_fn)(void *cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See mpv_stream_cb_open_ro_fn callback.
|
||||||
|
*/
|
||||||
|
typedef struct mpv_stream_cb_info {
|
||||||
|
/**
|
||||||
|
* Opaque user-provided value, which will be passed to the other callbacks.
|
||||||
|
* The close callback will be called to release the cookie. It is not
|
||||||
|
* interpreted by mpv. It doesn't even need to be a valid pointer.
|
||||||
|
*
|
||||||
|
* The user sets this in the mpv_stream_cb_open_ro_fn callback.
|
||||||
|
*/
|
||||||
|
void *cookie;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callbacks set by the user in the mpv_stream_cb_open_ro_fn callback. Some
|
||||||
|
* of them are optional, and can be left unset.
|
||||||
|
*
|
||||||
|
* The following callbacks are mandatory: read_fn, close_fn
|
||||||
|
*/
|
||||||
|
mpv_stream_cb_read_fn read_fn;
|
||||||
|
mpv_stream_cb_seek_fn seek_fn;
|
||||||
|
mpv_stream_cb_size_fn size_fn;
|
||||||
|
mpv_stream_cb_close_fn close_fn;
|
||||||
|
mpv_stream_cb_cancel_fn cancel_fn; /* since API 1.106 */
|
||||||
|
} mpv_stream_cb_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open callback used to implement a custom read-only (ro) stream. The user
|
||||||
|
* must set the callback fields in the passed info struct. The cookie field
|
||||||
|
* also can be set to store state associated to the stream instance.
|
||||||
|
*
|
||||||
|
* Note that the info struct is valid only for the duration of this callback.
|
||||||
|
* You can't change the callbacks or the pointer to the cookie at a later point.
|
||||||
|
*
|
||||||
|
* Each stream instance created by the open callback can have different
|
||||||
|
* callbacks.
|
||||||
|
*
|
||||||
|
* The close_fn callback will terminate the stream instance. The pointers to
|
||||||
|
* your callbacks and cookie will be discarded, and the callbacks will not be
|
||||||
|
* called again.
|
||||||
|
*
|
||||||
|
* @param user_data opaque user data provided via mpv_stream_cb_add()
|
||||||
|
* @param uri name of the stream to be opened (with protocol prefix)
|
||||||
|
* @param info fields which the user should fill
|
||||||
|
* @return 0 on success, MPV_ERROR_LOADING_FAILED if the URI cannot be opened.
|
||||||
|
*/
|
||||||
|
typedef int (*mpv_stream_cb_open_ro_fn)(void *user_data, char *uri,
|
||||||
|
mpv_stream_cb_info *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a custom stream protocol. This will register a protocol handler under
|
||||||
|
* the given protocol prefix, and invoke the given callbacks if an URI with the
|
||||||
|
* matching protocol prefix is opened.
|
||||||
|
*
|
||||||
|
* The "ro" is for read-only - only read-only streams can be registered with
|
||||||
|
* this function.
|
||||||
|
*
|
||||||
|
* The callback remains registered until the mpv core is registered.
|
||||||
|
*
|
||||||
|
* If a custom stream with the same name is already registered, then the
|
||||||
|
* MPV_ERROR_INVALID_PARAMETER error is returned.
|
||||||
|
*
|
||||||
|
* @param protocol protocol prefix, for example "foo" for "foo://" URIs
|
||||||
|
* @param user_data opaque pointer passed into the mpv_stream_cb_open_fn
|
||||||
|
* callback.
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int mpv_stream_cb_add_ro(mpv_handle *ctx, const char *protocol, void *user_data,
|
||||||
|
mpv_stream_cb_open_ro_fn open_fn);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
209
mpvdemo/mpv/mpv.cpp
Normal file
209
mpvdemo/mpv/mpv.cpp
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
#include "mpv.h"
|
||||||
|
#include "mpvtool.h"
|
||||||
|
|
||||||
|
MpvThread::MpvThread(QObject *parent) : QThread(parent)
|
||||||
|
{
|
||||||
|
setObjectName("MpvThread");
|
||||||
|
|
||||||
|
stopped = false;
|
||||||
|
isPlay = false;
|
||||||
|
|
||||||
|
url = "rtsp://192.168.1.200:554/1";
|
||||||
|
|
||||||
|
mpvPlayer = NULL;
|
||||||
|
|
||||||
|
static bool isInit = false;
|
||||||
|
if (!isInit) {
|
||||||
|
isInit = true;
|
||||||
|
qDebug() << TIMEMS << "init mpv lib ok" << " version:" << MPV_CLIENT_API_VERSION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvThread::run()
|
||||||
|
{
|
||||||
|
while (!stopped) {
|
||||||
|
msleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//线程结束后释放资源
|
||||||
|
free();
|
||||||
|
stopped = false;
|
||||||
|
isPlay = false;
|
||||||
|
//qDebug() << TIMEMS << "stop mpv thread";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvThread::setUrl(const QString &url)
|
||||||
|
{
|
||||||
|
this->url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MpvThread::getValue(const QString &name)
|
||||||
|
{
|
||||||
|
if (mpvPlayer != NULL) {
|
||||||
|
return qtmpv::get_property(mpvPlayer, name);
|
||||||
|
} else {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MpvThread::setValue(const QString &name, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (mpvPlayer != NULL) {
|
||||||
|
return qtmpv::set_property(mpvPlayer, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MpvThread::setOption(const QString &name, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (mpvPlayer != NULL) {
|
||||||
|
return qtmpv::set_option_variant(mpvPlayer, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MpvThread::command(const QVariant &args)
|
||||||
|
{
|
||||||
|
if (mpvPlayer != NULL) {
|
||||||
|
return qtmpv::command_variant(mpvPlayer, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MpvThread::init()
|
||||||
|
{
|
||||||
|
//创建实例
|
||||||
|
if (mpvPlayer == NULL) {
|
||||||
|
mpvPlayer = mpv_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
MpvWidget *widget = (MpvWidget *)this->parent();
|
||||||
|
HWND wid = (HWND)widget->winId();
|
||||||
|
mpv_set_option(mpvPlayer, "wid", MPV_FORMAT_INT64, &wid);
|
||||||
|
|
||||||
|
//请求级别日志消息
|
||||||
|
mpv_request_log_messages(mpvPlayer, "info");
|
||||||
|
//启用默认绑定
|
||||||
|
setValue("input-default-bindings", "yes");
|
||||||
|
//启用键盘输入
|
||||||
|
setValue("input-vo-keyboard", "yes");
|
||||||
|
|
||||||
|
//设置控制台打印
|
||||||
|
setOption("terminal", "false");
|
||||||
|
//设置消息级别
|
||||||
|
setOption("msg-level", "all=v");
|
||||||
|
|
||||||
|
//设置硬件加速 none auto any d3d11va dxva2
|
||||||
|
setOption("hwdec", "d3d11va");
|
||||||
|
//设置通信协议 tcp udp
|
||||||
|
setOption("rtsp-transport", "tcp");
|
||||||
|
//设置网络超时时间 单位秒
|
||||||
|
setOption("network-timeout", 3);
|
||||||
|
|
||||||
|
//初始化实例
|
||||||
|
if (mpv_initialize(mpvPlayer) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = url.toUtf8();
|
||||||
|
const char *args[] = {"loadfile", data.data(), NULL};
|
||||||
|
if (mpv_command_async(mpvPlayer, 0, args) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug() << TIMEMS << "init mpv finsh";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvThread::play()
|
||||||
|
{
|
||||||
|
isPlay = true;
|
||||||
|
this->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvThread::pause()
|
||||||
|
{
|
||||||
|
setValue("pause", "yes");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvThread::next()
|
||||||
|
{
|
||||||
|
setValue("pause", "no");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvThread::free()
|
||||||
|
{
|
||||||
|
if (mpvPlayer != NULL) {
|
||||||
|
mpv_terminate_destroy(mpvPlayer);
|
||||||
|
mpvPlayer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug() << TIMEMS << "close mpv ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvThread::stop()
|
||||||
|
{
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//实时视频显示窗体类
|
||||||
|
MpvWidget::MpvWidget(QWidget *parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
thread = new MpvThread(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MpvWidget::~MpvWidget()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvWidget::setUrl(const QString &url)
|
||||||
|
{
|
||||||
|
thread->setUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvWidget::open()
|
||||||
|
{
|
||||||
|
//qDebug() << TIMEMS << "open video" << objectName();
|
||||||
|
clear();
|
||||||
|
|
||||||
|
thread->play();
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvWidget::pause()
|
||||||
|
{
|
||||||
|
thread->pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvWidget::next()
|
||||||
|
{
|
||||||
|
thread->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvWidget::close()
|
||||||
|
{
|
||||||
|
//qDebug() << TIMEMS << "close video" << objectName();
|
||||||
|
if (thread->isRunning()) {
|
||||||
|
thread->stop();
|
||||||
|
thread->quit();
|
||||||
|
thread->wait(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTimer::singleShot(5, this, SLOT(clear()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvWidget::restart()
|
||||||
|
{
|
||||||
|
//qDebug() << TIMEMS << "restart video" << objectName();
|
||||||
|
close();
|
||||||
|
QTimer::singleShot(10, this, SLOT(open()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MpvWidget::clear()
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
85
mpvdemo/mpv/mpv.h
Normal file
85
mpvdemo/mpv/mpv.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#ifndef VLC_H
|
||||||
|
#define VLC_H
|
||||||
|
|
||||||
|
#include <QtGui>
|
||||||
|
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
|
||||||
|
#include <QtWidgets>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mpvhead.h"
|
||||||
|
|
||||||
|
class MpvThread : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MpvThread(QObject *parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
volatile bool stopped; //线程停止标志位
|
||||||
|
volatile bool isPlay; //播放视频标志位
|
||||||
|
|
||||||
|
QString url; //视频流地址
|
||||||
|
mpv_handle *mpvPlayer; //载体对象
|
||||||
|
|
||||||
|
signals:
|
||||||
|
//收到图片信号
|
||||||
|
void receiveImage(const QImage &image);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
//设置视频流地址
|
||||||
|
void setUrl(const QString &url);
|
||||||
|
|
||||||
|
//通用属性接口
|
||||||
|
QVariant getValue(const QString &name);
|
||||||
|
int setValue(const QString &name, const QVariant &value);
|
||||||
|
int setOption(const QString &name, const QVariant &value);
|
||||||
|
QVariant command(const QVariant &args);
|
||||||
|
|
||||||
|
//初始化视频对象
|
||||||
|
bool init();
|
||||||
|
//播放视频对象
|
||||||
|
void play();
|
||||||
|
//暂停播放
|
||||||
|
void pause();
|
||||||
|
//继续播放
|
||||||
|
void next();
|
||||||
|
//释放对象
|
||||||
|
void free();
|
||||||
|
//停止采集线程
|
||||||
|
void stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
//实时视频显示窗体类
|
||||||
|
class MpvWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MpvWidget(QWidget *parent = 0);
|
||||||
|
~MpvWidget();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MpvThread *thread;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
//设置视频流地址
|
||||||
|
void setUrl(const QString &url);
|
||||||
|
|
||||||
|
//打开设备
|
||||||
|
void open();
|
||||||
|
//暂停
|
||||||
|
void pause();
|
||||||
|
//继续
|
||||||
|
void next();
|
||||||
|
//关闭设备
|
||||||
|
void close();
|
||||||
|
//重新加载
|
||||||
|
void restart();
|
||||||
|
//清空
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VLC_H
|
||||||
22
mpvdemo/mpv/mpv.pri
Normal file
22
mpvdemo/mpv/mpv.pri
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
HEADERS += $$PWD/mpvhead.h
|
||||||
|
HEADERS += $$PWD/mpvtool.h
|
||||||
|
HEADERS += $$PWD/mpv.h
|
||||||
|
SOURCES += $$PWD/mpv.cpp
|
||||||
|
|
||||||
|
#表示64位的构建套件
|
||||||
|
contains(QT_ARCH, x86_64) {
|
||||||
|
strLib = winlib64
|
||||||
|
strInclude = include64
|
||||||
|
} else {
|
||||||
|
strLib = winlib
|
||||||
|
strInclude = include
|
||||||
|
}
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD/$$strInclude
|
||||||
|
win32 {
|
||||||
|
LIBS += -L$$PWD/$$strLib/ -llibmpv
|
||||||
|
}
|
||||||
|
|
||||||
|
#需要自己改为对应目录下的库
|
||||||
|
unix:!macx {}
|
||||||
|
macx {}
|
||||||
26
mpvdemo/mpv/mpvhead.h
Normal file
26
mpvdemo/mpv/mpvhead.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef MPVHEAD_H
|
||||||
|
#define MPVHEAD_H
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#include <client.h>
|
||||||
|
#include <render_gl.h>
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#include "qdatetime.h"
|
||||||
|
#pragma execution_character_set("utf-8")
|
||||||
|
|
||||||
|
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
||||||
|
#define TIME qPrintable(QTime::currentTime().toString("HH:mm:ss"))
|
||||||
|
#define QDATE qPrintable(QDate::currentDate().toString("yyyy-MM-dd"))
|
||||||
|
#define QTIME qPrintable(QTime::currentTime().toString("HH-mm-ss"))
|
||||||
|
#define DATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
|
||||||
|
#define STRDATETIMEMS qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss-zzz"))
|
||||||
|
|
||||||
|
#endif // MPVHEAD_H
|
||||||
373
mpvdemo/mpv/mpvtool.h
Normal file
373
mpvdemo/mpv/mpvtool.h
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
#ifndef MPVTOOL_H
|
||||||
|
#define MPVTOOL_H
|
||||||
|
|
||||||
|
#include <client.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
namespace qtmpv {
|
||||||
|
|
||||||
|
// Wrapper around mpv_handle. Does refcounting under the hood.
|
||||||
|
class Handle
|
||||||
|
{
|
||||||
|
struct container {
|
||||||
|
container(mpv_handle *h) : mpv(h) {}
|
||||||
|
~container() {
|
||||||
|
mpv_terminate_destroy(mpv);
|
||||||
|
}
|
||||||
|
mpv_handle *mpv;
|
||||||
|
};
|
||||||
|
QSharedPointer<container> sptr;
|
||||||
|
public:
|
||||||
|
// Construct a new Handle from a raw mpv_handle with refcount 1. If the
|
||||||
|
// last Handle goes out of scope, the mpv_handle will be destroyed with
|
||||||
|
// mpv_terminate_destroy().
|
||||||
|
// Never destroy the mpv_handle manually when using this wrapper. You
|
||||||
|
// will create dangling pointers. Just let the wrapper take care of
|
||||||
|
// destroying the mpv_handle.
|
||||||
|
// Never create multiple wrappers from the same raw mpv_handle; copy the
|
||||||
|
// wrapper instead (that's what it's for).
|
||||||
|
static Handle FromRawHandle(mpv_handle *handle) {
|
||||||
|
Handle h;
|
||||||
|
h.sptr = QSharedPointer<container>(new container(handle));
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the raw handle; for use with the libmpv C API.
|
||||||
|
operator mpv_handle *() const {
|
||||||
|
return sptr ? (*sptr).mpv : 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline QVariant node_to_variant(const mpv_node *node)
|
||||||
|
{
|
||||||
|
switch (node->format) {
|
||||||
|
case MPV_FORMAT_STRING:
|
||||||
|
return QVariant(QString::fromUtf8(node->u.string));
|
||||||
|
case MPV_FORMAT_FLAG:
|
||||||
|
return QVariant(static_cast<bool>(node->u.flag));
|
||||||
|
case MPV_FORMAT_INT64:
|
||||||
|
return QVariant(static_cast<qlonglong>(node->u.int64));
|
||||||
|
case MPV_FORMAT_DOUBLE:
|
||||||
|
return QVariant(node->u.double_);
|
||||||
|
case MPV_FORMAT_NODE_ARRAY: {
|
||||||
|
mpv_node_list *list = node->u.list;
|
||||||
|
QVariantList qlist;
|
||||||
|
for (int n = 0; n < list->num; n++) {
|
||||||
|
qlist.append(node_to_variant(&list->values[n]));
|
||||||
|
}
|
||||||
|
return QVariant(qlist);
|
||||||
|
}
|
||||||
|
case MPV_FORMAT_NODE_MAP: {
|
||||||
|
mpv_node_list *list = node->u.list;
|
||||||
|
QVariantMap qmap;
|
||||||
|
for (int n = 0; n < list->num; n++) {
|
||||||
|
qmap.insert(QString::fromUtf8(list->keys[n]),
|
||||||
|
node_to_variant(&list->values[n]));
|
||||||
|
}
|
||||||
|
return QVariant(qmap);
|
||||||
|
}
|
||||||
|
default: // MPV_FORMAT_NONE, unknown values (e.g. future extensions)
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node_builder {
|
||||||
|
node_builder(const QVariant &v) {
|
||||||
|
set(&node_, v);
|
||||||
|
}
|
||||||
|
~node_builder() {
|
||||||
|
free_node(&node_);
|
||||||
|
}
|
||||||
|
mpv_node *node() {
|
||||||
|
return &node_;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(node_builder)
|
||||||
|
mpv_node node_;
|
||||||
|
mpv_node_list *create_list(mpv_node *dst, bool is_map, int num) {
|
||||||
|
dst->format = is_map ? MPV_FORMAT_NODE_MAP : MPV_FORMAT_NODE_ARRAY;
|
||||||
|
mpv_node_list *list = new mpv_node_list();
|
||||||
|
dst->u.list = list;
|
||||||
|
if (!list) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
list->values = new mpv_node[num]();
|
||||||
|
if (!list->values) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (is_map) {
|
||||||
|
list->keys = new char *[num]();
|
||||||
|
if (!list->keys) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
err:
|
||||||
|
free_node(dst);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char *dup_qstring(const QString &s) {
|
||||||
|
QByteArray b = s.toUtf8();
|
||||||
|
char *r = new char[b.size() + 1];
|
||||||
|
if (r) {
|
||||||
|
std::memcpy(r, b.data(), b.size() + 1);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
bool test_type(const QVariant &v, QMetaType::Type t) {
|
||||||
|
// The Qt docs say: "Although this function is declared as returning
|
||||||
|
// "QVariant::Type(obsolete), the return value should be interpreted
|
||||||
|
// as QMetaType::Type."
|
||||||
|
// So a cast really seems to be needed to avoid warnings (urgh).
|
||||||
|
return static_cast<int>(v.type()) == static_cast<int>(t);
|
||||||
|
}
|
||||||
|
void set(mpv_node *dst, const QVariant &src) {
|
||||||
|
if (test_type(src, QMetaType::QString)) {
|
||||||
|
dst->format = MPV_FORMAT_STRING;
|
||||||
|
dst->u.string = dup_qstring(src.toString());
|
||||||
|
if (!dst->u.string) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else if (test_type(src, QMetaType::Bool)) {
|
||||||
|
dst->format = MPV_FORMAT_FLAG;
|
||||||
|
dst->u.flag = src.toBool() ? 1 : 0;
|
||||||
|
} else if (test_type(src, QMetaType::Int) ||
|
||||||
|
test_type(src, QMetaType::LongLong) ||
|
||||||
|
test_type(src, QMetaType::UInt) ||
|
||||||
|
test_type(src, QMetaType::ULongLong)) {
|
||||||
|
dst->format = MPV_FORMAT_INT64;
|
||||||
|
dst->u.int64 = src.toLongLong();
|
||||||
|
} else if (test_type(src, QMetaType::Double)) {
|
||||||
|
dst->format = MPV_FORMAT_DOUBLE;
|
||||||
|
dst->u.double_ = src.toDouble();
|
||||||
|
} else if (src.canConvert<QVariantList>()) {
|
||||||
|
QVariantList qlist = src.toList();
|
||||||
|
mpv_node_list *list = create_list(dst, false, qlist.size());
|
||||||
|
if (!list) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
list->num = qlist.size();
|
||||||
|
for (int n = 0; n < qlist.size(); n++) {
|
||||||
|
set(&list->values[n], qlist[n]);
|
||||||
|
}
|
||||||
|
} else if (src.canConvert<QVariantMap>()) {
|
||||||
|
QVariantMap qmap = src.toMap();
|
||||||
|
mpv_node_list *list = create_list(dst, true, qmap.size());
|
||||||
|
if (!list) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
list->num = qmap.size();
|
||||||
|
for (int n = 0; n < qmap.size(); n++) {
|
||||||
|
list->keys[n] = dup_qstring(qmap.keys()[n]);
|
||||||
|
if (!list->keys[n]) {
|
||||||
|
free_node(dst);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
set(&list->values[n], qmap.values()[n]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
dst->format = MPV_FORMAT_NONE;
|
||||||
|
}
|
||||||
|
void free_node(mpv_node *dst) {
|
||||||
|
switch (dst->format) {
|
||||||
|
case MPV_FORMAT_STRING:
|
||||||
|
delete[] dst->u.string;
|
||||||
|
break;
|
||||||
|
case MPV_FORMAT_NODE_ARRAY:
|
||||||
|
case MPV_FORMAT_NODE_MAP: {
|
||||||
|
mpv_node_list *list = dst->u.list;
|
||||||
|
if (list) {
|
||||||
|
for (int n = 0; n < list->num; n++) {
|
||||||
|
if (list->keys) {
|
||||||
|
delete[] list->keys[n];
|
||||||
|
}
|
||||||
|
if (list->values) {
|
||||||
|
free_node(&list->values[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] list->keys;
|
||||||
|
delete[] list->values;
|
||||||
|
}
|
||||||
|
delete list;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
dst->format = MPV_FORMAT_NONE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RAII wrapper that calls mpv_free_node_contents() on the pointer.
|
||||||
|
*/
|
||||||
|
struct node_autofree {
|
||||||
|
mpv_node *ptr;
|
||||||
|
node_autofree(mpv_node *a_ptr) : ptr(a_ptr) {}
|
||||||
|
~node_autofree() {
|
||||||
|
mpv_free_node_contents(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the given property as mpv_node converted to QVariant, or QVariant()
|
||||||
|
* on error.
|
||||||
|
*
|
||||||
|
* @deprecated use get_property() instead
|
||||||
|
*
|
||||||
|
* @param name the property name
|
||||||
|
*/
|
||||||
|
static inline QVariant get_property_variant(mpv_handle *ctx, const QString &name)
|
||||||
|
{
|
||||||
|
mpv_node node;
|
||||||
|
if (mpv_get_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, &node) < 0) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
node_autofree f(&node);
|
||||||
|
return node_to_variant(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given property as mpv_node converted from the QVariant argument.
|
||||||
|
|
||||||
|
* @deprecated use set_property() instead
|
||||||
|
*/
|
||||||
|
static inline int set_property_variant(mpv_handle *ctx, const QString &name,
|
||||||
|
const QVariant &v)
|
||||||
|
{
|
||||||
|
node_builder node(v);
|
||||||
|
return mpv_set_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given option as mpv_node converted from the QVariant argument.
|
||||||
|
*
|
||||||
|
* @deprecated use set_property() instead
|
||||||
|
*/
|
||||||
|
static inline int set_option_variant(mpv_handle *ctx, const QString &name,
|
||||||
|
const QVariant &v)
|
||||||
|
{
|
||||||
|
node_builder node(v);
|
||||||
|
return mpv_set_option(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpv_command_node() equivalent. Returns QVariant() on error (and
|
||||||
|
* unfortunately, the same on success).
|
||||||
|
*
|
||||||
|
* @deprecated use command() instead
|
||||||
|
*/
|
||||||
|
static inline QVariant command_variant(mpv_handle *ctx, const QVariant &args)
|
||||||
|
{
|
||||||
|
node_builder node(args);
|
||||||
|
mpv_node res;
|
||||||
|
if (mpv_command_node(ctx, node.node(), &res) < 0) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
node_autofree f(&res);
|
||||||
|
return node_to_variant(&res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to return error codes wrapped in QVariant for functions which
|
||||||
|
* return QVariant.
|
||||||
|
*
|
||||||
|
* You can use get_error() or is_error() to extract the error status from a
|
||||||
|
* QVariant value.
|
||||||
|
*/
|
||||||
|
struct ErrorReturn {
|
||||||
|
/**
|
||||||
|
* enum mpv_error value (or a value outside of it if ABI was extended)
|
||||||
|
*/
|
||||||
|
int error;
|
||||||
|
|
||||||
|
ErrorReturn() : error(0) {}
|
||||||
|
explicit ErrorReturn(int err) : error(err) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the mpv error code packed into a QVariant, or 0 (success) if it's not
|
||||||
|
* an error value.
|
||||||
|
*
|
||||||
|
* @return error code (<0) or success (>=0)
|
||||||
|
*/
|
||||||
|
static inline int get_error(const QVariant &v)
|
||||||
|
{
|
||||||
|
if (!v.canConvert<ErrorReturn>()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return v.value<ErrorReturn>().error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the QVariant carries a mpv error code.
|
||||||
|
*/
|
||||||
|
static inline bool is_error(const QVariant &v)
|
||||||
|
{
|
||||||
|
return get_error(v) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the given property as mpv_node converted to QVariant, or QVariant()
|
||||||
|
* on error.
|
||||||
|
*
|
||||||
|
* @param name the property name
|
||||||
|
* @return the property value, or an ErrorReturn with the error code
|
||||||
|
*/
|
||||||
|
static inline QVariant get_property(mpv_handle *ctx, const QString &name)
|
||||||
|
{
|
||||||
|
mpv_node node;
|
||||||
|
int err = mpv_get_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, &node);
|
||||||
|
if (err < 0) {
|
||||||
|
return QVariant::fromValue(ErrorReturn(err));
|
||||||
|
}
|
||||||
|
node_autofree f(&node);
|
||||||
|
return node_to_variant(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given property as mpv_node converted from the QVariant argument.
|
||||||
|
*
|
||||||
|
* @return mpv error code (<0 on error, >= 0 on success)
|
||||||
|
*/
|
||||||
|
static inline int set_property(mpv_handle *ctx, const QString &name,
|
||||||
|
const QVariant &v)
|
||||||
|
{
|
||||||
|
node_builder node(v);
|
||||||
|
return mpv_set_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpv_command_node() equivalent.
|
||||||
|
*
|
||||||
|
* @param args command arguments, with args[0] being the command name as string
|
||||||
|
* @return the property value, or an ErrorReturn with the error code
|
||||||
|
*/
|
||||||
|
static inline QVariant command(mpv_handle *ctx, const QVariant &args)
|
||||||
|
{
|
||||||
|
node_builder node(args);
|
||||||
|
mpv_node res;
|
||||||
|
int err = mpv_command_node(ctx, node.node(), &res);
|
||||||
|
if (err < 0) {
|
||||||
|
return QVariant::fromValue(ErrorReturn(err));
|
||||||
|
}
|
||||||
|
node_autofree f(&res);
|
||||||
|
return node_to_variant(&res);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(qtmpv::ErrorReturn)
|
||||||
|
|
||||||
|
#endif // MPVTOOL_H
|
||||||
BIN
mpvdemo/mpv/winlib/libmpv.lib
Normal file
BIN
mpvdemo/mpv/winlib/libmpv.lib
Normal file
Binary file not shown.
BIN
mpvdemo/mpv/winlib64/libmpv.lib
Normal file
BIN
mpvdemo/mpv/winlib64/libmpv.lib
Normal file
Binary file not shown.
19
mpvdemo/mpvdemo.pro
Normal file
19
mpvdemo/mpvdemo.pro
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
QT += core gui
|
||||||
|
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
TARGET = mpvdemo
|
||||||
|
TEMPLATE = app
|
||||||
|
MOC_DIR = temp/moc
|
||||||
|
RCC_DIR = temp/rcc
|
||||||
|
UI_DIR = temp/ui
|
||||||
|
OBJECTS_DIR = temp/obj
|
||||||
|
DESTDIR = $$PWD/../bin
|
||||||
|
|
||||||
|
SOURCES += main.cpp widget.cpp
|
||||||
|
HEADERS += widget.h
|
||||||
|
FORMS += widget.ui
|
||||||
|
CONFIG += warn_off
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD/mpv
|
||||||
|
include ($$PWD/mpv/mpv.pri)
|
||||||
9
mpvdemo/readme.txt
Normal file
9
mpvdemo/readme.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ժ<EFBFBD><EFBFBD>ǵý<EFBFBD>dll<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>ͬһĿ¼<EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>汾<EFBFBD><EFBFBD>dll<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>ַ<EFBFBD><EFBFBD>https://pan.baidu.com/s/13LDRu6mXC6gaADtrGprNVA <20><>ȡ<EFBFBD><C8A1>: ujm7
|
||||||
|
|
||||||
|
<EFBFBD>շ<EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD>汾<EFBFBD><EFBFBD>https://blog.csdn.net/feiyangqingyun/article/details/107972067
|
||||||
|
|
||||||
|
2. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
|
||||||
|
3. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
|
||||||
|
4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
|
||||||
|
5. ֪<><D6AA><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
|
||||||
37
mpvdemo/widget.cpp
Normal file
37
mpvdemo/widget.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma execution_character_set("utf-8")
|
||||||
|
#include "widget.h"
|
||||||
|
#include "ui_widget.h"
|
||||||
|
|
||||||
|
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
QStringList urls;
|
||||||
|
urls << "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov";
|
||||||
|
urls << "rtsp://admin:Admin123456@192.168.1.64:554/Streaming/Channels/102?transportmode=unicast&profile=Profile_2";
|
||||||
|
urls << "rtsp://192.168.1.108:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif";
|
||||||
|
urls << "rtsp://192.168.1.15:554/media/video1";
|
||||||
|
urls << "rtsp://192.168.1.15:554/media/video2";
|
||||||
|
urls << "rtsp://192.168.1.247:554/av0_0";
|
||||||
|
urls << "rtsp://192.168.1.247:554/av0_1";
|
||||||
|
ui->cboxUrl->addItems(urls);
|
||||||
|
ui->cboxUrl->setCurrentIndex(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::~Widget()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::on_btnOpen_clicked()
|
||||||
|
{
|
||||||
|
if (ui->btnOpen->text() == "打开") {
|
||||||
|
ui->btnOpen->setText("关闭");
|
||||||
|
QString url = ui->cboxUrl->currentText().trimmed();
|
||||||
|
ui->playWidget->setUrl(url);
|
||||||
|
ui->playWidget->open();
|
||||||
|
} else {
|
||||||
|
ui->btnOpen->setText("打开");
|
||||||
|
ui->playWidget->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
24
mpvdemo/widget.h
Normal file
24
mpvdemo/widget.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef WIDGET_H
|
||||||
|
#define WIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui { class Widget; }
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class Widget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Widget(QWidget *parent = 0);
|
||||||
|
~Widget();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_btnOpen_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::Widget *ui;
|
||||||
|
};
|
||||||
|
#endif // WIDGET_H
|
||||||
63
mpvdemo/widget.ui
Normal file
63
mpvdemo/widget.ui
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Widget</class>
|
||||||
|
<widget class="QWidget" name="Widget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>700</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Widget</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="MpvWidget" name="playWidget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="cboxUrl">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnOpen">
|
||||||
|
<property name="text">
|
||||||
|
<string>打开</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>MpvWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>mpv.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -6,12 +6,4 @@
|
|||||||
2. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
|
2. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
|
||||||
3. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
|
3. <20><><EFBFBD><EFBFBD>վ<EFBFBD>㣺[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
|
||||||
4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
|
4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
|
||||||
5. ֪<><D6AA><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
|
5. ֪<><D6AA><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
|
||||||
|
|
||||||
1. <20><><EFBFBD>߳<EFBFBD>ʵʱ<CAB5><CAB1><EFBFBD><EFBFBD>
|
|
||||||
2. ͬʱ<CDAC><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>
|
|
||||||
3. ֧<><D6A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Qt<51>汾<EFBFBD><E6B1BE><EFBFBD><EFBFBD>ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
4. <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CDB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>룬<EFBFBD><EBA3AC>չ<EFBFBD><D5B9>ǿ
|
|
||||||
5. <20><>ѡvlc2<63><32>vlc3<63><33><EFBFBD><EFBFBD><EFBFBD>汾
|
|
||||||
6. <20><>ѡ32λ<32><CEBB>64λ<34><CEBB>vlc<6C><63>
|
|
||||||
7. ע<>;<EFBFBD><CDBE><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
#include "vlc.h"
|
#include "vlc.h"
|
||||||
|
|
||||||
#pragma execution_character_set("utf-8")
|
|
||||||
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
|
||||||
#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
|
|
||||||
|
|
||||||
VlcThread::VlcThread(QObject *parent) : QThread(parent)
|
VlcThread::VlcThread(QObject *parent) : QThread(parent)
|
||||||
{
|
{
|
||||||
setObjectName("VlcThread");
|
setObjectName("VlcThread");
|
||||||
@@ -34,7 +30,7 @@ void VlcThread::run()
|
|||||||
free();
|
free();
|
||||||
stopped = false;
|
stopped = false;
|
||||||
isPlay = false;
|
isPlay = false;
|
||||||
//qDebug() << TIMEMS << "stop vlc thread";
|
//qDebug() << TIMEMS << "stop vlc1 thread";
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlcThread::setUrl(const QString &url)
|
void VlcThread::setUrl(const QString &url)
|
||||||
@@ -136,7 +132,7 @@ void VlcThread::stop()
|
|||||||
//实时视频显示窗体类
|
//实时视频显示窗体类
|
||||||
VlcWidget::VlcWidget(QWidget *parent) : QWidget(parent)
|
VlcWidget::VlcWidget(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
vlc = new VlcThread(this);
|
thread = new VlcThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
VlcWidget::~VlcWidget()
|
VlcWidget::~VlcWidget()
|
||||||
@@ -146,7 +142,7 @@ VlcWidget::~VlcWidget()
|
|||||||
|
|
||||||
void VlcWidget::setUrl(const QString &url)
|
void VlcWidget::setUrl(const QString &url)
|
||||||
{
|
{
|
||||||
vlc->setUrl(url);
|
thread->setUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlcWidget::open()
|
void VlcWidget::open()
|
||||||
@@ -154,27 +150,27 @@ void VlcWidget::open()
|
|||||||
//qDebug() << TIMEMS << "open video" << objectName();
|
//qDebug() << TIMEMS << "open video" << objectName();
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
vlc->play();
|
thread->play();
|
||||||
vlc->start();
|
thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlcWidget::pause()
|
void VlcWidget::pause()
|
||||||
{
|
{
|
||||||
vlc->pause();
|
thread->pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlcWidget::next()
|
void VlcWidget::next()
|
||||||
{
|
{
|
||||||
vlc->next();
|
thread->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlcWidget::close()
|
void VlcWidget::close()
|
||||||
{
|
{
|
||||||
//qDebug() << TIMEMS << "close video" << objectName();
|
//qDebug() << TIMEMS << "close video" << objectName();
|
||||||
if (vlc->isRunning()) {
|
if (thread->isRunning()) {
|
||||||
vlc->stop();
|
thread->stop();
|
||||||
vlc->quit();
|
thread->quit();
|
||||||
vlc->wait(3000);
|
thread->wait(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTimer::singleShot(5, this, SLOT(clear()));
|
QTimer::singleShot(5, this, SLOT(clear()));
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "vlchead.h"
|
#include "vlchead.h"
|
||||||
class VlcWidget;
|
|
||||||
|
|
||||||
class VlcThread : public QThread
|
class VlcThread : public QThread
|
||||||
{
|
{
|
||||||
@@ -23,7 +22,6 @@ private:
|
|||||||
volatile bool isPlay; //播放视频标志位
|
volatile bool isPlay; //播放视频标志位
|
||||||
|
|
||||||
QString url; //视频流地址
|
QString url; //视频流地址
|
||||||
|
|
||||||
libvlc_instance_t *vlcInst; //载体对象
|
libvlc_instance_t *vlcInst; //载体对象
|
||||||
libvlc_media_t *vlcMedia; //媒体对象
|
libvlc_media_t *vlcMedia; //媒体对象
|
||||||
libvlc_media_player_t *vlcPlayer; //播放对象
|
libvlc_media_player_t *vlcPlayer; //播放对象
|
||||||
@@ -60,7 +58,7 @@ public:
|
|||||||
~VlcWidget();
|
~VlcWidget();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VlcThread *vlc; //实时视频采集对象
|
VlcThread *thread;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
//设置视频流地址
|
//设置视频流地址
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
HEADERS += $$PWD/vlchead.h
|
HEADERS += $$PWD/vlchead.h
|
||||||
HEADERS += $$PWD/vlc.h
|
HEADERS += $$PWD/vlc.h
|
||||||
SOURCES += $$PWD/vlc.cpp
|
SOURCES += $$PWD/vlc.cpp
|
||||||
|
|
||||||
#如果用的是vlc3内核请将vlc2改成vlc3,两种内核不兼容,头文件也不一样,建议用vlc2
|
#如果用的是vlc3内核请将vlc2改成vlc3,两种内核不兼容,头文件也不一样,建议用vlc2
|
||||||
DEFINES += vlc2
|
DEFINES += vlc2
|
||||||
|
|||||||
@@ -1,37 +1,5 @@
|
|||||||
/*****************************************************************************
|
#ifndef VLCHEAD_H
|
||||||
* vlc.h: global header for libvlc
|
#define VLCHEAD_H 1
|
||||||
*****************************************************************************
|
|
||||||
* Copyright (C) 1998-2008 VLC authors and VideoLAN
|
|
||||||
* $Id: 8f39094bd4b15c99288cecd001f76fcc10565daa $
|
|
||||||
*
|
|
||||||
* Authors: Vincent Seguin <seguin@via.ecp.fr>
|
|
||||||
* Samuel Hocevar <sam@zoy.org>
|
|
||||||
* Gildas Bazin <gbazin@netcourrier.com>
|
|
||||||
* Derk-Jan Hartman <hartman at videolan dot org>
|
|
||||||
* Pierre d'Herbemont <pdherbemont@videolan.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2.1 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program 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 Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef VLC_VLC_H
|
|
||||||
#define VLC_VLC_H 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file
|
|
||||||
* This file defines libvlc new external API
|
|
||||||
*/
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -68,4 +36,15 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif /* _VLC_VLC_H */
|
#include "qdatetime.h"
|
||||||
|
#pragma execution_character_set("utf-8")
|
||||||
|
|
||||||
|
#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
|
||||||
|
#define TIME qPrintable(QTime::currentTime().toString("HH:mm:ss"))
|
||||||
|
#define QDATE qPrintable(QDate::currentDate().toString("yyyy-MM-dd"))
|
||||||
|
#define QTIME qPrintable(QTime::currentTime().toString("HH-mm-ss"))
|
||||||
|
#define DATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
|
||||||
|
#define STRDATETIMEMS qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss-zzz"))
|
||||||
|
|
||||||
|
#endif // VLCHEAD_H
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "ui_widget.h"
|
#include "ui_widget.h"
|
||||||
|
|
||||||
Widget::Widget(QWidget *parent)
|
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
|
||||||
: QWidget(parent)
|
|
||||||
, ui(new Ui::Widget)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@@ -17,6 +15,7 @@ Widget::Widget(QWidget *parent)
|
|||||||
urls << "rtsp://192.168.1.247:554/av0_0";
|
urls << "rtsp://192.168.1.247:554/av0_0";
|
||||||
urls << "rtsp://192.168.1.247:554/av0_1";
|
urls << "rtsp://192.168.1.247:554/av0_1";
|
||||||
ui->cboxUrl->addItems(urls);
|
ui->cboxUrl->addItems(urls);
|
||||||
|
ui->cboxUrl->setCurrentIndex(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget::~Widget()
|
Widget::~Widget()
|
||||||
@@ -29,10 +28,10 @@ void Widget::on_btnOpen_clicked()
|
|||||||
if (ui->btnOpen->text() == "打开") {
|
if (ui->btnOpen->text() == "打开") {
|
||||||
ui->btnOpen->setText("关闭");
|
ui->btnOpen->setText("关闭");
|
||||||
QString url = ui->cboxUrl->currentText().trimmed();
|
QString url = ui->cboxUrl->currentText().trimmed();
|
||||||
ui->vlcWidget->setUrl(url);
|
ui->playWidget->setUrl(url);
|
||||||
ui->vlcWidget->open();
|
ui->playWidget->open();
|
||||||
} else {
|
} else {
|
||||||
ui->btnOpen->setText("打开");
|
ui->btnOpen->setText("打开");
|
||||||
ui->vlcWidget->close();
|
ui->playWidget->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="VlcWidget" name="vlcWidget" native="true">
|
<widget class="VlcWidget" name="playWidget" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
|||||||
Reference in New Issue
Block a user