├── .github └── workflows │ └── main.yaml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── examples ├── extract_frames │ ├── extract_frames.pro │ └── main.cpp ├── qml_video │ ├── CMakeLists.txt │ ├── main.cpp │ ├── main.qml │ ├── main_qt6.qml │ ├── qml.qrc │ ├── qml_qt6.qrc │ └── qml_video.pro ├── widget_video │ ├── CMakeLists.txt │ ├── main.cpp │ └── widget_video.pro └── widget_video_opengl │ ├── CMakeLists.txt │ ├── main.cpp │ └── widget_video_opengl.pro ├── src └── QtAVPlayer │ ├── QtAVPlayer.cmake │ ├── QtAVPlayer.pri │ ├── qavandroidsurfacetexture.cpp │ ├── qavandroidsurfacetexture_p.h │ ├── qavaudiocodec.cpp │ ├── qavaudiocodec_p.h │ ├── qavaudioconverter.cpp │ ├── qavaudioconverter.h │ ├── qavaudiofilter.cpp │ ├── qavaudiofilter_p.h │ ├── qavaudioformat.h │ ├── qavaudioframe.cpp │ ├── qavaudioframe.h │ ├── qavaudioinputfilter.cpp │ ├── qavaudioinputfilter_p.h │ ├── qavaudiooutput.cpp │ ├── qavaudiooutput.h │ ├── qavaudiooutputdevice.cpp │ ├── qavaudiooutputdevice.h │ ├── qavaudiooutputfilter.cpp │ ├── qavaudiooutputfilter_p.h │ ├── qavcodec.cpp │ ├── qavcodec_p.h │ ├── qavcodec_p_p.h │ ├── qavdemuxer.cpp │ ├── qavdemuxer_p.h │ ├── qavfilter.cpp │ ├── qavfilter_p.h │ ├── qavfilter_p_p.h │ ├── qavfiltergraph.cpp │ ├── qavfiltergraph_p.h │ ├── qavfilters.cpp │ ├── qavfilters_p.h │ ├── qavframe.cpp │ ├── qavframe.h │ ├── qavframe_p.h │ ├── qavframecodec.cpp │ ├── qavframecodec_p.h │ ├── qavhwdevice_d3d11.cpp │ ├── qavhwdevice_d3d11_p.h │ ├── qavhwdevice_mediacodec.cpp │ ├── qavhwdevice_mediacodec_p.h │ ├── qavhwdevice_p.h │ ├── qavhwdevice_vaapi_drm_egl.cpp │ ├── qavhwdevice_vaapi_drm_egl_p.h │ ├── qavhwdevice_vaapi_x11_glx.cpp │ ├── qavhwdevice_vaapi_x11_glx_p.h │ ├── qavhwdevice_vdpau.cpp │ ├── qavhwdevice_vdpau_p.h │ ├── qavhwdevice_videotoolbox.mm │ ├── qavhwdevice_videotoolbox_p.h │ ├── qavinoutfilter.cpp │ ├── qavinoutfilter_p.h │ ├── qavinoutfilter_p_p.h │ ├── qaviodevice.cpp │ ├── qaviodevice.h │ ├── qavmuxer.cpp │ ├── qavmuxer.h │ ├── qavpacket.cpp │ ├── qavpacket.h │ ├── qavpacketqueue_p.h │ ├── qavplayer.cpp │ ├── qavplayer.h │ ├── qavstream.cpp │ ├── qavstream.h │ ├── qavstreamframe.cpp │ ├── qavstreamframe.h │ ├── qavstreamframe_p.h │ ├── qavsubtitlecodec.cpp │ ├── qavsubtitlecodec_p.h │ ├── qavsubtitleframe.cpp │ ├── qavsubtitleframe.h │ ├── qavvideobuffer_cpu.cpp │ ├── qavvideobuffer_cpu_p.h │ ├── qavvideobuffer_gpu.cpp │ ├── qavvideobuffer_gpu_p.h │ ├── qavvideobuffer_p.h │ ├── qavvideocodec.cpp │ ├── qavvideocodec_p.h │ ├── qavvideofilter.cpp │ ├── qavvideofilter_p.h │ ├── qavvideoframe.cpp │ ├── qavvideoframe.h │ ├── qavvideoinputfilter.cpp │ ├── qavvideoinputfilter_p.h │ ├── qavvideooutputfilter.cpp │ ├── qavvideooutputfilter_p.h │ ├── qavwidget_opengl.cpp │ ├── qavwidget_opengl.h │ └── qtavplayerglobal.h └── tests └── auto └── integration ├── qavdemuxer ├── files.qrc ├── qavdemuxer.pro └── tst_qavdemuxer.cpp ├── qavplayer ├── qavplayer.pro └── tst_qavplayer.cpp └── testdata ├── 1.dv ├── 20190821_075842.jpg ├── 7_BCL02006_ffv1_20s_1.mkv ├── 7_BCL02006_ffv1_20s_2.mkv ├── BAVC1010958_DV000107.dv ├── DHC0413_CreaseOrNot.mp4 ├── Earth_Zoom_In.mov ├── av_sample.mkv ├── colors.mp4 ├── colors_subtitles.mkv ├── colors_subtitles.mp4 ├── dv.tar ├── dv25_pal__411_4-3_2ch_32k_bars_sine.dv ├── dv_dsf_1_stype_1.dv ├── guido.mp4 ├── rotated_90.mp4 ├── shots0000.dv ├── small.mp4 ├── star_trails.mpeg ├── test.mkv ├── test.mov ├── test.mp3 ├── test.wav ├── test6g100.mkv └── test_5beeps.mkv /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile* 2 | *.pch 3 | *.pdb 4 | *.exe 5 | *.dll 6 | *.ilk 7 | *.obj 8 | *.lib 9 | *.res 10 | *.exp 11 | *.manifest 12 | *_resource.rc 13 | moc_*.cpp 14 | ui_*.h 15 | qrc_*.cpp 16 | *.moc 17 | .qmake.cache 18 | config.log 19 | *.pro.user* 20 | tmp 21 | *.o 22 | *.app 23 | *.dylib 24 | *.framework 25 | *_wrapper.* 26 | *-config.pri 27 | *.version* 28 | 29 | # 30 | # Includes 31 | # 32 | 33 | # 34 | # Snippets 35 | # 36 | *.so 37 | *.so.* 38 | 39 | # 40 | # Tests 41 | # 42 | tst_* 43 | !tst_*.cpp 44 | !tst_*.qml 45 | tests/auto/cmake/build 46 | 47 | # Generated static plugin import sources 48 | *_plugin_import.cpp 49 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Special thanks for all the people who had helped this project: 2 | 3 | - tangmingcheng <45536906+tangmingcheng@users.noreply.github.com> 4 | - DevelopRepo 5 | - Mauricio Ferrari 6 | - Alexander Ivash 7 | - Vladyslav Arzhanov 8 | - Charlie LEGER 9 | - Longshan Du 10 | - Transporter 11 | - fibonacci-matrix <176021117+fibonacci-matrix@users.noreply.github.com> 12 | - Dniester Amorim 13 | - Gilles Caulier 14 | - Maxime Gervais 15 | - Niko Križnik <45733509+niko-kriznik@users.noreply.github.com> 16 | - Novacer 17 | - kimvnhung 18 | - leavelet <45084815+leavelet@users.noreply.github.com> 19 | - xdcsystems 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Val Doroshchuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/extract_frames/extract_frames.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = extract_frames 3 | INCLUDEPATH += . 4 | 5 | INCLUDEPATH += . ../../src 6 | include(../../src/QtAVPlayer/QtAVPlayer.pri) 7 | 8 | QT -= gui 9 | CONFIG += c++1z 10 | SOURCES += main.cpp 11 | 12 | target.path = $$[QT_INSTALL_EXAMPLES]/$$TARGET 13 | INSTALLS += target 14 | -------------------------------------------------------------------------------- /examples/extract_frames/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | QCoreApplication app(argc, argv); 17 | 18 | QAVPlayer p; 19 | QObject::connect(&p, &QAVPlayer::audioFrame, [&](const QAVAudioFrame &frame) { qDebug() << "audio:" << frame.pts(); }); 20 | QObject::connect(&p, &QAVPlayer::videoFrame, [&](const QAVVideoFrame &frame) { qDebug() << "video:" << frame.pts(); }); 21 | p.setSource(QLatin1String("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")); 22 | p.play(); 23 | 24 | QObject::connect(&p, &QAVPlayer::stateChanged, [&](auto s) { qDebug() << "stateChanged" << s << p.mediaStatus(); }); 25 | QObject::connect(&p, &QAVPlayer::mediaStatusChanged, [&](auto s){ qDebug() << "mediaStatusChanged"<< s << p.state(); }); 26 | QObject::connect(&p, &QAVPlayer::durationChanged, [&](auto d) { qDebug() << "durationChanged" << d; }); 27 | 28 | return app.exec(); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /examples/qml_video/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(qml_video LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_AUTOMOC ON) 6 | 7 | find_package(Qt6 COMPONENTS CoreTools) 8 | if(Qt6CoreTools_FOUND) 9 | find_package(Qt6 COMPONENTS QmlTools Quick REQUIRED) 10 | qt6_add_resources(QT_RESOURCES qml_qt6.qrc) 11 | find_package(Qt6 COMPONENTS MultimediaQuickPrivate REQUIRED) 12 | include_directories(${Qt6MultimediaQuick_PRIVATE_INCLUDE_DIRS}) 13 | include_directories(${Qt6Multimedia_PRIVATE_INCLUDE_DIRS}) 14 | find_package(Qt6 REQUIRED COMPONENTS Core BuildInternals OPTIONAL_COMPONENTS Multimedia) 15 | add_definitions(${Qt6Core_DEFINITIONS}) 16 | else() 17 | find_package(Qt5 REQUIRED COMPONENTS Core OPTIONAL_COMPONENTS Gui Multimedia) 18 | find_package(Qt5 COMPONENTS Quick) 19 | qt5_add_resources(QT_RESOURCES qml.qrc) 20 | include_directories(${Qt5Multimedia_PRIVATE_INCLUDE_DIRS}) 21 | add_definitions(${Qt5Core_DEFINITIONS}) 22 | endif() 23 | 24 | include_directories(../../src/) 25 | set(QT_AVPLAYER_DIR ../../src/QtAVPlayer/) 26 | include(../../src/QtAVPlayer/QtAVPlayer.cmake) 27 | 28 | set(SOURCES ${QtAVPlayer_SOURCES} main.cpp) 29 | 30 | add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${QT_RESOURCES}) 31 | if(NOT WIN32) 32 | add_definitions(-std=c++1z) 33 | target_compile_options(${PROJECT_NAME} PRIVATE -fPIC) 34 | endif() 35 | 36 | set(LIBS ${QtAVPlayer_LIBS}) 37 | 38 | if(Qt6_FOUND) 39 | set(LIBS ${LIBS} Qt6::Core Qt6::Gui Qt6::Multimedia Qt6::Quick Qt6::MultimediaQuickPrivate) 40 | else() 41 | set(LIBS ${LIBS} Qt5::Core Qt5::Gui Qt5::Quick Qt5::Multimedia ${MultimediaQuick_LIBRARY}) 42 | if (Qt5Core_VERSION VERSION_LESS 5.15.0) 43 | find_library(MultimediaQuick_LIBRARY REQUIRED NAMES Qt5MultimediaQuick) 44 | set(LIBS ${LIBS} ${MultimediaQuick_LIBRARY}) 45 | else() 46 | find_package(Qt5 COMPONENTS MultimediaQuick REQUIRED) 47 | include_directories(${Qt5MultimediaQuick_PRIVATE_INCLUDE_DIRS}) 48 | set(LIBS ${LIBS} Qt5::MultimediaQuick) 49 | endif() 50 | endif() 51 | 52 | target_link_libraries(${PROJECT_NAME} ${LIBS}) 53 | -------------------------------------------------------------------------------- /examples/qml_video/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | import QtMultimedia 5.12 3 | 4 | Item { 5 | id: root 6 | property alias frame_fps: fpsTextVideo.text 7 | property alias qml_fps: fpsTextQML.text 8 | 9 | VideoOutput { 10 | anchors.fill: parent 11 | objectName: "videoOutput" 12 | } 13 | 14 | Rectangle { 15 | id: fps 16 | property color textColor: "white" 17 | property int textSize: 30 18 | 19 | border.width: 1 20 | border.color: "black" 21 | width: 5.5 * fps.textSize 22 | height: 2.5 * fps.textSize 23 | color: "black" 24 | opacity: 0.5 25 | radius: 0 26 | 27 | // This should ensure that the monitor is on top of all other content 28 | z: 999 29 | 30 | Text { 31 | id: labelText 32 | anchors { 33 | top: parent.top 34 | left: parent.left 35 | margins: 10 36 | } 37 | color: fps.textColor 38 | font.pixelSize: 0.6 * fps.textSize 39 | text: "Video FPS" 40 | width: fps.width - 2*anchors.margins 41 | elide: Text.ElideRight 42 | } 43 | 44 | Text { 45 | id: labelTextQML 46 | anchors { 47 | bottom: parent.bottom 48 | left: parent.left 49 | margins: 10 50 | } 51 | color: fps.textColor 52 | font.pixelSize: 0.6 * fps.textSize 53 | text: "QML FPS" 54 | width: fps.width - 2*anchors.margins 55 | elide: Text.ElideRight 56 | } 57 | 58 | Text { 59 | id: fpsTextVideo 60 | anchors { 61 | top: parent.top 62 | right: parent.right 63 | margins: 10 64 | } 65 | color: fps.textColor 66 | font.pixelSize: 0.6 * fps.textSize 67 | } 68 | 69 | Text { 70 | id: fpsTextQML 71 | anchors { 72 | bottom: parent.bottom 73 | right: parent.right 74 | margins: 10 75 | } 76 | color: fps.textColor 77 | font.pixelSize: 0.6 * fps.textSize 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/qml_video/main_qt6.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | import QtMultimedia 6.2 3 | 4 | Item { 5 | id: root 6 | property alias frame_fps: fpsTextVideo.text 7 | property alias qml_fps: fpsTextQML.text 8 | 9 | VideoOutput { 10 | anchors.fill: parent 11 | objectName: "videoOutput" 12 | } 13 | 14 | Rectangle { 15 | id: fps 16 | property color textColor: "white" 17 | property int textSize: 30 18 | 19 | border.width: 1 20 | border.color: "black" 21 | width: 5.5 * fps.textSize 22 | height: 2.5 * fps.textSize 23 | color: "black" 24 | opacity: 0.5 25 | radius: 0 26 | 27 | // This should ensure that the monitor is on top of all other content 28 | z: 999 29 | 30 | Text { 31 | id: labelText 32 | anchors { 33 | top: parent.top 34 | left: parent.left 35 | margins: 10 36 | } 37 | color: fps.textColor 38 | font.pixelSize: 0.6 * fps.textSize 39 | text: "Video FPS" 40 | width: fps.width - 2*anchors.margins 41 | elide: Text.ElideRight 42 | } 43 | 44 | Text { 45 | id: labelTextQML 46 | anchors { 47 | bottom: parent.bottom 48 | left: parent.left 49 | margins: 10 50 | } 51 | color: fps.textColor 52 | font.pixelSize: 0.6 * fps.textSize 53 | text: "QML FPS" 54 | width: fps.width - 2*anchors.margins 55 | elide: Text.ElideRight 56 | } 57 | 58 | Text { 59 | id: fpsTextVideo 60 | anchors { 61 | top: parent.top 62 | right: parent.right 63 | margins: 10 64 | } 65 | color: fps.textColor 66 | font.pixelSize: 0.6 * fps.textSize 67 | } 68 | 69 | Text { 70 | id: fpsTextQML 71 | anchors { 72 | bottom: parent.bottom 73 | right: parent.right 74 | margins: 10 75 | } 76 | color: fps.textColor 77 | font.pixelSize: 0.6 * fps.textSize 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/qml_video/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | ../../tests/auto/integration/testdata/20190821_075842.jpg 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/qml_video/qml_qt6.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main_qt6.qml 4 | ../../tests/auto/integration/testdata/20190821_075842.jpg 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/qml_video/qml_video.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = qml_video 3 | QT += gui gui-private multimedia 4 | DEFINES += "QT_AVPLAYER_MULTIMEDIA" 5 | DEFINES += "QT_NO_CAST_FROM_ASCII" 6 | INCLUDEPATH += . ../../src 7 | include(../../src/QtAVPlayer/QtAVPlayer.pri) 8 | # Example 9 | #ANDROID_EXTRA_LIBS += /opt/mobile-ffmpeg/prebuilt/android-arm/ffmpeg/lib/libavdevice.so \ 10 | # /opt/mobile-ffmpeg/prebuilt/android-arm/ffmpeg/lib/libavformat.so \ 11 | # /opt/mobile-ffmpeg/prebuilt/android-arm/ffmpeg/lib/libavutil.so \ 12 | # /opt/mobile-ffmpeg/prebuilt/android-arm/ffmpeg/lib/libavcodec.so \ 13 | # /opt/mobile-ffmpeg/prebuilt/android-arm/ffmpeg/lib/libavfilter.so \ 14 | # /opt/mobile-ffmpeg/prebuilt/android-arm/ffmpeg/lib/libswscale.so \ 15 | # /opt/mobile-ffmpeg/prebuilt/android-arm/ffmpeg/lib/libswresample.so 16 | CONFIG += c++1z 17 | lessThan(QT_MAJOR_VERSION, 6): QT += qtmultimediaquicktools-private 18 | equals(QT_MAJOR_VERSION, 6): QT += multimediaquick-private 19 | 20 | SOURCES += main.cpp 21 | lessThan(QT_MAJOR_VERSION, 6): RESOURCES += qml.qrc 22 | equals(QT_MAJOR_VERSION, 6): RESOURCES += qml_qt6.qrc 23 | 24 | target.path = $$[QT_INSTALL_EXAMPLES]/$$TARGET 25 | INSTALLS += target 26 | -------------------------------------------------------------------------------- /examples/widget_video/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(widget_video LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_AUTOMOC ON) 6 | 7 | find_package(Qt6 COMPONENTS CoreTools) 8 | if(Qt6CoreTools_FOUND) 9 | find_package(Qt6 COMPONENTS MultimediaWidgets REQUIRED) 10 | find_package(Qt6 REQUIRED COMPONENTS Core BuildInternals OPTIONAL_COMPONENTS Multimedia) 11 | include_directories(${Qt6Multimedia_PRIVATE_INCLUDE_DIRS}) 12 | include_directories(${Qt6MultimediaWidgets_INCLUDE_DIRS}) 13 | add_definitions(${Qt6Core_DEFINITIONS}) 14 | else() 15 | find_package(Qt5 COMPONENTS MultimediaWidgets REQUIRED) 16 | find_package(Qt5 REQUIRED COMPONENTS Core OPTIONAL_COMPONENTS Gui Multimedia) 17 | include_directories(${Qt5Multimedia_PRIVATE_INCLUDE_DIRS}) 18 | include_directories(${Qt5MultimediaWidgets_INCLUDE_DIRS}) 19 | add_definitions(${Qt5Core_DEFINITIONS}) 20 | endif() 21 | 22 | include_directories(../../src/) 23 | set(QT_AVPLAYER_DIR ../../src/QtAVPlayer/) 24 | include(../../src/QtAVPlayer/QtAVPlayer.cmake) 25 | 26 | set(SOURCES ${QtAVPlayer_SOURCES} main.cpp) 27 | 28 | add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${QT_RESOURCES}) 29 | if(NOT WIN32) 30 | add_definitions(-std=c++1z) 31 | target_compile_options(${PROJECT_NAME} PRIVATE -fPIC) 32 | endif() 33 | 34 | set(LIBS ${QtAVPlayer_LIBS}) 35 | 36 | if(Qt6_FOUND) 37 | set(LIBS ${LIBS} Qt6::Core Qt6::Gui Qt6::Multimedia Qt6::MultimediaWidgets) 38 | else() 39 | set(LIBS ${LIBS} Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::MultimediaWidgets) 40 | endif() 41 | 42 | target_link_libraries(${PROJECT_NAME} ${LIBS}) 43 | -------------------------------------------------------------------------------- /examples/widget_video/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | class VideoRenderer : public QVideoRendererControl 23 | { 24 | public: 25 | QAbstractVideoSurface *surface() const override 26 | { 27 | return m_surface; 28 | } 29 | 30 | void setSurface(QAbstractVideoSurface *surface) override 31 | { 32 | m_surface = surface; 33 | } 34 | 35 | QAbstractVideoSurface *m_surface = nullptr; 36 | }; 37 | 38 | class MediaService : public QMediaService 39 | { 40 | public: 41 | MediaService(VideoRenderer *vr, QObject* parent = nullptr) 42 | : QMediaService(parent) 43 | , m_renderer(vr) 44 | { 45 | } 46 | 47 | QMediaControl* requestControl(const char *name) override 48 | { 49 | if (qstrcmp(name, QVideoRendererControl_iid) == 0) 50 | return m_renderer; 51 | 52 | return nullptr; 53 | } 54 | 55 | void releaseControl(QMediaControl *) override 56 | { 57 | } 58 | 59 | VideoRenderer *m_renderer = nullptr; 60 | }; 61 | 62 | class MediaObject : public QMediaObject 63 | { 64 | public: 65 | explicit MediaObject(VideoRenderer *vr, QObject* parent = nullptr) 66 | : QMediaObject(parent, new MediaService(vr, parent)) 67 | { 68 | } 69 | }; 70 | 71 | class VideoWidget : public QVideoWidget 72 | { 73 | public: 74 | bool setMediaObject(QMediaObject *object) override 75 | { 76 | return QVideoWidget::setMediaObject(object); 77 | } 78 | }; 79 | #else 80 | #include 81 | #endif 82 | 83 | int main(int argc, char *argv[]) 84 | { 85 | QApplication app(argc, argv); 86 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 87 | VideoRenderer vr; 88 | 89 | VideoWidget w; 90 | w.show(); 91 | 92 | MediaObject mo(&vr); 93 | w.setMediaObject(&mo); 94 | #else 95 | QVideoWidget w; 96 | w.show(); 97 | #endif 98 | 99 | QAVPlayer p; 100 | QString file = argc > 1 ? QString::fromUtf8(argv[1]) : QString::fromLatin1("http://archive.org/download/big-bunny-sample-video/SampleVideo.ia.mp4"); 101 | p.setSource(file); 102 | p.play(); 103 | //p.seek(55000); 104 | 105 | QAVAudioOutput audioOutput; 106 | //audioOutput.setBufferSize(128 * 1024); 107 | QObject::connect(&p, &QAVPlayer::audioFrame, &audioOutput, [&audioOutput](const QAVAudioFrame &frame) { audioOutput.play(frame); }, Qt::DirectConnection); 108 | 109 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 110 | QObject::connect(&p, &QAVPlayer::videoFrame, &p, [&](const QAVVideoFrame &frame) { 111 | if (vr.m_surface == nullptr) 112 | return; 113 | QVideoFrame videoFrame = frame.convertTo(AV_PIX_FMT_RGB32); 114 | if (!vr.m_surface->isActive() || vr.m_surface->surfaceFormat().frameSize() != videoFrame.size()) { 115 | QVideoSurfaceFormat f(videoFrame.size(), videoFrame.pixelFormat(), videoFrame.handleType()); 116 | vr.m_surface->start(f); 117 | } 118 | if (vr.m_surface->isActive()) 119 | vr.m_surface->present(videoFrame); 120 | }, Qt::DirectConnection); 121 | #else 122 | QObject::connect(&p, &QAVPlayer::videoFrame, &p, [&](const QAVVideoFrame &frame) { 123 | QVideoFrame videoFrame = frame; 124 | w.videoSink()->setVideoFrame(videoFrame); 125 | }, Qt::DirectConnection); 126 | #endif 127 | 128 | QObject::connect(&p, &QAVPlayer::mediaStatusChanged, [&](auto status) { 129 | qDebug() << "mediaStatusChanged"<< status << p.state(); 130 | if (status == QAVPlayer::LoadedMedia) { 131 | qDebug() << "Video streams:" << p.currentVideoStreams().size(); 132 | for (const auto &s: p.currentVideoStreams()) 133 | qDebug() << "[" << s.index() << "]" << s.metadata() << s.framesCount() << "frames," << s.frameRate() << "frame rate"; 134 | qDebug() << "Audio streams:" << p.currentAudioStreams().size(); 135 | for (const auto &s: p.currentAudioStreams()) 136 | qDebug() << "[" << s.index() << "]" << s.metadata() << s.framesCount() << "frames," << s.frameRate() << "frame rate"; 137 | } else if (status == QAVPlayer::EndOfMedia) { 138 | audioOutput.stop(); 139 | } 140 | }); 141 | 142 | return app.exec(); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /examples/widget_video/widget_video.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = widget_video 3 | QT += gui gui-private multimedia multimediawidgets 4 | DEFINES += "QT_AVPLAYER_MULTIMEDIA" 5 | DEFINES += "QT_NO_CAST_FROM_ASCII" 6 | INCLUDEPATH += . ../../src 7 | include(../../src/QtAVPlayer/QtAVPlayer.pri) 8 | 9 | CONFIG += c++1z 10 | 11 | SOURCES += main.cpp 12 | 13 | target.path = $$[QT_INSTALL_EXAMPLES]/$$TARGET 14 | INSTALLS += target 15 | -------------------------------------------------------------------------------- /examples/widget_video_opengl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(widget_video_opengl LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_AUTOMOC ON) 6 | 7 | find_package(Qt6 COMPONENTS CoreTools) 8 | if(Qt6CoreTools_FOUND) 9 | find_package(Qt6 COMPONENTS MultimediaWidgets REQUIRED) 10 | find_package(Qt6 REQUIRED COMPONENTS Core BuildInternals OPTIONAL_COMPONENTS Multimedia OpenGL OpenGLWidgets) 11 | include_directories(${Qt6Multimedia_PRIVATE_INCLUDE_DIRS}) 12 | include_directories(${Qt6MultimediaWidgets_INCLUDE_DIRS}) 13 | include_directories(${Qt6OpenGLWidgets_INCLUDE_DIRS}) 14 | add_definitions(${Qt6Core_DEFINITIONS}) 15 | else() 16 | find_package(Qt5 COMPONENTS MultimediaWidgets REQUIRED) 17 | find_package(Qt5 REQUIRED COMPONENTS Core OPTIONAL_COMPONENTS Gui OpenGL) 18 | add_definitions(${Qt5Core_DEFINITIONS}) 19 | endif() 20 | 21 | set(QT_AVPLAYER_WIDGET_OPENGL ON CACHE BOOL "" FORCE) 22 | set(QT_AVPLAYER_MULTIMEDIA ON CACHE BOOL "" FORCE) 23 | include_directories(../../src/) 24 | set(QT_AVPLAYER_DIR ../../src/QtAVPlayer/) 25 | include(../../src/QtAVPlayer/QtAVPlayer.cmake) 26 | 27 | set(SOURCES ${QtAVPlayer_SOURCES} main.cpp) 28 | 29 | add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${QT_RESOURCES}) 30 | if(NOT WIN32) 31 | add_definitions(-std=c++1z) 32 | target_compile_options(${PROJECT_NAME} PRIVATE -fPIC) 33 | endif() 34 | 35 | set(LIBS ${QtAVPlayer_LIBS}) 36 | 37 | if(Qt6_FOUND) 38 | set(LIBS ${LIBS} Qt6::Core Qt6::Gui Qt6::Multimedia Qt6::OpenGL Qt6::OpenGLWidgets) 39 | else() 40 | set(LIBS ${LIBS} Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::OpenGL) 41 | endif() 42 | 43 | target_link_libraries(${PROJECT_NAME} ${LIBS}) 44 | -------------------------------------------------------------------------------- /examples/widget_video_opengl/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | QApplication app(argc, argv); 16 | 17 | QAVWidget_OpenGL w; 18 | w.resize(1000, 800); 19 | w.show(); 20 | 21 | QAVPlayer p; 22 | QString file = argc > 1 ? QString::fromUtf8(argv[1]) : QString::fromLatin1("http://archive.org/download/big-bunny-sample-video/SampleVideo.ia.mp4"); 23 | p.setSource(file); 24 | 25 | QObject::connect(&p, &QAVPlayer::videoFrame, &p, [&](const QAVVideoFrame &frame) { 26 | w.setVideoFrame(frame); 27 | }, Qt::DirectConnection); 28 | 29 | QAVAudioOutput audioOutput; 30 | QObject::connect(&p, &QAVPlayer::audioFrame, &audioOutput, [&audioOutput](const QAVAudioFrame &frame) { 31 | audioOutput.play(frame); 32 | }, Qt::DirectConnection); 33 | 34 | p.play(); 35 | 36 | return app.exec(); 37 | } 38 | -------------------------------------------------------------------------------- /examples/widget_video_opengl/widget_video_opengl.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = widget_video_opengl 3 | QT += gui gui-private multimedia 4 | equals(QT_MAJOR_VERSION, 6): QT += openglwidgets 5 | DEFINES += "QT_AVPLAYER_MULTIMEDIA" 6 | DEFINES += "QT_NO_CAST_FROM_ASCII" 7 | DEFINES += "QT_AVPLAYER_WIDGET_OPENGL" 8 | INCLUDEPATH += . ../../src 9 | include(../../src/QtAVPlayer/QtAVPlayer.pri) 10 | 11 | CONFIG += c++1z console 12 | SOURCES += main.cpp 13 | 14 | target.path = $$[QT_INSTALL_EXAMPLES]/$$TARGET 15 | INSTALLS += target 16 | -------------------------------------------------------------------------------- /src/QtAVPlayer/QtAVPlayer.pri: -------------------------------------------------------------------------------- 1 | QT += concurrent 2 | CONFIG += C++1z 3 | LIBS += -lavcodec -lavformat -lswscale -lavutil -lswresample -lswscale -lavfilter -lavdevice 4 | 5 | PRIVATE_HEADERS += \ 6 | $$PWD/qavcodec_p.h \ 7 | $$PWD/qavcodec_p_p.h \ 8 | $$PWD/qavframecodec_p.h \ 9 | $$PWD/qavaudiocodec_p.h \ 10 | $$PWD/qavvideocodec_p.h \ 11 | $$PWD/qavsubtitlecodec_p.h \ 12 | $$PWD/qavhwdevice_p.h \ 13 | $$PWD/qavdemuxer_p.h \ 14 | $$PWD/qavstreamframe_p.h \ 15 | $$PWD/qavframe_p.h \ 16 | $$PWD/qavpacketqueue_p.h \ 17 | $$PWD/qavvideobuffer_p.h \ 18 | $$PWD/qavvideobuffer_cpu_p.h \ 19 | $$PWD/qavvideobuffer_gpu_p.h \ 20 | $$PWD/qavfilter_p.h \ 21 | $$PWD/qavfilter_p_p.h \ 22 | $$PWD/qavvideofilter_p.h \ 23 | $$PWD/qavaudiofilter_p.h \ 24 | $$PWD/qavfiltergraph_p.h \ 25 | $$PWD/qavinoutfilter_p.h \ 26 | $$PWD/qavinoutfilter_p_p.h \ 27 | $$PWD/qavvideoinputfilter_p.h \ 28 | $$PWD/qavaudioinputfilter_p.h \ 29 | $$PWD/qavvideooutputfilter_p.h \ 30 | $$PWD/qavaudiooutputfilter_p.h \ 31 | $$PWD/qavfilters_p.h 32 | 33 | PUBLIC_HEADERS += \ 34 | $$PWD/qaviodevice.h \ 35 | $$PWD/qavaudioformat.h \ 36 | $$PWD/qavpacket.h \ 37 | $$PWD/qavstreamframe.h \ 38 | $$PWD/qavframe.h \ 39 | $$PWD/qavvideoframe.h \ 40 | $$PWD/qavaudioframe.h \ 41 | $$PWD/qavsubtitleframe.h \ 42 | $$PWD/qtavplayerglobal.h \ 43 | $$PWD/qavstream.h \ 44 | $$PWD/qavplayer.h \ 45 | $$PWD/qavaudioconverter.h \ 46 | $$PWD/qavmuxer.h \ 47 | 48 | SOURCES += \ 49 | $$PWD/qavplayer.cpp \ 50 | $$PWD/qavcodec.cpp \ 51 | $$PWD/qavframecodec.cpp \ 52 | $$PWD/qavaudiocodec.cpp \ 53 | $$PWD/qavvideocodec.cpp \ 54 | $$PWD/qavsubtitlecodec.cpp \ 55 | $$PWD/qavdemuxer.cpp \ 56 | $$PWD/qavmuxer.cpp \ 57 | $$PWD/qavpacket.cpp \ 58 | $$PWD/qavframe.cpp \ 59 | $$PWD/qavstreamframe.cpp \ 60 | $$PWD/qavvideoframe.cpp \ 61 | $$PWD/qavaudioframe.cpp \ 62 | $$PWD/qavsubtitleframe.cpp \ 63 | $$PWD/qavvideobuffer_cpu.cpp \ 64 | $$PWD/qavvideobuffer_gpu.cpp \ 65 | $$PWD/qavfilter.cpp \ 66 | $$PWD/qavvideofilter.cpp \ 67 | $$PWD/qavaudiofilter.cpp \ 68 | $$PWD/qavfiltergraph.cpp \ 69 | $$PWD/qavinoutfilter.cpp \ 70 | $$PWD/qavvideoinputfilter.cpp \ 71 | $$PWD/qavaudioinputfilter.cpp \ 72 | $$PWD/qavvideooutputfilter.cpp \ 73 | $$PWD/qavaudiooutputfilter.cpp \ 74 | $$PWD/qaviodevice.cpp \ 75 | $$PWD/qavstream.cpp \ 76 | $$PWD/qavfilters.cpp \ 77 | $$PWD/qavaudioconverter.cpp \ 78 | 79 | contains(DEFINES, QT_AVPLAYER_MULTIMEDIA) { 80 | QT += multimedia 81 | # Needed for QAbstractVideoBuffer 82 | equals(QT_MAJOR_VERSION, 6): QT += multimedia-private 83 | HEADERS += $$PWD/qavaudiooutput.h $$PWD/qavaudiooutputdevice.h 84 | SOURCES += $$PWD/qavaudiooutput.cpp $$PWD/qavaudiooutputdevice.cpp 85 | } 86 | 87 | contains(DEFINES, QT_AVPLAYER_WIDGET_OPENGL):qtConfig(opengl) { 88 | QT += opengl 89 | equals(QT_MAJOR_VERSION, 6): QT += openglwidgets 90 | PUBLIC_HEADERS += $$PWD/qavwidget_opengl.h 91 | SOURCES += $$PWD/qavwidget_opengl.cpp 92 | } 93 | 94 | contains(DEFINES, QT_AVPLAYER_VA_X11):qtConfig(opengl) { 95 | QMAKE_USE += x11 opengl 96 | LIBS += -lva-x11 -lva 97 | PRIVATE_HEADERS += $$PWD/qavhwdevice_vaapi_x11_glx_p.h 98 | SOURCES += $$PWD/qavhwdevice_vaapi_x11_glx.cpp 99 | } 100 | 101 | contains(DEFINES, QT_AVPLAYER_VA_DRM):qtConfig(egl) { 102 | QMAKE_USE += egl opengl 103 | LIBS += -lva-drm -lva 104 | exists(/usr/include/drm):INCLUDEPATH += /usr/include/drm 105 | exists(/usr/include/libdrm):INCLUDEPATH += /usr/include/libdrm 106 | PRIVATE_HEADERS += $$PWD/qavhwdevice_vaapi_drm_egl_p.h 107 | SOURCES += $$PWD/qavhwdevice_vaapi_drm_egl.cpp 108 | } 109 | 110 | contains(DEFINES, QT_AVPLAYER_VDPAU) { 111 | QT += opengl 112 | PRIVATE_HEADERS += $$PWD/qavhwdevice_vdpau_p.h 113 | SOURCES += $$PWD/qavhwdevice_vdpau.cpp 114 | } 115 | 116 | macos|darwin { 117 | PRIVATE_HEADERS += $$PWD/qavhwdevice_videotoolbox_p.h 118 | SOURCES += $$PWD/qavhwdevice_videotoolbox.mm 119 | LIBS += -framework CoreVideo -framework Metal -framework CoreMedia -framework QuartzCore -framework IOSurface 120 | } 121 | 122 | win32 { 123 | QT += opengl 124 | QMAKE_USE += opengl 125 | # Needed by mingw 126 | LIBS += -ld3d11 -lopengl32 -lD3DCompiler 127 | PRIVATE_HEADERS += $$PWD/qavhwdevice_d3d11_p.h 128 | SOURCES += $$PWD/qavhwdevice_d3d11.cpp 129 | } 130 | 131 | android { 132 | QT += core-private 133 | PRIVATE_HEADERS += $$PWD/qavhwdevice_mediacodec_p.h 134 | SOURCES += $$PWD/qavhwdevice_mediacodec.cpp $$PWD/qavandroidsurfacetexture.cpp 135 | 136 | equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ 137 | LIBS += -L$$(AVPLAYER_ANDROID_LIB_ARMEABI_V7A) 138 | 139 | equals(ANDROID_TARGET_ARCH, arm64-v8a): \ 140 | LIBS += -L$$(AVPLAYER_ANDROID_LIB_ARMEABI_V8A) 141 | 142 | equals(ANDROID_TARGET_ARCH, x86): \ 143 | LIBS += -L$$(AVPLAYER_ANDROID_LIB_X86) 144 | 145 | equals(ANDROID_TARGET_ARCH, x86_64): \ 146 | LIBS += -L$$(AVPLAYER_ANDROID_LIB_X86_64) 147 | } 148 | 149 | HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS 150 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavandroidsurfacetexture.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavandroidsurfacetexture_p.h" 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | QAVAndroidSurfaceTexture::QAVAndroidSurfaceTexture(quint32 texName) 15 | { 16 | Q_STATIC_ASSERT(sizeof (jlong) >= sizeof (void *)); 17 | m_surfaceTexture = JniObject("android/graphics/SurfaceTexture", "(I)V", jint(texName)); 18 | } 19 | 20 | QAVAndroidSurfaceTexture::~QAVAndroidSurfaceTexture() 21 | { 22 | if (m_surface.isValid()) 23 | m_surface.callMethod("release"); 24 | 25 | if (m_surfaceTexture.isValid()) 26 | release(); 27 | } 28 | 29 | void QAVAndroidSurfaceTexture::release() 30 | { 31 | m_surfaceTexture.callMethod("release"); 32 | } 33 | 34 | void QAVAndroidSurfaceTexture::updateTexImage() 35 | { 36 | if (!m_surfaceTexture.isValid()) 37 | return; 38 | 39 | m_surfaceTexture.callMethod("updateTexImage"); 40 | } 41 | 42 | jobject QAVAndroidSurfaceTexture::surfaceTexture() 43 | { 44 | return m_surfaceTexture.object(); 45 | } 46 | 47 | jobject QAVAndroidSurfaceTexture::surface() 48 | { 49 | if (!m_surface.isValid()) { 50 | m_surface = JniObject("android/view/Surface", 51 | "(Landroid/graphics/SurfaceTexture;)V", 52 | m_surfaceTexture.object()); 53 | } 54 | 55 | return m_surface.object(); 56 | } 57 | 58 | void QAVAndroidSurfaceTexture::attachToGLContext(quint32 texName) 59 | { 60 | if (!m_surfaceTexture.isValid()) 61 | return; 62 | 63 | m_surfaceTexture.callMethod("attachToGLContext", "(I)V", texName); 64 | } 65 | 66 | void QAVAndroidSurfaceTexture::detachFromGLContext() 67 | { 68 | if (!m_surfaceTexture.isValid()) 69 | return; 70 | 71 | m_surfaceTexture.callMethod("detachFromGLContext"); 72 | } 73 | 74 | QT_END_NAMESPACE 75 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavandroidsurfacetexture_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVANDROIDSURFACETEXTURE_H 9 | #define QAVANDROIDSURFACETEXTURE_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include 23 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 24 | #include 25 | #include 26 | using JniObject = QJNIObjectPrivate; 27 | using JniEnvironment = QJNIEnvironmentPrivate; 28 | #else 29 | #include 30 | using JniObject = QJniObject; 31 | using JniEnvironment = QJniEnvironment; 32 | #endif 33 | 34 | #include 35 | 36 | QT_BEGIN_NAMESPACE 37 | 38 | class QAVAndroidSurfaceTexture 39 | { 40 | public: 41 | explicit QAVAndroidSurfaceTexture(quint32 texName = 0); 42 | ~QAVAndroidSurfaceTexture(); 43 | 44 | jobject surfaceTexture(); 45 | jobject surface(); 46 | inline bool isValid() const { return m_surfaceTexture.isValid(); } 47 | 48 | void release(); // API level 14 49 | void updateTexImage(); 50 | 51 | void attachToGLContext(quint32 texName); // API level 16 52 | void detachFromGLContext(); // API level 16 53 | 54 | private: 55 | JniObject m_surfaceTexture; 56 | JniObject m_surface; 57 | }; 58 | 59 | QT_END_NAMESPACE 60 | 61 | #endif // QAVANDROIDSURFACETEXTURE_H 62 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiocodec.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #include "qavaudiocodec_p.h" 9 | #include "qavcodec_p_p.h" 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | } 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | QAVAudioCodec::QAVAudioCodec(const AVCodec *codec) 19 | { 20 | setCodec(codec); 21 | } 22 | 23 | QAVAudioFormat QAVAudioCodec::audioFormat() const 24 | { 25 | Q_D(const QAVCodec); 26 | QAVAudioFormat format; 27 | if (!d->avctx) 28 | return format; 29 | 30 | auto fmt = AVSampleFormat(d->avctx->sample_fmt); 31 | if (fmt == AV_SAMPLE_FMT_U8) 32 | format.setSampleFormat(QAVAudioFormat::UInt8); 33 | else if (fmt == AV_SAMPLE_FMT_S16) 34 | format.setSampleFormat(QAVAudioFormat::Int16); 35 | else if (fmt == AV_SAMPLE_FMT_S32) 36 | format.setSampleFormat(QAVAudioFormat::Int32); 37 | else if (fmt == AV_SAMPLE_FMT_FLT) 38 | format.setSampleFormat(QAVAudioFormat::Float); 39 | 40 | format.setSampleRate(d->avctx->sample_rate); 41 | #if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(59, 23, 0) 42 | format.setChannelCount(d->avctx->channels); 43 | #else 44 | format.setChannelCount(d->avctx->ch_layout.nb_channels); 45 | #endif 46 | 47 | return format; 48 | } 49 | 50 | QT_END_NAMESPACE 51 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiocodec_p.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVAUDIOCODEC_P_H 9 | #define QAVAUDIOCODEC_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavframecodec_p.h" 23 | #include "qavaudioformat.h" 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVAudioCodec : public QAVFrameCodec 28 | { 29 | public: 30 | QAVAudioCodec(const AVCodec *codec = nullptr); 31 | QAVAudioFormat audioFormat() const; 32 | 33 | private: 34 | Q_DISABLE_COPY(QAVAudioCodec) 35 | }; 36 | 37 | QT_END_NAMESPACE 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudioconverter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2024, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavaudioconverter.h" 9 | #include 10 | 11 | extern "C" { 12 | #include "libswresample/swresample.h" 13 | } 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QAVAudioConverterPrivate 18 | { 19 | public: 20 | SwrContext *swr_ctx = nullptr; 21 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 22 | int64_t outChannelLayout = 0; 23 | #else 24 | AVChannelLayout outChannelLayout; 25 | #endif 26 | AVSampleFormat outFormat = AV_SAMPLE_FMT_NONE; 27 | int outSampleRate = 0; 28 | 29 | uint8_t *audioBuf = nullptr; 30 | }; 31 | 32 | QAVAudioConverter::QAVAudioConverter() 33 | : d_ptr(new QAVAudioConverterPrivate) 34 | { 35 | } 36 | 37 | QAVAudioConverter::~QAVAudioConverter() 38 | { 39 | Q_D(QAVAudioConverter); 40 | swr_free(&d->swr_ctx); 41 | av_freep(&d->audioBuf); 42 | } 43 | 44 | QByteArray QAVAudioConverter::data(const QAVAudioFrame &audioFrame) 45 | { 46 | Q_D(QAVAudioConverter); 47 | const auto frame = audioFrame.frame(); 48 | if (!frame) 49 | return {}; 50 | 51 | QByteArray audioData; 52 | const auto fmt = audioFrame.format(); 53 | AVSampleFormat outFormat = AV_SAMPLE_FMT_NONE; 54 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 55 | int64_t outChannelLayout = av_get_default_channel_layout(fmt.channelCount()); 56 | #else 57 | AVChannelLayout outChannelLayout; 58 | av_channel_layout_default(&outChannelLayout, fmt.channelCount()); 59 | #endif 60 | int outSampleRate = fmt.sampleRate(); 61 | 62 | switch (fmt.sampleFormat()) { 63 | case QAVAudioFormat::UInt8: 64 | outFormat = AV_SAMPLE_FMT_U8; 65 | break; 66 | case QAVAudioFormat::Int16: 67 | outFormat = AV_SAMPLE_FMT_S16; 68 | break; 69 | case QAVAudioFormat::Int32: 70 | outFormat = AV_SAMPLE_FMT_S32; 71 | break; 72 | case QAVAudioFormat::Float: 73 | outFormat = AV_SAMPLE_FMT_FLT; 74 | break; 75 | default: 76 | qWarning() << "Could not negotiate output format:" << fmt.sampleFormat(); 77 | return {}; 78 | } 79 | 80 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 81 | int64_t channelLayout = (frame->channel_layout && frame->channels == av_get_channel_layout_nb_channels(frame->channel_layout)) 82 | ? frame->channel_layout 83 | : av_get_default_channel_layout(frame->channels); 84 | bool needsConvert = frame->format != outFormat || channelLayout != outChannelLayout || frame->sample_rate != d->outSampleRate; 85 | #else 86 | AVChannelLayout channelLayout = frame->ch_layout; 87 | bool needsConvert = frame->format != outFormat || av_channel_layout_compare(&channelLayout, &outChannelLayout) || frame->sample_rate != outSampleRate; 88 | #endif 89 | 90 | if (needsConvert) { 91 | bool needsCtxChange = outFormat != d->outFormat || outSampleRate != d->outSampleRate || 92 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 93 | outChannelLayout != d->outChannelLayout; 94 | #else 95 | av_channel_layout_compare(&outChannelLayout, &d->outChannelLayout); 96 | #endif 97 | if (needsCtxChange || !d->swr_ctx) { 98 | swr_free(&d->swr_ctx); 99 | #if LIBSWRESAMPLE_VERSION_INT <= AV_VERSION_INT(4, 4, 0) 100 | d->swr_ctx = swr_alloc_set_opts(nullptr, 101 | outChannelLayout, outFormat, outSampleRate, 102 | channelLayout, AVSampleFormat(frame->format), frame->sample_rate, 103 | 0, nullptr); 104 | #else 105 | swr_alloc_set_opts2(&d->swr_ctx, 106 | &outChannelLayout, outFormat, outSampleRate, 107 | &channelLayout, AVSampleFormat(frame->format), frame->sample_rate, 108 | 0, nullptr); 109 | #endif 110 | int ret = swr_init(d->swr_ctx); 111 | if (!d->swr_ctx || ret < 0) { 112 | qWarning() << "Could not init SwrContext:" << ret; 113 | return {}; 114 | } 115 | d->outChannelLayout = outChannelLayout; 116 | d->outFormat = outFormat; 117 | d->outSampleRate = outSampleRate; 118 | } 119 | } 120 | 121 | if (d->swr_ctx) { 122 | const uint8_t **in = (const uint8_t **)frame->extended_data; 123 | int outCount = (int64_t)frame->nb_samples * outSampleRate / frame->sample_rate + 256; 124 | int outSize = av_samples_get_buffer_size(nullptr, fmt.channelCount(), outCount, outFormat, 0); 125 | 126 | av_freep(&d->audioBuf); 127 | uint8_t **out = &d->audioBuf; 128 | unsigned bufSize = 0; 129 | av_fast_malloc(&d->audioBuf, &bufSize, outSize); 130 | 131 | int samples = swr_convert(d->swr_ctx, out, outCount, in, frame->nb_samples); 132 | if (samples < 0) { 133 | qWarning() << "Could not convert audio samples"; 134 | return {}; 135 | } 136 | 137 | int size = samples * fmt.channelCount() * av_get_bytes_per_sample(outFormat); 138 | // Make deep copy 139 | audioData = QByteArray((const char *)d->audioBuf, size); 140 | } else { 141 | int size = av_samples_get_buffer_size(nullptr, 142 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 143 | frame->channels, 144 | #else 145 | outChannelLayout.nb_channels, 146 | #endif 147 | frame->nb_samples, 148 | AVSampleFormat(frame->format), 1); 149 | // Return data from the frame 150 | audioData = QByteArray::fromRawData((const char *)frame->data[0], size); 151 | } 152 | 153 | return audioData; 154 | } 155 | 156 | QT_END_NAMESPACE 157 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudioconverter.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2024, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFAUDIOCONVERTER_H 9 | #define QAVFAUDIOCONVERTER_H 10 | 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QAVAudioConverterPrivate; 16 | class QAVAudioConverter 17 | { 18 | public: 19 | QAVAudioConverter(); 20 | ~QAVAudioConverter(); 21 | 22 | QByteArray data(const QAVAudioFrame &frame); 23 | 24 | private: 25 | Q_DISABLE_COPY(QAVAudioConverter) 26 | Q_DECLARE_PRIVATE(QAVAudioConverter) 27 | std::unique_ptr d_ptr; 28 | }; 29 | 30 | QT_END_NAMESPACE 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiofilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavaudiofilter_p.h" 9 | #include "qavfilter_p_p.h" 10 | #include "qavcodec_p.h" 11 | #include "qavstream.h" 12 | #include 13 | 14 | extern "C" { 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | } 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | class QAVAudioFilterPrivate : public QAVFilterPrivate 25 | { 26 | public: 27 | QAVAudioFilterPrivate(QAVFilter *q, QMutex &mutex) : QAVFilterPrivate(q, mutex) { } 28 | 29 | QList inputs; 30 | QList outputs; 31 | int64_t filter_in_rescale_delta_last = AV_NOPTS_VALUE; 32 | }; 33 | 34 | QAVAudioFilter::QAVAudioFilter( 35 | const QAVStream &stream, 36 | const QString &name, 37 | const QList &inputs, 38 | const QList &outputs, 39 | QMutex &mutex) 40 | : QAVFilter( 41 | stream, 42 | name, 43 | *new QAVAudioFilterPrivate(this, mutex)) 44 | { 45 | Q_D(QAVAudioFilter); 46 | d->inputs = inputs; 47 | d->outputs = outputs; 48 | } 49 | 50 | int QAVAudioFilter::write(const QAVFrame &frame) 51 | { 52 | Q_D(QAVAudioFilter); 53 | if (!frame || frame.stream().stream()->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { 54 | qWarning() << "Frame is not audio"; 55 | return AVERROR(EINVAL); 56 | } 57 | if (!d->isEmpty) 58 | return AVERROR(EAGAIN); 59 | 60 | d->sourceFrame = frame; 61 | AVFrame *decoded_frame = d->sourceFrame.frame(); 62 | AVRational decoded_frame_tb = d->sourceFrame.stream().stream()->time_base; 63 | // TODO: clear filter_in_rescale_delta_last 64 | if (!d->inputs.isEmpty() && decoded_frame->pts != AV_NOPTS_VALUE) { 65 | decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts, 66 | AVRational{1, decoded_frame->sample_rate}, 67 | decoded_frame->nb_samples, 68 | &d->filter_in_rescale_delta_last, 69 | AVRational{1, decoded_frame->sample_rate}); 70 | } 71 | 72 | for (auto &filter : d->inputs) { 73 | QAVFrame ref = d->sourceFrame; 74 | QMutexLocker locker(&d->graphMutex); 75 | int ret = av_buffersrc_add_frame_flags(filter.ctx(), ref.frame(), AV_BUFFERSRC_FLAG_PUSH); 76 | if (ret < 0) 77 | return ret; 78 | } 79 | d->isEmpty = false; 80 | return 0; 81 | } 82 | 83 | int QAVAudioFilter::read(QAVFrame &frame) 84 | { 85 | Q_D(QAVAudioFilter); 86 | if (d->outputs.isEmpty() || d->isEmpty) { 87 | int ret = AVERROR(EAGAIN); 88 | if (d->sourceFrame && d->outputs.isEmpty()) { 89 | frame = d->sourceFrame; 90 | ret = 0; 91 | } 92 | d->sourceFrame = {}; 93 | d->isEmpty = true; 94 | return ret; 95 | } 96 | 97 | int ret = 0; 98 | if (d->outputFrames.isEmpty()) { 99 | for (int i = 0; i < d->outputs.size(); ++i) { 100 | const auto &filter = d->outputs[i]; 101 | while (true) { 102 | QAVFrame out = d->sourceFrame; 103 | // av_buffersink_get_frame_flags allocates frame's data 104 | av_frame_unref(out.frame()); 105 | { 106 | QMutexLocker locker(&d->graphMutex); 107 | ret = av_buffersink_get_frame_flags(filter.ctx(), out.frame(), 0); 108 | } 109 | if (ret < 0) 110 | break; 111 | 112 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 30, 0) 113 | if (!out.frame()->pkt_duration) 114 | out.frame()->pkt_duration = d->sourceFrame.frame()->pkt_duration; 115 | #else 116 | if (out.frame()->duration == AV_NOPTS_VALUE || out.frame()->duration == 0) 117 | out.frame()->duration = d->sourceFrame.frame()->duration; 118 | #endif 119 | out.setFrameRate(av_buffersink_get_frame_rate(filter.ctx())); 120 | out.setTimeBase(av_buffersink_get_time_base(filter.ctx())); 121 | out.setFilterName( 122 | !filter.name().isEmpty() 123 | ? filter.name() 124 | : QString(QLatin1String("%1:%2")).arg(d->name).arg(QString::number(i))); 125 | if (!out.stream()) 126 | out.setStream(d->stream); 127 | d->outputFrames.push_back(out); 128 | } 129 | } 130 | } 131 | 132 | ret = AVERROR(EAGAIN); 133 | if (!d->outputFrames.isEmpty()) { 134 | frame = d->outputFrames.takeFirst(); 135 | ret = 0; 136 | } 137 | if (d->outputFrames.isEmpty()) { 138 | d->sourceFrame = {}; 139 | d->isEmpty = true; 140 | } 141 | return ret; 142 | } 143 | 144 | void QAVAudioFilter::flush() 145 | { 146 | Q_D(QAVAudioFilter); 147 | for (const auto &filter : d->inputs) { 148 | int ret = av_buffersrc_add_frame(filter.ctx(), nullptr); 149 | if (ret < 0) 150 | qWarning() << "Could not flush:" << ret; 151 | } 152 | d->isEmpty = false; 153 | } 154 | 155 | QT_END_NAMESPACE 156 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiofilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVAUDIOFILTER_P_H 9 | #define QAVAUDIOFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavfilter_p.h" 23 | #include "qavaudioinputfilter_p.h" 24 | #include "qavaudiooutputfilter_p.h" 25 | #include 26 | #include 27 | 28 | QT_BEGIN_NAMESPACE 29 | 30 | class QAVAudioFilterPrivate; 31 | class QAVAudioFilter : public QAVFilter 32 | { 33 | public: 34 | QAVAudioFilter( 35 | const QAVStream &stream, 36 | const QString &name, 37 | const QList &inputs, 38 | const QList &outputs, 39 | QMutex &mutex); 40 | 41 | int write(const QAVFrame &frame) override; 42 | int read(QAVFrame &frame) override; 43 | void flush() override; 44 | 45 | protected: 46 | Q_DECLARE_PRIVATE(QAVAudioFilter) 47 | private: 48 | Q_DISABLE_COPY(QAVAudioFilter) 49 | }; 50 | 51 | QT_END_NAMESPACE 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudioformat.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVAUDIOFORMAT_H 9 | #define QAVAUDIOFORMAT_H 10 | 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QAVAudioFormat 16 | { 17 | public: 18 | enum SampleFormat 19 | { 20 | Unknown, 21 | UInt8, 22 | Int16, 23 | Int32, 24 | Float 25 | }; 26 | 27 | SampleFormat sampleFormat() const { return m_sampleFormat; } 28 | void setSampleFormat(SampleFormat f) { m_sampleFormat = f; } 29 | 30 | int sampleRate() const { return m_sampleRate; } 31 | void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; } 32 | 33 | int channelCount() const { return m_channelCount; } 34 | void setChannelCount(int channelCount) { m_channelCount = channelCount; } 35 | 36 | operator bool() const 37 | { 38 | return m_sampleFormat != SampleFormat::Unknown && m_sampleRate != 0 && m_channelCount != 0; 39 | } 40 | 41 | friend bool operator==(const QAVAudioFormat &a, const QAVAudioFormat &b) 42 | { 43 | return a.m_sampleRate == b.m_sampleRate && 44 | a.m_channelCount == b.m_channelCount && 45 | a.m_sampleFormat == b.m_sampleFormat; 46 | } 47 | 48 | friend bool operator!=(const QAVAudioFormat &a, const QAVAudioFormat &b) 49 | { 50 | return !(a == b); 51 | } 52 | 53 | private: 54 | SampleFormat m_sampleFormat = Unknown; 55 | int m_sampleRate = 0; 56 | int m_channelCount = 0; 57 | }; 58 | 59 | QT_END_NAMESPACE 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudioframe.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavaudioframe.h" 9 | #include "qavaudioconverter.h" 10 | #include "qavframe_p.h" 11 | #include "qavaudiocodec_p.h" 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | 16 | class QAVAudioFramePrivate : public QAVFramePrivate 17 | { 18 | public: 19 | QAVAudioFormat outAudioFormat; 20 | QByteArray data; 21 | }; 22 | 23 | QAVAudioFrame::QAVAudioFrame() 24 | : QAVFrame(*new QAVAudioFramePrivate) 25 | { 26 | } 27 | 28 | QAVAudioFrame::QAVAudioFrame(const QAVFrame &other) 29 | : QAVFrame(*new QAVAudioFramePrivate) 30 | { 31 | operator=(other); 32 | } 33 | 34 | QAVAudioFrame::QAVAudioFrame(const QAVAudioFrame &other) 35 | : QAVFrame(*new QAVAudioFramePrivate) 36 | { 37 | operator=(other); 38 | } 39 | 40 | QAVAudioFrame::QAVAudioFrame(const QAVAudioFormat &format, const QByteArray &data) 41 | : QAVAudioFrame() 42 | { 43 | Q_D(QAVAudioFrame); 44 | d->outAudioFormat = format; 45 | d->data = data; 46 | } 47 | 48 | QAVAudioFrame &QAVAudioFrame::operator=(const QAVFrame &other) 49 | { 50 | Q_D(QAVAudioFrame); 51 | QAVFrame::operator=(other); 52 | d->data.clear(); 53 | 54 | return *this; 55 | } 56 | 57 | QAVAudioFrame &QAVAudioFrame::operator=(const QAVAudioFrame &other) 58 | { 59 | Q_D(QAVAudioFrame); 60 | QAVFrame::operator=(other); 61 | auto rhs = reinterpret_cast(other.d_ptr.get()); 62 | d->outAudioFormat = rhs->outAudioFormat; 63 | d->data = rhs->data; 64 | 65 | return *this; 66 | } 67 | 68 | QAVAudioFrame::operator bool() const 69 | { 70 | Q_D(const QAVAudioFrame); 71 | return (d->outAudioFormat &&!d->data.isEmpty()) || QAVFrame::operator bool(); 72 | } 73 | 74 | static const QAVAudioCodec *audioCodec(const QAVCodec *c) 75 | { 76 | return reinterpret_cast(c); 77 | } 78 | 79 | QAVAudioFormat QAVAudioFrame::format() const 80 | { 81 | Q_D(const QAVAudioFrame); 82 | if (d->outAudioFormat) 83 | return d->outAudioFormat; 84 | 85 | if (!d->stream) 86 | return {}; 87 | 88 | auto c = audioCodec(d->stream.codec().data()); 89 | if (!c) 90 | return {}; 91 | 92 | auto format = c->audioFormat(); 93 | if (format.sampleFormat() != QAVAudioFormat::Int32) 94 | format.setSampleFormat(QAVAudioFormat::Int32); 95 | 96 | return format; 97 | } 98 | 99 | QByteArray QAVAudioFrame::data() const 100 | { 101 | auto d = const_cast(reinterpret_cast(d_ptr.get())); 102 | if (d->data.isEmpty()) { 103 | d->outAudioFormat = format(); 104 | d->data = QAVAudioConverter().data(*this); 105 | } 106 | return d->data; 107 | } 108 | 109 | QT_END_NAMESPACE 110 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudioframe.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFAUDIOFRAME_H 9 | #define QAVFAUDIOFRAME_H 10 | 11 | #include 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | 16 | class QAVAudioCodec; 17 | class QAVAudioFramePrivate; 18 | class QAVAudioFrame : public QAVFrame 19 | { 20 | public: 21 | QAVAudioFrame(); 22 | QAVAudioFrame(const QAVFrame &other); 23 | QAVAudioFrame(const QAVAudioFrame &other); 24 | QAVAudioFrame(const QAVAudioFormat &format, const QByteArray &data); 25 | QAVAudioFrame &operator=(const QAVFrame &other); 26 | QAVAudioFrame &operator=(const QAVAudioFrame &other); 27 | operator bool() const; 28 | 29 | QAVAudioFormat format() const; 30 | QByteArray data() const; 31 | 32 | private: 33 | Q_DECLARE_PRIVATE(QAVAudioFrame) 34 | }; 35 | 36 | Q_DECLARE_METATYPE(QAVAudioFrame) 37 | 38 | QT_END_NAMESPACE 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudioinputfilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #if !defined(__STDC_FORMAT_MACROS) 9 | #define __STDC_FORMAT_MACROS 1 10 | #endif 11 | #include 12 | 13 | #include "qavframe.h" 14 | #include "qavaudioinputfilter_p.h" 15 | #include "qavinoutfilter_p_p.h" 16 | #include "qavdemuxer_p.h" 17 | #include 18 | 19 | extern "C" { 20 | #include 21 | #include 22 | #include 23 | } 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVAudioInputFilterPrivate : public QAVInOutFilterPrivate 28 | { 29 | public: 30 | QAVAudioInputFilterPrivate(QAVInOutFilter *q) 31 | : QAVInOutFilterPrivate(q) 32 | { } 33 | 34 | AVSampleFormat format = AV_SAMPLE_FMT_NONE; 35 | int sample_rate = 0; 36 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 37 | uint64_t channel_layout = 0; 38 | int channels = 0; 39 | #else 40 | AVChannelLayout ch_layout; 41 | #endif 42 | }; 43 | 44 | QAVAudioInputFilter::QAVAudioInputFilter() 45 | : QAVInOutFilter(*new QAVAudioInputFilterPrivate(this)) 46 | { 47 | } 48 | 49 | QAVAudioInputFilter::QAVAudioInputFilter(const QAVFrame &frame) 50 | : QAVAudioInputFilter() 51 | { 52 | Q_D(QAVAudioInputFilter); 53 | const auto & frm = frame.frame(); 54 | const auto & stream = frame.stream().stream(); 55 | d->format = frm->format != AV_SAMPLE_FMT_NONE ? AVSampleFormat(frm->format) : AVSampleFormat(stream->codecpar->format); 56 | d->sample_rate = frm->sample_rate ? frm->sample_rate : stream->codecpar->sample_rate; 57 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 58 | d->channel_layout = frm->channel_layout ? frm->channel_layout : stream->codecpar->channel_layout; 59 | d->channels = frm->channels ? frm->channels : stream->codecpar->channels; 60 | #else 61 | d->ch_layout = frm->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC ? frm->ch_layout : stream->codecpar->ch_layout; 62 | #endif 63 | } 64 | 65 | QAVAudioInputFilter::QAVAudioInputFilter(const QAVAudioInputFilter &other) 66 | : QAVAudioInputFilter() 67 | { 68 | *this = other; 69 | } 70 | 71 | QAVAudioInputFilter::~QAVAudioInputFilter() = default; 72 | 73 | QAVAudioInputFilter &QAVAudioInputFilter::operator=(const QAVAudioInputFilter &other) 74 | { 75 | Q_D(QAVAudioInputFilter); 76 | QAVInOutFilter::operator=(other); 77 | d->format = other.d_func()->format; 78 | d->sample_rate = other.d_func()->sample_rate; 79 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 80 | d->channel_layout = other.d_func()->channel_layout; 81 | d->channels = other.d_func()->channels; 82 | #else 83 | d->ch_layout = other.d_func()->ch_layout; 84 | #endif 85 | return *this; 86 | } 87 | 88 | int QAVAudioInputFilter::configure(AVFilterGraph *graph, AVFilterInOut *in) 89 | { 90 | QAVInOutFilter::configure(graph, in); 91 | Q_D(QAVAudioInputFilter); 92 | AVBPrint args; 93 | av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC); 94 | av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s", 95 | 1, d->sample_rate, 96 | d->sample_rate, 97 | av_get_sample_fmt_name(AVSampleFormat(d->format))); 98 | 99 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0) 100 | if (d->channel_layout) 101 | av_bprintf(&args, ":channel_layout=0x%" PRIx64, d->channel_layout); 102 | else 103 | av_bprintf(&args, ":channels=%d", d->channels); 104 | #else 105 | if (av_channel_layout_check(&d->ch_layout) && 106 | d->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) { 107 | av_bprintf(&args, ":channel_layout="); 108 | av_channel_layout_describe_bprint(&d->ch_layout, &args); 109 | } else { 110 | av_bprintf(&args, ":channels=%d", d->ch_layout.nb_channels); 111 | } 112 | #endif 113 | 114 | char name[255]; 115 | static int index = 0; 116 | snprintf(name, sizeof(name), "abuffer_%d", index++); 117 | 118 | int ret = avfilter_graph_create_filter(&d->ctx, 119 | avfilter_get_by_name("abuffer"), 120 | name, args.str, nullptr, graph); 121 | if (ret < 0) 122 | return ret; 123 | 124 | return avfilter_link(d->ctx, 0, in->filter_ctx, in->pad_idx); 125 | } 126 | 127 | QT_END_NAMESPACE 128 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudioinputfilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVAUDIOINPUTFILTER_P_H 9 | #define QAVAUDIOINPUTFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavinoutfilter_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVFrame; 27 | class QAVAudioInputFilterPrivate; 28 | class QAVAudioInputFilter : public QAVInOutFilter 29 | { 30 | public: 31 | QAVAudioInputFilter(const QAVFrame &frame); 32 | QAVAudioInputFilter(const QAVAudioInputFilter &other); 33 | ~QAVAudioInputFilter(); 34 | QAVAudioInputFilter &operator=(const QAVAudioInputFilter &other); 35 | 36 | int configure(AVFilterGraph *graph, AVFilterInOut *in) override; 37 | 38 | protected: 39 | QAVAudioInputFilter(); 40 | Q_DECLARE_PRIVATE(QAVAudioInputFilter) 41 | }; 42 | 43 | QT_END_NAMESPACE 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiooutput.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVAUDIOOUTPUT_H 9 | #define QAVAUDIOOUTPUT_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | class QAVAudioOutputPrivate; 20 | class QAVAudioOutput : public QObject 21 | { 22 | Q_OBJECT 23 | public: 24 | QAVAudioOutput(QObject *parent = nullptr); 25 | ~QAVAudioOutput(); 26 | 27 | void setVolume(qreal v); 28 | qreal volume() const; 29 | void setBufferSize(int bytes); 30 | int bufferSize() const; 31 | #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) 32 | void setChannelConfig(QAudioFormat::ChannelConfig); 33 | QAudioFormat::ChannelConfig channelConfig() const; 34 | #endif 35 | 36 | bool play(const QAVAudioFrame &frame); 37 | 38 | public Q_SLOTS: 39 | // No audio should be rendered if stopped even if play() is called 40 | void stop(); 41 | 42 | private: 43 | Q_DISABLE_COPY(QAVAudioOutput) 44 | Q_DECLARE_PRIVATE(QAVAudioOutput) 45 | std::unique_ptr d_ptr; 46 | }; 47 | 48 | QT_END_NAMESPACE 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiooutputdevice.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2024, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavaudiooutputdevice.h" 9 | #include "qavaudioconverter.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QAVAudioOutputDevicePrivate 18 | { 19 | public: 20 | QList frames; 21 | qint64 offset = 0; 22 | quint64 bytes = 0; 23 | QAVAudioConverter conv; 24 | mutable QMutex mutex; 25 | QWaitCondition cond; 26 | bool quit = false; 27 | }; 28 | 29 | QAVAudioOutputDevice::QAVAudioOutputDevice(QObject *parent) 30 | : QIODevice(parent) 31 | , d_ptr(new QAVAudioOutputDevicePrivate) 32 | { 33 | } 34 | 35 | QAVAudioOutputDevice::~QAVAudioOutputDevice() 36 | { 37 | stop(); 38 | } 39 | 40 | qint64 QAVAudioOutputDevice::readData(char *data, qint64 len) 41 | { 42 | Q_D(QAVAudioOutputDevice); 43 | if (!len) 44 | return 0; 45 | 46 | QMutexLocker locker(&d->mutex); 47 | qint64 bytesWritten = 0; 48 | while (len && !d->quit) { 49 | if (d->frames.isEmpty()) { 50 | d->cond.wait(&d->mutex); 51 | if (d->quit || d->frames.isEmpty()) 52 | break; 53 | } 54 | 55 | auto &sampleData = d->frames.front(); 56 | const int toWrite = qMin(sampleData.size() - d->offset, len); 57 | memcpy(data, sampleData.constData() + d->offset, toWrite); 58 | bytesWritten += toWrite; 59 | data += toWrite; 60 | len -= toWrite; 61 | d->offset += toWrite; 62 | 63 | if (d->offset >= sampleData.size()) { 64 | d->offset = 0; 65 | d->bytes -= sampleData.size(); 66 | d->frames.removeFirst(); 67 | } 68 | } 69 | if (d->quit) { 70 | memset(data, 0, static_cast(len)); 71 | bytesWritten = len; 72 | } 73 | return bytesWritten; 74 | } 75 | 76 | void QAVAudioOutputDevice::play(const QAVAudioFrame &frame) 77 | { 78 | Q_D(QAVAudioOutputDevice); 79 | { 80 | QMutexLocker locker(&d->mutex); 81 | auto data = d->conv.data(frame); 82 | d->bytes += data.size(); 83 | d->frames.push_back(std::move(data)); 84 | } 85 | d->cond.wakeAll(); 86 | } 87 | 88 | void QAVAudioOutputDevice::start() 89 | { 90 | Q_D(QAVAudioOutputDevice); 91 | { 92 | QMutexLocker locker(&d->mutex); 93 | d->quit = false; 94 | } 95 | d->cond.wakeAll(); 96 | } 97 | 98 | void QAVAudioOutputDevice::stop() 99 | { 100 | Q_D(QAVAudioOutputDevice); 101 | { 102 | QMutexLocker locker(&d->mutex); 103 | d->quit = true; 104 | } 105 | d->cond.wakeAll(); 106 | } 107 | 108 | quint64 QAVAudioOutputDevice::bytesInQueue() const 109 | { 110 | Q_D(const QAVAudioOutputDevice); 111 | QMutexLocker locker(&d->mutex); 112 | return d->bytes; 113 | } 114 | 115 | QT_END_NAMESPACE 116 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiooutputdevice.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2024, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVAUDIOOUTPUTDEVICE_H 9 | #define QAVAUDIOOUTPUTDEVICE_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QAVAudioOutputDevicePrivate; 19 | class QAVAudioOutputDevice : public QIODevice 20 | { 21 | Q_OBJECT 22 | public: 23 | QAVAudioOutputDevice(QObject *parent = nullptr); 24 | ~QAVAudioOutputDevice(); 25 | 26 | qint64 readData(char *data, qint64 len) override; 27 | qint64 writeData(const char *, qint64) override { return 0; } 28 | qint64 size() const override { return 0; } 29 | qint64 bytesAvailable() const override { return std::numeric_limits::max(); } 30 | bool isSequential() const override { return false; } 31 | bool atEnd() const override { return false; } 32 | 33 | // Enqueues the audio frame to be sent from readData() 34 | void play(const QAVAudioFrame &frame); 35 | // Start sending the audio data from readData() 36 | void start(); 37 | // Don't send the audio data from readData() 38 | void stop(); 39 | quint64 bytesInQueue() const; 40 | 41 | protected: 42 | std::unique_ptr d_ptr; 43 | 44 | private: 45 | Q_DISABLE_COPY(QAVAudioOutputDevice) 46 | Q_DECLARE_PRIVATE(QAVAudioOutputDevice) 47 | }; 48 | 49 | QT_END_NAMESPACE 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiooutputfilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavaudiooutputfilter_p.h" 9 | #include "qavinoutfilter_p_p.h" 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | #include 15 | #include 16 | } 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | QAVAudioOutputFilter::QAVAudioOutputFilter() 21 | : QAVInOutFilter(*new QAVInOutFilterPrivate(this)) 22 | { 23 | } 24 | 25 | QAVAudioOutputFilter::~QAVAudioOutputFilter() = default; 26 | 27 | int QAVAudioOutputFilter::configure(AVFilterGraph *graph, AVFilterInOut *out) 28 | { 29 | QAVInOutFilter::configure(graph, out); 30 | Q_D(QAVInOutFilter); 31 | char name[255]; 32 | static int index = 0; 33 | snprintf(name, sizeof(name), "out_%d", index++); 34 | int ret = avfilter_graph_create_filter(&d->ctx, 35 | avfilter_get_by_name("abuffersink"), 36 | name, nullptr, nullptr, graph); 37 | if (ret < 0) 38 | return ret; 39 | 40 | return avfilter_link(out->filter_ctx, out->pad_idx, d->ctx, 0); 41 | } 42 | 43 | QT_END_NAMESPACE 44 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavaudiooutputfilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVAUDIOOUTPUTFILTER_P_H 9 | #define QAVAUDIOOUTPUTFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavinoutfilter_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVAudioOutputFilterPrivate; 27 | class QAVAudioOutputFilter : public QAVInOutFilter 28 | { 29 | public: 30 | QAVAudioOutputFilter(); 31 | ~QAVAudioOutputFilter(); 32 | 33 | int configure(AVFilterGraph *graph, AVFilterInOut *out) override; 34 | }; 35 | 36 | QT_END_NAMESPACE 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavcodec.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #include "qavcodec_p.h" 9 | #include "qavcodec_p_p.h" 10 | 11 | #include 12 | 13 | extern "C" { 14 | #include 15 | #include 16 | #include 17 | } 18 | 19 | QT_BEGIN_NAMESPACE 20 | 21 | QAVCodec::QAVCodec() 22 | : QAVCodec(*new QAVCodecPrivate) 23 | { 24 | } 25 | 26 | QAVCodec::QAVCodec(QAVCodecPrivate &d, const AVCodec *codec) 27 | : d_ptr(&d) 28 | { 29 | d_ptr->avctx = avcodec_alloc_context3(codec); 30 | d_ptr->codec = codec; 31 | } 32 | 33 | QAVCodec::~QAVCodec() 34 | { 35 | Q_D(QAVCodec); 36 | if (d->avctx) 37 | avcodec_free_context(&d->avctx); 38 | } 39 | 40 | void QAVCodec::setCodec(const AVCodec *c) 41 | { 42 | d_func()->codec = c; 43 | } 44 | 45 | bool QAVCodec::open(AVStream *stream, AVDictionary** opts) 46 | { 47 | Q_D(QAVCodec); 48 | 49 | if (!stream) 50 | return false; 51 | int ret = avcodec_parameters_to_context(d->avctx, stream->codecpar); 52 | if (ret < 0) { 53 | qWarning() << "Failed avcodec_parameters_to_context:" << ret; 54 | return false; 55 | } 56 | 57 | d->avctx->pkt_timebase = stream->time_base; 58 | d->avctx->framerate = stream->avg_frame_rate; 59 | if (!d->codec) 60 | d->codec = avcodec_find_decoder(d->avctx->codec_id); 61 | if (!d->codec) { 62 | qWarning() << "No decoder could be found for codec:" << d->avctx->codec_id << 63 | (d->avctx->codec ? d->avctx->codec->name : ""); 64 | return false; 65 | } 66 | 67 | d->avctx->codec_id = d->codec->id; 68 | ret = avcodec_open2(d->avctx, d->codec, opts); 69 | if (ret < 0) { 70 | qWarning() << "Could not open the codec:" << d->codec->name << d->codec->id << ret; 71 | return false; 72 | } 73 | 74 | stream->discard = AVDISCARD_DEFAULT; 75 | d->stream = stream; 76 | 77 | return true; 78 | } 79 | 80 | AVCodecContext *QAVCodec::avctx() const 81 | { 82 | return d_func()->avctx; 83 | } 84 | 85 | const AVCodec *QAVCodec::codec() const 86 | { 87 | return d_func()->codec; 88 | } 89 | 90 | void QAVCodec::flushBuffers() 91 | { 92 | Q_D(QAVCodec); 93 | if (!d->avctx) 94 | return; 95 | avcodec_flush_buffers(d->avctx); 96 | } 97 | QT_END_NAMESPACE 98 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavcodec_p.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVCODEC_P_H 9 | #define QAVCODEC_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavpacket.h" 23 | #include "qavframe.h" 24 | #include 25 | #include 26 | 27 | extern "C" { 28 | #include 29 | } 30 | 31 | QT_BEGIN_NAMESPACE 32 | 33 | struct AVCodec; 34 | struct AVCodecContext; 35 | struct AVStream; 36 | class QAVCodecPrivate; 37 | class QAVCodec 38 | { 39 | public: 40 | virtual ~QAVCodec(); 41 | 42 | bool open(AVStream *stream, AVDictionary** opts = NULL); 43 | AVCodecContext *avctx() const; 44 | void setCodec(const AVCodec *c); 45 | const AVCodec *codec() const; 46 | 47 | void flushBuffers(); 48 | 49 | // Sends a packet 50 | virtual int write(const QAVPacket &pkt) = 0; 51 | // Sends a frame 52 | virtual int write(const QAVStreamFrame &frame) = 0; 53 | // Receives a frame 54 | // NOTE: There could be multiple frames 55 | virtual int read(QAVStreamFrame &frame) = 0; 56 | // Receives a packet 57 | virtual int read(QAVPacket &pkt) = 0; 58 | 59 | protected: 60 | QAVCodec(); 61 | QAVCodec(QAVCodecPrivate &d, const AVCodec *codec = nullptr); 62 | 63 | std::unique_ptr d_ptr; 64 | Q_DECLARE_PRIVATE(QAVCodec) 65 | private: 66 | Q_DISABLE_COPY(QAVCodec) 67 | }; 68 | 69 | QT_END_NAMESPACE 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavcodec_p_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVCODEC_P_P_H 9 | #define QAVCODEC_P_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavcodec_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | struct AVCodec; 27 | struct AVStream; 28 | struct AVCodecContext; 29 | class QAVCodecPrivate 30 | { 31 | public: 32 | virtual ~QAVCodecPrivate() = default; 33 | 34 | AVCodecContext *avctx = nullptr; 35 | const AVCodec *codec = nullptr; 36 | AVStream *stream = nullptr; 37 | }; 38 | 39 | QT_END_NAMESPACE 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavdemuxer_p.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVDEMUXER_H 9 | #define QAVDEMUXER_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavpacket.h" 23 | #include "qavstream.h" 24 | #include "qavframe.h" 25 | #include "qavsubtitleframe.h" 26 | #include 27 | #include 28 | 29 | QT_BEGIN_NAMESPACE 30 | 31 | extern "C" { 32 | #include 33 | } 34 | 35 | class QAVDemuxerPrivate; 36 | class QAVVideoCodec; 37 | class QAVAudioCodec; 38 | class QAVIODevice; 39 | struct AVStream; 40 | struct AVFormatContext; 41 | class QAVDemuxer 42 | { 43 | public: 44 | QAVDemuxer(); 45 | ~QAVDemuxer(); 46 | 47 | void abort(bool stop = true); 48 | int load(const QString &url, QAVIODevice *dev = nullptr); 49 | void unload(); 50 | 51 | AVMediaType currentCodecType(int index) const; 52 | 53 | QList availableStreams() const; 54 | 55 | QList availableVideoStreams() const; 56 | QList currentVideoStreams() const; 57 | bool setVideoStreams(const QList &streams); 58 | 59 | QList availableAudioStreams() const; 60 | QList currentAudioStreams() const; 61 | bool setAudioStreams(const QList &streams); 62 | 63 | QList availableSubtitleStreams() const; 64 | QList currentSubtitleStreams() const; 65 | bool setSubtitleStreams(const QList &streams); 66 | 67 | AVFormatContext *avctx() const; 68 | /** 69 | * Reads and returns a packet from AVFormatContext 70 | * @return AVERROR 71 | */ 72 | int read(QAVPacket &pkt); 73 | 74 | static void decode(const QAVPacket &pkt, QList &frames); 75 | static void decode(const QAVPacket &pkt, QList &frames); 76 | void flushCodecBuffers(); 77 | 78 | double duration() const; 79 | bool seekable() const; 80 | int seek(double sec); 81 | bool eof() const; 82 | double videoFrameRate() const; 83 | 84 | QMap metadata() const; 85 | 86 | QString bitstreamFilter() const; 87 | int applyBitstreamFilter(const QString &bsfs); 88 | 89 | QString inputFormat() const; 90 | void setInputFormat(const QString &format); 91 | 92 | QString inputVideoCodec() const; 93 | void setInputVideoCodec(const QString &codec); 94 | 95 | QMap inputOptions() const; 96 | void setInputOptions(const QMap &opts); 97 | 98 | QMap videoCodecOptions() const; 99 | void setVideoCodecOptions(const QMap &opts); 100 | 101 | void onFrameSent(const QAVStreamFrame &frame); 102 | QAVStream::Progress progress(const QAVStream &s) const; 103 | 104 | bool isMasterStream(const QAVStream &stream) const; 105 | 106 | static QStringList supportedFormats(); 107 | static QStringList supportedVideoCodecs(); 108 | static QStringList supportedProtocols(); 109 | static QStringList supportedBitstreamFilters(); 110 | 111 | protected: 112 | std::unique_ptr d_ptr; 113 | 114 | private: 115 | int resetCodecs(); 116 | 117 | Q_DISABLE_COPY(QAVDemuxer) 118 | Q_DECLARE_PRIVATE(QAVDemuxer) 119 | }; 120 | 121 | QT_END_NAMESPACE 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavfilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavfilter_p.h" 9 | #include "qavfilter_p_p.h" 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | QAVFilter::QAVFilter( 15 | const QAVStream &stream, 16 | const QString &name, 17 | QAVFilterPrivate &d) 18 | : d_ptr(&d) 19 | { 20 | d.stream = stream; 21 | d.name = name; 22 | } 23 | 24 | QAVFilter::~QAVFilter() = default; 25 | 26 | bool QAVFilter::isEmpty() const 27 | { 28 | return d_func()->isEmpty; 29 | } 30 | 31 | QT_END_NAMESPACE 32 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavfilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFILTER_P_H 9 | #define QAVFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QAVFilterPrivate; 30 | class QAVFilter 31 | { 32 | public: 33 | virtual ~QAVFilter(); 34 | 35 | virtual int write(const QAVFrame &frame) = 0; 36 | virtual int read(QAVFrame &frame) = 0; 37 | // Checks if all frames have been read 38 | bool isEmpty() const; 39 | virtual void flush() = 0; 40 | 41 | protected: 42 | QAVFilter( 43 | const QAVStream &stream, 44 | const QString &name, 45 | QAVFilterPrivate &d); 46 | std::unique_ptr d_ptr; 47 | Q_DECLARE_PRIVATE(QAVFilter) 48 | private: 49 | Q_DISABLE_COPY(QAVFilter) 50 | }; 51 | 52 | QT_END_NAMESPACE 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavfilter_p_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFILTER_P_P_H 9 | #define QAVFILTER_P_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QAVFilter; 30 | class QAVFilterPrivate 31 | { 32 | Q_DECLARE_PUBLIC(QAVFilter) 33 | public: 34 | QAVFilterPrivate(QAVFilter *q, QMutex &mutex) : q_ptr(q), graphMutex(mutex) { } 35 | virtual ~QAVFilterPrivate() = default; 36 | 37 | QAVFilter *q_ptr = nullptr; 38 | QAVStream stream; 39 | QString name; 40 | QAVFrame sourceFrame; 41 | QList outputFrames; 42 | bool isEmpty = true; 43 | QMutex &graphMutex; 44 | }; 45 | 46 | QT_END_NAMESPACE 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavfiltergraph.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavfiltergraph_p.h" 9 | #include "qavcodec_p.h" 10 | #include "qavvideocodec_p.h" 11 | #include "qavaudiocodec_p.h" 12 | #include 13 | 14 | extern "C" { 15 | #include 16 | #include 17 | #include 18 | #include 19 | } 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | class QAVFilterGraphPrivate 24 | { 25 | Q_DECLARE_PUBLIC(QAVFilterGraph) 26 | public: 27 | QAVFilterGraphPrivate(QAVFilterGraph *q) : q_ptr(q) { } 28 | 29 | int read(); 30 | 31 | QAVFilterGraph *q_ptr = nullptr; 32 | QString desc; 33 | AVFilterGraph *graph = nullptr; 34 | AVFilterInOut *outputs = nullptr; 35 | AVFilterInOut *inputs = nullptr; 36 | QList videoInputFilters; 37 | QList videoOutputFilters; 38 | QList audioInputFilters; 39 | QList audioOutputFilters; 40 | mutable QMutex mutex; 41 | }; 42 | 43 | QAVFilterGraph::QAVFilterGraph() 44 | : d_ptr(new QAVFilterGraphPrivate(this)) 45 | { 46 | } 47 | 48 | QAVFilterGraph::~QAVFilterGraph() 49 | { 50 | Q_D(QAVFilterGraph); 51 | avfilter_graph_free(&d->graph); 52 | avfilter_inout_free(&d->inputs); 53 | avfilter_inout_free(&d->outputs); 54 | } 55 | 56 | int QAVFilterGraph::parse(const QString &desc) 57 | { 58 | Q_D(QAVFilterGraph); 59 | d->desc = desc; 60 | avfilter_graph_free(&d->graph); 61 | avfilter_inout_free(&d->inputs); 62 | avfilter_inout_free(&d->outputs); 63 | d->graph = avfilter_graph_alloc(); 64 | return avfilter_graph_parse2(d->graph, desc.toUtf8().constData(), &d->inputs, &d->outputs); 65 | } 66 | 67 | int QAVFilterGraph::apply(const QAVFrame &frame) 68 | { 69 | Q_D(QAVFilterGraph); 70 | if (!frame.stream()) 71 | return 0; 72 | const AVMediaType codec_type = frame.stream().stream()->codecpar->codec_type; 73 | switch (codec_type) { 74 | case AVMEDIA_TYPE_VIDEO: 75 | d->videoInputFilters.clear(); 76 | d->videoOutputFilters.clear(); 77 | break; 78 | case AVMEDIA_TYPE_AUDIO: 79 | d->audioInputFilters.clear(); 80 | d->audioOutputFilters.clear(); 81 | break; 82 | default: 83 | qWarning() << "Could not apply frame: Unsupported codec type:" << codec_type; 84 | return AVERROR(EINVAL); 85 | } 86 | 87 | int ret = 0; 88 | int i = 0; 89 | AVFilterInOut *cur = nullptr; 90 | for (cur = d->inputs, i = 0; cur; cur = cur->next, ++i) { 91 | switch (avfilter_pad_get_type(cur->filter_ctx->input_pads, cur->pad_idx)) { 92 | case AVMEDIA_TYPE_VIDEO: { 93 | if (codec_type == AVMEDIA_TYPE_VIDEO) { 94 | QAVVideoInputFilter filter(frame); 95 | ret = filter.configure(d->graph, cur); 96 | if (ret < 0) 97 | return ret; 98 | d->videoInputFilters.push_back(filter); 99 | } 100 | } break; 101 | case AVMEDIA_TYPE_AUDIO: { 102 | if (codec_type == AVMEDIA_TYPE_AUDIO) { 103 | QAVAudioInputFilter filter(frame); 104 | ret = filter.configure(d->graph, cur); 105 | if (ret < 0) 106 | return ret; 107 | d->audioInputFilters.push_back(filter); 108 | } 109 | } break; 110 | default: 111 | return AVERROR(EINVAL); 112 | } 113 | } 114 | 115 | for (cur = d->outputs, i = 0; cur; cur = cur->next, ++i) { 116 | switch (avfilter_pad_get_type(cur->filter_ctx->output_pads, cur->pad_idx)) { 117 | case AVMEDIA_TYPE_VIDEO: { 118 | if (codec_type == AVMEDIA_TYPE_VIDEO) { 119 | QAVVideoOutputFilter filter; 120 | ret = filter.configure(d->graph, cur); 121 | if (ret < 0) 122 | return ret; 123 | d->videoOutputFilters.push_back(filter); 124 | } 125 | } break; 126 | case AVMEDIA_TYPE_AUDIO: { 127 | if (codec_type == AVMEDIA_TYPE_AUDIO) { 128 | QAVAudioOutputFilter filter; 129 | int ret = filter.configure(d->graph, cur); 130 | if (ret < 0) 131 | return ret; 132 | d->audioOutputFilters.push_back(filter); 133 | } 134 | } break; 135 | default: 136 | return AVERROR(EINVAL); 137 | } 138 | } 139 | 140 | return ret; 141 | } 142 | 143 | int QAVFilterGraph::config() 144 | { 145 | Q_D(QAVFilterGraph); 146 | return avfilter_graph_config(d->graph, nullptr); 147 | } 148 | 149 | QString QAVFilterGraph::desc() const 150 | { 151 | Q_D(const QAVFilterGraph); 152 | return d->desc; 153 | } 154 | 155 | QMutex &QAVFilterGraph::mutex() 156 | { 157 | Q_D(QAVFilterGraph); 158 | return d->mutex; 159 | } 160 | 161 | AVFilterGraph *QAVFilterGraph::graph() const 162 | { 163 | return d_func()->graph; 164 | } 165 | 166 | QList QAVFilterGraph::videoInputFilters() const 167 | { 168 | return d_func()->videoInputFilters; 169 | } 170 | 171 | QList QAVFilterGraph::videoOutputFilters() const 172 | { 173 | return d_func()->videoOutputFilters; 174 | } 175 | 176 | QList QAVFilterGraph::audioInputFilters() const 177 | { 178 | return d_func()->audioInputFilters; 179 | } 180 | 181 | QList QAVFilterGraph::audioOutputFilters() const 182 | { 183 | return d_func()->audioOutputFilters; 184 | } 185 | 186 | QT_END_NAMESPACE 187 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavfiltergraph_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFILTERGRAPH_P_H 9 | #define QAVFILTERGRAPH_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavvideoinputfilter_p.h" 23 | #include "qavvideooutputfilter_p.h" 24 | #include "qavaudioinputfilter_p.h" 25 | #include "qavaudiooutputfilter_p.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | QT_BEGIN_NAMESPACE 34 | 35 | class QAVFilterGraphPrivate; 36 | class QAVDemuxer; 37 | class QAVFilterGraph 38 | { 39 | public: 40 | QAVFilterGraph(); 41 | ~QAVFilterGraph(); 42 | 43 | int parse(const QString &desc); 44 | int apply(const QAVFrame &frame); 45 | int config(); 46 | QString desc() const; 47 | QMutex &mutex(); 48 | 49 | AVFilterGraph *graph() const; 50 | QList videoInputFilters() const; 51 | QList videoOutputFilters() const; 52 | QList audioInputFilters() const; 53 | QList audioOutputFilters() const; 54 | 55 | protected: 56 | std::unique_ptr d_ptr; 57 | Q_DECLARE_PRIVATE(QAVFilterGraph) 58 | private: 59 | Q_DISABLE_COPY(QAVFilterGraph) 60 | }; 61 | 62 | QT_END_NAMESPACE 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavfilters_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFILTERS_P_H 9 | #define QAVFILTERS_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include 23 | #include "qavframe.h" 24 | #include "qavfilter_p.h" 25 | #include "qavfiltergraph_p.h" 26 | #include 27 | #include 28 | #include 29 | 30 | QT_BEGIN_NAMESPACE 31 | 32 | class QAVFilters 33 | { 34 | public: 35 | QAVFilters() = default; 36 | int createFilters( 37 | const QList &filterDescs, 38 | const QAVFrame &frame, 39 | const QAVStream &videoStream, 40 | const QAVStream &audioStream); 41 | int write( 42 | AVMediaType mediaType, 43 | const QAVFrame &decodedFrame); 44 | int read( 45 | AVMediaType mediaType, 46 | const QAVFrame &decodedFrame, 47 | QList &filteredFrames); 48 | QList filterDescs() const; 49 | bool isEmpty() const; 50 | void flush(); 51 | void clear(); 52 | 53 | private: 54 | Q_DISABLE_COPY(QAVFilters) 55 | 56 | QList m_filterDescs; 57 | std::vector> m_filterGraphs; 58 | std::vector> m_videoFilters; 59 | std::vector> m_audioFilters; 60 | mutable QMutex m_mutex; 61 | }; 62 | 63 | QT_END_NAMESPACE 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavframe.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavframe.h" 9 | #include "qavstream.h" 10 | #include "qavframe_p.h" 11 | #include 12 | 13 | extern "C" { 14 | #include 15 | } 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | QAVFrame::QAVFrame() 20 | : QAVFrame(*new QAVFramePrivate) 21 | { 22 | } 23 | 24 | QAVFrame::QAVFrame(const QAVFrame &other) 25 | : QAVFrame() 26 | { 27 | *this = other; 28 | } 29 | 30 | QAVFrame::QAVFrame(QAVFramePrivate &d) 31 | : QAVStreamFrame(d) 32 | { 33 | d.frame = av_frame_alloc(); 34 | } 35 | 36 | QAVFrame &QAVFrame::operator=(const QAVFrame &other) 37 | { 38 | Q_D(QAVFrame); 39 | QAVStreamFrame::operator=(other); 40 | 41 | auto other_priv = static_cast(other.d_ptr.get()); 42 | int64_t pts = d->frame->pts; 43 | av_frame_unref(d->frame); 44 | av_frame_ref(d->frame, other_priv->frame); 45 | 46 | if (d->frame->pts < 0) 47 | d->frame->pts = pts; 48 | 49 | d->frameRate = other_priv->frameRate; 50 | d->timeBase = other_priv->timeBase; 51 | d->filterName = other_priv->filterName; 52 | return *this; 53 | } 54 | 55 | QAVFrame::operator bool() const 56 | { 57 | Q_D(const QAVFrame); 58 | return QAVStreamFrame::operator bool() && d->frame && (d->frame->data[0] || d->frame->data[1] || d->frame->data[2] || d->frame->data[3]); 59 | } 60 | 61 | QAVFrame::~QAVFrame() 62 | { 63 | Q_D(QAVFrame); 64 | av_frame_free(&d->frame); 65 | } 66 | 67 | AVFrame *QAVFrame::frame() const 68 | { 69 | Q_D(const QAVFrame); 70 | return d->frame; 71 | } 72 | 73 | void QAVFrame::setFrameRate(const AVRational &value) 74 | { 75 | Q_D(QAVFrame); 76 | d->frameRate = value; 77 | } 78 | 79 | void QAVFrame::setTimeBase(const AVRational &value) 80 | { 81 | Q_D(QAVFrame); 82 | d->timeBase = value; 83 | } 84 | 85 | QString QAVFrame::filterName() const 86 | { 87 | return d_func()->filterName; 88 | } 89 | 90 | void QAVFrame::setFilterName(const QString &name) 91 | { 92 | Q_D(QAVFrame); 93 | d->filterName = name; 94 | } 95 | 96 | double QAVFramePrivate::pts() const 97 | { 98 | if (!frame || !stream) 99 | return NAN; 100 | 101 | AVRational tb = timeBase.num && timeBase.den ? timeBase : stream.stream()->time_base; 102 | return frame->pts == AV_NOPTS_VALUE ? NAN : frame->pts * av_q2d(tb); 103 | } 104 | 105 | double QAVFramePrivate::duration() const 106 | { 107 | if (!frame || !stream) 108 | return 0.0; 109 | 110 | return frameRate.den && frameRate.num 111 | ? av_q2d(AVRational{frameRate.den, frameRate.num}) 112 | : 113 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 30, 0) 114 | frame->pkt_duration 115 | #else 116 | frame->duration 117 | #endif 118 | * av_q2d(stream.stream()->time_base); 119 | } 120 | 121 | QT_END_NAMESPACE 122 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavframe.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFRAME_H 9 | #define QAVFRAME_H 10 | 11 | #include 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | 16 | struct AVFrame; 17 | struct AVRational; 18 | class QAVFramePrivate; 19 | class QAVFrame : public QAVStreamFrame 20 | { 21 | public: 22 | QAVFrame(); 23 | ~QAVFrame(); 24 | QAVFrame(const QAVFrame &other); 25 | QAVFrame &operator=(const QAVFrame &other); 26 | operator bool() const; 27 | AVFrame *frame() const; 28 | 29 | void setFrameRate(const AVRational &value); 30 | void setTimeBase(const AVRational &value); 31 | QString filterName() const; 32 | void setFilterName(const QString &name); 33 | 34 | protected: 35 | QAVFrame(QAVFramePrivate &d); 36 | Q_DECLARE_PRIVATE(QAVFrame) 37 | }; 38 | 39 | QT_END_NAMESPACE 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavframe_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFRAME_P_H 9 | #define QAVFRAME_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavstreamframe_p.h" 23 | 24 | extern "C" { 25 | #include 26 | } 27 | 28 | QT_BEGIN_NAMESPACE 29 | 30 | struct AVFrame; 31 | class QAVFramePrivate : public QAVStreamFramePrivate 32 | { 33 | public: 34 | 35 | double pts() const override; 36 | double duration() const override; 37 | 38 | AVFrame *frame = nullptr; 39 | // Overridden data from filters if any 40 | AVRational frameRate{}; 41 | AVRational timeBase{}; 42 | // Name of a filter the frame has retrieved from 43 | QString filterName; 44 | }; 45 | 46 | QT_END_NAMESPACE 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavframecodec.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #include "qavframecodec_p.h" 9 | #include "qavcodec_p_p.h" 10 | 11 | #include 12 | 13 | extern "C" { 14 | #include 15 | #include 16 | } 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | QAVFrameCodec::QAVFrameCodec() 21 | { 22 | } 23 | 24 | QAVFrameCodec::QAVFrameCodec(QAVCodecPrivate &d, const AVCodec *codec) 25 | : QAVCodec(d, codec) 26 | { 27 | } 28 | 29 | int QAVFrameCodec::write(const QAVPacket &pkt) 30 | { 31 | Q_D(QAVCodec); 32 | if (!d->avctx) 33 | return AVERROR(EINVAL); 34 | return avcodec_send_packet(d->avctx, pkt ? pkt.packet() : nullptr); 35 | } 36 | 37 | int QAVFrameCodec::write(const QAVStreamFrame &frame) 38 | { 39 | Q_D(QAVCodec); 40 | if (!d->avctx) 41 | return AVERROR(EINVAL); 42 | auto &f = static_cast(frame); 43 | return avcodec_send_frame(d->avctx, f ? f.frame() : nullptr); 44 | } 45 | 46 | int QAVFrameCodec::read(QAVStreamFrame &frame) 47 | { 48 | Q_D(QAVCodec); 49 | if (!d->avctx) 50 | return AVERROR(EINVAL); 51 | auto f = static_cast(&frame); 52 | return avcodec_receive_frame(d->avctx, f->frame()); 53 | } 54 | 55 | int QAVFrameCodec::read(QAVPacket &pkt) 56 | { 57 | Q_D(QAVCodec); 58 | if (!d->avctx) 59 | return AVERROR(EINVAL); 60 | return avcodec_receive_packet(d->avctx, pkt.packet()); 61 | } 62 | 63 | QT_END_NAMESPACE 64 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavframecodec_p.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVFRAMECODEC_P_H 9 | #define QAVFRAMECODEC_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavframe.h" 23 | #include "qavcodec_p.h" 24 | #include "qavpacket.h" 25 | 26 | QT_BEGIN_NAMESPACE 27 | 28 | class QAVFrameCodec : public QAVCodec 29 | { 30 | public: 31 | int write(const QAVPacket &pkt) override; 32 | int write(const QAVStreamFrame &frame) override; 33 | int read(QAVStreamFrame &frame) override; 34 | int read(QAVPacket &pkt) override; 35 | 36 | protected: 37 | using QAVCodec::QAVCodec; 38 | QAVFrameCodec(); 39 | QAVFrameCodec(QAVCodecPrivate &d, const AVCodec *codec = nullptr); 40 | }; 41 | 42 | QT_END_NAMESPACE 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_d3d11_p.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVHWDEVICE_D3D11_P_H 9 | #define QAVHWDEVICE_D3D11_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavhwdevice_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | struct AVCodecContext; 27 | class QAVHWDevice_D3D11 : public QAVHWDevice 28 | { 29 | public: 30 | QAVHWDevice_D3D11() = default; 31 | ~QAVHWDevice_D3D11() = default; 32 | 33 | void init(AVCodecContext *avctx) override; 34 | AVPixelFormat format() const override; 35 | AVHWDeviceType type() const override; 36 | QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const override; 37 | 38 | private: 39 | Q_DISABLE_COPY(QAVHWDevice_D3D11) 40 | }; 41 | 42 | class QAVHWDevice_D3D11_GL : public QAVHWDevice 43 | { 44 | public: 45 | QAVHWDevice_D3D11_GL() = default; 46 | ~QAVHWDevice_D3D11_GL() = default; 47 | 48 | AVPixelFormat format() const override; 49 | AVHWDeviceType type() const override; 50 | QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const override; 51 | 52 | private: 53 | Q_DISABLE_COPY(QAVHWDevice_D3D11_GL) 54 | }; 55 | 56 | QT_END_NAMESPACE 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_mediacodec.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavhwdevice_mediacodec_p.h" 9 | #include "qavvideobuffer_gpu_p.h" 10 | #include "qavcodec_p.h" 11 | #include "qavandroidsurfacetexture_p.h" 12 | #include 13 | 14 | extern "C" { 15 | #include 16 | #include 17 | #include 18 | } 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | class QAVHWDevice_MediaCodecPrivate 23 | { 24 | public: 25 | QAVHWDevice_MediaCodecPrivate() 26 | { 27 | androidSurfaceTexture = std::make_unique(); 28 | } 29 | 30 | GLuint texture = 0; 31 | std::unique_ptr androidSurfaceTexture; 32 | }; 33 | 34 | QAVHWDevice_MediaCodec::QAVHWDevice_MediaCodec() 35 | : d_ptr(new QAVHWDevice_MediaCodecPrivate) 36 | { 37 | } 38 | 39 | QAVHWDevice_MediaCodec::~QAVHWDevice_MediaCodec() 40 | { 41 | Q_D(QAVHWDevice_MediaCodec); 42 | if (d->texture) 43 | glDeleteTextures(1, &d->texture); 44 | } 45 | 46 | void QAVHWDevice_MediaCodec::init(AVCodecContext *avctx) 47 | { 48 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 49 | AVBufferRef *hw_device_ctx = avctx->hw_device_ctx; 50 | if (hw_device_ctx) { 51 | AVHWDeviceContext *deviceContext = reinterpret_cast(hw_device_ctx->data); 52 | if (deviceContext->hwctx) { 53 | AVMediaCodecDeviceContext *mediaDeviceContext = 54 | reinterpret_cast(deviceContext->hwctx); 55 | if (mediaDeviceContext) 56 | mediaDeviceContext->surface = d_ptr->androidSurfaceTexture->surface(); 57 | } 58 | } 59 | #else 60 | Q_UNUSED(avctx); 61 | #endif 62 | } 63 | 64 | AVPixelFormat QAVHWDevice_MediaCodec::format() const 65 | { 66 | return AV_PIX_FMT_MEDIACODEC; 67 | } 68 | 69 | AVHWDeviceType QAVHWDevice_MediaCodec::type() const 70 | { 71 | return AV_HWDEVICE_TYPE_MEDIACODEC; 72 | } 73 | 74 | class VideoBuffer_MediaCodec : public QAVVideoBuffer_GPU 75 | { 76 | public: 77 | VideoBuffer_MediaCodec(QAVHWDevice_MediaCodecPrivate *hw, const QAVVideoFrame &frame) 78 | : QAVVideoBuffer_GPU(frame) 79 | , m_hw(hw) 80 | { 81 | } 82 | 83 | QAVVideoFrame::HandleType handleType() const override 84 | { 85 | return QAVVideoFrame::GLTextureHandle; 86 | } 87 | 88 | QVariant handle(QRhi */*rhi*/) const override 89 | { 90 | if (!m_hw->androidSurfaceTexture->isValid()) 91 | return {}; 92 | 93 | if (!m_hw->texture) { 94 | m_hw->androidSurfaceTexture->detachFromGLContext(); 95 | glGenTextures(1, &m_hw->texture); 96 | m_hw->androidSurfaceTexture->attachToGLContext(m_hw->texture); 97 | } 98 | 99 | AVMediaCodecBuffer *buffer = reinterpret_cast(frame().frame()->data[3]); 100 | if (!buffer) { 101 | qWarning() << "Received a frame without AVMediaCodecBuffer."; 102 | } else if (av_mediacodec_release_buffer(buffer, 1) < 0) { 103 | qWarning() << "Failed to render buffer to surface."; 104 | return {}; 105 | } 106 | 107 | m_hw->androidSurfaceTexture->updateTexImage(); 108 | return m_hw->texture; 109 | } 110 | 111 | QAVHWDevice_MediaCodecPrivate *m_hw = nullptr; 112 | }; 113 | 114 | QAVVideoBuffer *QAVHWDevice_MediaCodec::videoBuffer(const QAVVideoFrame &frame) const 115 | { 116 | return new VideoBuffer_MediaCodec(d_ptr.get(), frame); 117 | } 118 | 119 | QT_END_NAMESPACE 120 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_mediacodec_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVHWDEVICE_MEDIACODEC_P_H 9 | #define QAVHWDEVICE_MEDIACODEC_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavhwdevice_p.h" 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVHWDevice_MediaCodecPrivate; 28 | class QAVHWDevice_MediaCodec : public QAVHWDevice 29 | { 30 | public: 31 | QAVHWDevice_MediaCodec(); 32 | ~QAVHWDevice_MediaCodec(); 33 | 34 | void init(AVCodecContext *avctx) override; 35 | AVPixelFormat format() const override; 36 | AVHWDeviceType type() const override; 37 | QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const override; 38 | 39 | private: 40 | std::unique_ptr d_ptr; 41 | Q_DISABLE_COPY(QAVHWDevice_MediaCodec) 42 | Q_DECLARE_PRIVATE(QAVHWDevice_MediaCodec) 43 | }; 44 | 45 | QT_END_NAMESPACE 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVHWDEVICE_P_H 9 | #define QAVHWDEVICE_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavvideoframe.h" 23 | #include "qtavplayerglobal.h" 24 | 25 | extern "C" { 26 | #include 27 | #include 28 | } 29 | 30 | QT_BEGIN_NAMESPACE 31 | 32 | struct AVCodecContext; 33 | class QAVVideoBuffer; 34 | class QAVHWDevice 35 | { 36 | public: 37 | QAVHWDevice() = default; 38 | virtual ~QAVHWDevice() = default; 39 | 40 | virtual void init(AVCodecContext *) { } 41 | virtual AVPixelFormat format() const = 0; 42 | virtual AVHWDeviceType type() const = 0; 43 | virtual QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const = 0; 44 | 45 | private: 46 | Q_DISABLE_COPY(QAVHWDevice) 47 | }; 48 | 49 | QT_END_NAMESPACE 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_vaapi_drm_egl.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavhwdevice_vaapi_drm_egl_p.h" 9 | #include "qavvideocodec_p.h" 10 | #include "qavvideobuffer_gpu_p.h" 11 | #include "qavstream.h" 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | extern "C" { 22 | #include 23 | #include 24 | } 25 | 26 | static PFNEGLCREATEIMAGEKHRPROC s_eglCreateImageKHR = nullptr; 27 | static PFNEGLDESTROYIMAGEKHRPROC s_eglDestroyImageKHR = nullptr; 28 | static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC s_glEGLImageTargetTexture2DOES = nullptr; 29 | 30 | QT_BEGIN_NAMESPACE 31 | 32 | class QAVHWDevice_VAAPI_DRM_EGLPrivate 33 | { 34 | public: 35 | GLuint textures[2] = {0}; 36 | }; 37 | 38 | QAVHWDevice_VAAPI_DRM_EGL::QAVHWDevice_VAAPI_DRM_EGL() 39 | : d_ptr(new QAVHWDevice_VAAPI_DRM_EGLPrivate) 40 | { 41 | } 42 | 43 | QAVHWDevice_VAAPI_DRM_EGL::~QAVHWDevice_VAAPI_DRM_EGL() 44 | { 45 | Q_D(QAVHWDevice_VAAPI_DRM_EGL); 46 | 47 | if (d->textures[0]) 48 | glDeleteTextures(2, &d->textures[0]); 49 | } 50 | 51 | AVPixelFormat QAVHWDevice_VAAPI_DRM_EGL::format() const 52 | { 53 | return AV_PIX_FMT_VAAPI; 54 | } 55 | 56 | AVHWDeviceType QAVHWDevice_VAAPI_DRM_EGL::type() const 57 | { 58 | return AV_HWDEVICE_TYPE_VAAPI; 59 | } 60 | 61 | class VideoBuffer_EGL : public QAVVideoBuffer_GPU 62 | { 63 | public: 64 | VideoBuffer_EGL(QAVHWDevice_VAAPI_DRM_EGLPrivate *hw, const QAVVideoFrame &frame) 65 | : QAVVideoBuffer_GPU(frame) 66 | , m_hw(hw) 67 | { 68 | if (!s_eglCreateImageKHR) { 69 | s_eglCreateImageKHR = reinterpret_cast(eglGetProcAddress("eglCreateImageKHR")); 70 | s_eglDestroyImageKHR = reinterpret_cast(eglGetProcAddress("eglDestroyImageKHR")); 71 | s_glEGLImageTargetTexture2DOES = reinterpret_cast(eglGetProcAddress("glEGLImageTargetTexture2DOES")); 72 | } 73 | } 74 | 75 | QAVVideoFrame::HandleType handleType() const override 76 | { 77 | return QAVVideoFrame::GLTextureHandle; 78 | } 79 | 80 | QVariant textures() const 81 | { 82 | return QList() << m_hw->textures[0] << m_hw->textures[1]; 83 | } 84 | 85 | QVariant handle(QRhi */*rhi*/) const override 86 | { 87 | if (!m_hw->textures[0]) 88 | glGenTextures(2, m_hw->textures); 89 | 90 | auto va_frame = frame().frame(); 91 | AVHWDeviceContext *hwctx = (AVHWDeviceContext *)frame().stream().codec()->avctx()->hw_device_ctx->data; 92 | AVVAAPIDeviceContext *vactx = (AVVAAPIDeviceContext *)hwctx->hwctx; 93 | VADisplay va_display = vactx->display; 94 | VASurfaceID va_surface = (VASurfaceID)(uintptr_t)va_frame->data[3]; 95 | 96 | VADRMPRIMESurfaceDescriptor prime; 97 | auto status = vaExportSurfaceHandle(va_display, va_surface, 98 | VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, 99 | VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS, 100 | &prime); 101 | if (status != VA_STATUS_SUCCESS) { 102 | qWarning() << "vaExportSurfaceHandle failed" << status; 103 | return textures(); 104 | } 105 | 106 | if (prime.fourcc != VA_FOURCC_NV12) { 107 | qWarning() << "prime.fourcc != VA_FOURCC_NV12"; 108 | return textures(); 109 | } 110 | 111 | vaSyncSurface(va_display, va_surface); 112 | 113 | static const uint32_t formats[2] = { DRM_FORMAT_R8, DRM_FORMAT_GR88 }; 114 | for (int i = 0; i < 2; ++i) { 115 | if (prime.layers[i].drm_format != formats[i]) 116 | qWarning() << "Wrong DRM format:" << prime.layers[i].drm_format << formats[i]; 117 | 118 | EGLint img_attr[] = { 119 | EGL_LINUX_DRM_FOURCC_EXT, EGLint(formats[i]), 120 | EGL_WIDTH, va_frame->width / (i + 1), 121 | EGL_HEIGHT, va_frame->height / (i + 1), 122 | EGL_DMA_BUF_PLANE0_FD_EXT, prime.objects[prime.layers[i].object_index[0]].fd, 123 | EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(prime.layers[i].offset[0]), 124 | EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(prime.layers[i].pitch[0]), 125 | EGL_NONE 126 | }; 127 | 128 | EGLImage img = s_eglCreateImageKHR(eglGetCurrentDisplay(), 129 | EGL_NO_CONTEXT, 130 | EGL_LINUX_DMA_BUF_EXT, 131 | NULL, img_attr); 132 | if (!img) { 133 | qWarning() << "eglCreateImageKHR failed"; 134 | return textures(); 135 | } 136 | 137 | glActiveTexture(GL_TEXTURE0 + i); 138 | glBindTexture(GL_TEXTURE_2D, m_hw->textures[i]); 139 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 140 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 141 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 142 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 143 | 144 | s_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img); 145 | if (glGetError()) 146 | qWarning() << "glEGLImageTargetTexture2DOES failed"; 147 | 148 | glBindTexture(GL_TEXTURE_2D, 0); 149 | s_eglDestroyImageKHR(eglGetCurrentDisplay(), img); 150 | } 151 | 152 | return textures(); 153 | } 154 | 155 | QAVHWDevice_VAAPI_DRM_EGLPrivate *m_hw = nullptr; 156 | }; 157 | 158 | QAVVideoBuffer *QAVHWDevice_VAAPI_DRM_EGL::videoBuffer(const QAVVideoFrame &frame) const 159 | { 160 | return new VideoBuffer_EGL(d_ptr.get(), frame); 161 | } 162 | 163 | QT_END_NAMESPACE 164 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_vaapi_drm_egl_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVHWDEVICE_VAAPI_DRM_EGL_P_H 9 | #define QAVHWDEVICE_VAAPI_DRM_EGL_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavhwdevice_p.h" 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVHWDevice_VAAPI_DRM_EGLPrivate; 28 | class QAVHWDevice_VAAPI_DRM_EGL : public QAVHWDevice 29 | { 30 | public: 31 | QAVHWDevice_VAAPI_DRM_EGL(); 32 | ~QAVHWDevice_VAAPI_DRM_EGL(); 33 | 34 | AVPixelFormat format() const override; 35 | AVHWDeviceType type() const override; 36 | QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const override; 37 | 38 | private: 39 | std::unique_ptr d_ptr; 40 | Q_DISABLE_COPY(QAVHWDevice_VAAPI_DRM_EGL) 41 | Q_DECLARE_PRIVATE(QAVHWDevice_VAAPI_DRM_EGL) 42 | }; 43 | 44 | QT_END_NAMESPACE 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_vaapi_x11_glx.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavhwdevice_vaapi_x11_glx_p.h" 9 | #include "qavvideocodec_p.h" 10 | #include "qavstream.h" 11 | #include "qavvideobuffer_gpu_p.h" 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | extern "C" { 18 | #include 19 | #include 20 | } 21 | 22 | typedef void (*glXBindTexImageEXT_)(Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); 23 | typedef void (*glXReleaseTexImageEXT_)(Display *dpy, GLXDrawable draw, int buffer); 24 | static glXBindTexImageEXT_ s_glXBindTexImageEXT = nullptr; 25 | static glXReleaseTexImageEXT_ s_glXReleaseTexImageEXT = nullptr; 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QAVHWDevice_VAAPI_X11_GLXPrivate 30 | { 31 | public: 32 | Pixmap pixmap = 0; 33 | GLXPixmap glxpixmap = 0; 34 | Display *display = nullptr; 35 | GLuint texture = 0; 36 | }; 37 | 38 | QAVHWDevice_VAAPI_X11_GLX::QAVHWDevice_VAAPI_X11_GLX() 39 | : d_ptr(new QAVHWDevice_VAAPI_X11_GLXPrivate) 40 | { 41 | } 42 | 43 | QAVHWDevice_VAAPI_X11_GLX::~QAVHWDevice_VAAPI_X11_GLX() 44 | { 45 | Q_D(QAVHWDevice_VAAPI_X11_GLX); 46 | 47 | if (d->glxpixmap) { 48 | s_glXReleaseTexImageEXT(d->display, d->glxpixmap, GLX_FRONT_EXT); 49 | glXDestroyPixmap(d->display, d->glxpixmap); 50 | } 51 | if (d->pixmap) 52 | XFreePixmap(d->display, d->pixmap); 53 | 54 | if (d->texture) 55 | glDeleteTextures(1, &d->texture); 56 | } 57 | 58 | AVPixelFormat QAVHWDevice_VAAPI_X11_GLX::format() const 59 | { 60 | return AV_PIX_FMT_VAAPI; 61 | } 62 | 63 | AVHWDeviceType QAVHWDevice_VAAPI_X11_GLX::type() const 64 | { 65 | return AV_HWDEVICE_TYPE_VAAPI; 66 | } 67 | 68 | class VideoBuffer_GLX : public QAVVideoBuffer_GPU 69 | { 70 | public: 71 | VideoBuffer_GLX(QAVHWDevice_VAAPI_X11_GLXPrivate *hw, const QAVVideoFrame &frame) 72 | : QAVVideoBuffer_GPU(frame) 73 | , m_hw(hw) 74 | { 75 | if (!s_glXBindTexImageEXT) { 76 | s_glXBindTexImageEXT = (glXBindTexImageEXT_) glXGetProcAddressARB((const GLubyte *)"glXBindTexImageEXT"); 77 | s_glXReleaseTexImageEXT = (glXReleaseTexImageEXT_) glXGetProcAddressARB((const GLubyte *)"glXReleaseTexImageEXT"); 78 | } 79 | } 80 | 81 | QAVVideoFrame::HandleType handleType() const override 82 | { 83 | return QAVVideoFrame::GLTextureHandle; 84 | } 85 | 86 | QVariant handle(QRhi */*rhi*/) const override 87 | { 88 | if (!s_glXBindTexImageEXT) { 89 | qWarning() << "Could not get proc address: s_glXBindTexImageEXT"; 90 | return 0; 91 | } 92 | 93 | auto av_frame = frame().frame(); 94 | AVHWDeviceContext *hwctx = (AVHWDeviceContext *)frame().stream().codec()->avctx()->hw_device_ctx->data; 95 | AVVAAPIDeviceContext *vactx = (AVVAAPIDeviceContext *)hwctx->hwctx; 96 | VADisplay va_display = vactx->display; 97 | VASurfaceID va_surface = (VASurfaceID)(uintptr_t)av_frame->data[3]; 98 | 99 | int w = av_frame->width; 100 | int h = av_frame->height; 101 | 102 | if (!m_hw->display) { 103 | glGenTextures(1, &m_hw->texture); 104 | auto display = (Display *)glXGetCurrentDisplay(); 105 | m_hw->display = display; 106 | int xscr = DefaultScreen(display); 107 | const char *glxext = glXQueryExtensionsString(display, xscr); 108 | if (!glxext || !strstr(glxext, "GLX_EXT_texture_from_pixmap")) { 109 | qWarning() << "GLX_EXT_texture_from_pixmap is not supported"; 110 | return 0; 111 | } 112 | 113 | int attribs[] = { 114 | GLX_RENDER_TYPE, GLX_RGBA_BIT, 115 | GLX_X_RENDERABLE, True, 116 | GLX_BIND_TO_TEXTURE_RGBA_EXT, True, 117 | GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, 118 | GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, 119 | GLX_Y_INVERTED_EXT, True, 120 | GLX_DOUBLEBUFFER, False, 121 | GLX_RED_SIZE, 8, 122 | GLX_GREEN_SIZE, 8, 123 | GLX_BLUE_SIZE, 8, 124 | GLX_ALPHA_SIZE, 8, 125 | None 126 | }; 127 | 128 | int fbcount; 129 | GLXFBConfig *fbcs = glXChooseFBConfig(display, xscr, attribs, &fbcount); 130 | if (!fbcount) { 131 | XFree(fbcs); 132 | qWarning() << "No texture-from-pixmap support"; 133 | return 0; 134 | } 135 | 136 | GLXFBConfig fbc = fbcs[0]; 137 | XFree(fbcs); 138 | 139 | XWindowAttributes xwa; 140 | XGetWindowAttributes(display, DefaultRootWindow(display), &xwa); 141 | 142 | m_hw->pixmap = XCreatePixmap(display, DefaultRootWindow(display), w, h, xwa.depth); 143 | 144 | const int attribs_pixmap[] = { 145 | GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, 146 | GLX_TEXTURE_FORMAT_EXT, xwa.depth == 32 ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT, 147 | GLX_MIPMAP_TEXTURE_EXT, False, 148 | None, 149 | }; 150 | 151 | m_hw->glxpixmap = glXCreatePixmap(display, fbc, m_hw->pixmap, attribs_pixmap); 152 | } 153 | 154 | vaSyncSurface(va_display, va_surface); 155 | auto status = vaPutSurface(va_display, va_surface, m_hw->pixmap, 156 | 0, 0, w, h, 157 | 0, 0, w, h, 158 | NULL, 0, VA_FRAME_PICTURE | VA_SRC_BT709); 159 | if (status != VA_STATUS_SUCCESS) { 160 | qWarning() << "vaPutSurface failed" << status; 161 | return 0; 162 | } 163 | 164 | XSync(m_hw->display, False); 165 | glBindTexture(GL_TEXTURE_2D, m_hw->texture); 166 | s_glXBindTexImageEXT(m_hw->display, m_hw->glxpixmap, GLX_FRONT_EXT, NULL); 167 | glBindTexture(GL_TEXTURE_2D, 0); 168 | 169 | return m_hw->texture; 170 | } 171 | 172 | QAVHWDevice_VAAPI_X11_GLXPrivate *m_hw = nullptr; 173 | }; 174 | 175 | QAVVideoBuffer *QAVHWDevice_VAAPI_X11_GLX::videoBuffer(const QAVVideoFrame &frame) const 176 | { 177 | return new VideoBuffer_GLX(d_ptr.get(), frame); 178 | } 179 | 180 | QT_END_NAMESPACE 181 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_vaapi_x11_glx_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVHWDEVICE_VAAPI_X11_GLX_P_H 9 | #define QAVHWDEVICE_VAAPI_X11_GLX_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavhwdevice_p.h" 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVHWDevice_VAAPI_X11_GLXPrivate; 28 | class QAVHWDevice_VAAPI_X11_GLX : public QAVHWDevice 29 | { 30 | public: 31 | QAVHWDevice_VAAPI_X11_GLX(); 32 | ~QAVHWDevice_VAAPI_X11_GLX(); 33 | 34 | AVPixelFormat format() const override; 35 | AVHWDeviceType type() const override; 36 | QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const override; 37 | 38 | private: 39 | std::unique_ptr d_ptr; 40 | Q_DISABLE_COPY(QAVHWDevice_VAAPI_X11_GLX) 41 | Q_DECLARE_PRIVATE(QAVHWDevice_VAAPI_X11_GLX) 42 | }; 43 | 44 | QT_END_NAMESPACE 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_vdpau_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVHWDEVICE_VDPAU_P_H 9 | #define QAVHWDEVICE_VDPAU_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavhwdevice_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVHWDevice_VDPAU : public QAVHWDevice 27 | { 28 | public: 29 | QAVHWDevice_VDPAU(); 30 | ~QAVHWDevice_VDPAU(); 31 | 32 | AVPixelFormat format() const override; 33 | AVHWDeviceType type() const override; 34 | QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const override; 35 | 36 | private: 37 | Q_DISABLE_COPY(QAVHWDevice_VDPAU) 38 | }; 39 | 40 | QT_END_NAMESPACE 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_videotoolbox.mm: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavhwdevice_videotoolbox_p.h" 9 | #include "qavvideobuffer_gpu_p.h" 10 | 11 | #import 12 | #if defined(Q_OS_MACOS) 13 | #import 14 | #else 15 | #import 16 | #endif 17 | #import 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | class QAVHWDevice_VideoToolboxPrivate 26 | { 27 | public: 28 | id device = nullptr; 29 | CVPixelBufferRef pbuf = nullptr; 30 | }; 31 | 32 | QAVHWDevice_VideoToolbox::QAVHWDevice_VideoToolbox() 33 | : d_ptr(new QAVHWDevice_VideoToolboxPrivate) 34 | { 35 | } 36 | 37 | QAVHWDevice_VideoToolbox::~QAVHWDevice_VideoToolbox() 38 | { 39 | Q_D(QAVHWDevice_VideoToolbox); 40 | CVPixelBufferRelease(d->pbuf); 41 | [d->device release]; 42 | } 43 | 44 | AVPixelFormat QAVHWDevice_VideoToolbox::format() const 45 | { 46 | return AV_PIX_FMT_VIDEOTOOLBOX; 47 | } 48 | 49 | AVHWDeviceType QAVHWDevice_VideoToolbox::type() const 50 | { 51 | return AV_HWDEVICE_TYPE_VIDEOTOOLBOX; 52 | } 53 | 54 | class VideoBuffer_MTL : public QAVVideoBuffer_GPU 55 | { 56 | public: 57 | VideoBuffer_MTL(QAVHWDevice_VideoToolboxPrivate *hw, const QAVVideoFrame &frame) 58 | : QAVVideoBuffer_GPU(frame) 59 | , m_hw(hw) 60 | { 61 | } 62 | 63 | QAVVideoFrame::HandleType handleType() const override 64 | { 65 | return QAVVideoFrame::MTLTextureHandle; 66 | } 67 | 68 | QVariant handle(QRhi */*rhi*/) const override 69 | { 70 | CVPixelBufferRelease(m_hw->pbuf); 71 | m_hw->pbuf = (CVPixelBufferRef)frame().frame()->data[3]; 72 | CVPixelBufferRetain(m_hw->pbuf); 73 | QList textures = { 0, 0 }; 74 | 75 | if (!m_hw->pbuf) 76 | return textures; 77 | 78 | if (CVPixelBufferGetDataSize(m_hw->pbuf) <= 0) 79 | return textures; 80 | 81 | auto format = CVPixelBufferGetPixelFormatType(m_hw->pbuf); 82 | if (format != '420v') { 83 | qWarning() << "420v is supported only"; 84 | return textures; 85 | } 86 | 87 | if (!m_hw->device) 88 | m_hw->device = MTLCreateSystemDefaultDevice(); 89 | 90 | IOSurfaceRef surface = CVPixelBufferGetIOSurface(m_hw->pbuf); 91 | int planes = CVPixelBufferGetPlaneCount(m_hw->pbuf); 92 | for (int i = 0; i < planes; ++i) { 93 | int w = IOSurfaceGetWidthOfPlane(surface, i); 94 | int h = IOSurfaceGetHeightOfPlane(surface, i) ; 95 | MTLPixelFormat f = i ? MTLPixelFormatRG8Unorm : MTLPixelFormatR8Unorm; 96 | MTLTextureDescriptor *desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:f width:w height:h mipmapped:NO]; 97 | 98 | textures[i] = quint64([m_hw->device newTextureWithDescriptor:desc iosurface:surface plane:i]); 99 | } 100 | 101 | return textures; 102 | } 103 | 104 | QAVHWDevice_VideoToolboxPrivate *m_hw = nullptr; 105 | }; 106 | 107 | QAVVideoBuffer *QAVHWDevice_VideoToolbox::videoBuffer(const QAVVideoFrame &frame) const 108 | { 109 | return new VideoBuffer_MTL(d_ptr.get(), frame); 110 | } 111 | 112 | QT_END_NAMESPACE 113 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavhwdevice_videotoolbox_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVHWDEVICE_VIDEOTOOLBOX_P_H 9 | #define QAVHWDEVICE_VIDEOTOOLBOX_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavhwdevice_p.h" 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVHWDevice_VideoToolboxPrivate; 28 | class QAVHWDevice_VideoToolbox : public QAVHWDevice 29 | { 30 | public: 31 | QAVHWDevice_VideoToolbox(); 32 | ~QAVHWDevice_VideoToolbox(); 33 | 34 | AVPixelFormat format() const override; 35 | AVHWDeviceType type() const override; 36 | QAVVideoBuffer *videoBuffer(const QAVVideoFrame &frame) const override; 37 | 38 | private: 39 | std::unique_ptr d_ptr; 40 | Q_DISABLE_COPY(QAVHWDevice_VideoToolbox) 41 | Q_DECLARE_PRIVATE(QAVHWDevice_VideoToolbox) 42 | }; 43 | 44 | QT_END_NAMESPACE 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavinoutfilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavinoutfilter_p.h" 9 | #include "qavinoutfilter_p_p.h" 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | #include 15 | } 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | QAVInOutFilter::QAVInOutFilter() 20 | : QAVInOutFilter(*new QAVInOutFilterPrivate(this)) 21 | { 22 | } 23 | 24 | QAVInOutFilter::QAVInOutFilter(QAVInOutFilterPrivate &d) 25 | : d_ptr(&d) 26 | { 27 | } 28 | 29 | QAVInOutFilter::~QAVInOutFilter() = default; 30 | 31 | QAVInOutFilter::QAVInOutFilter(const QAVInOutFilter &other) 32 | : QAVInOutFilter() 33 | { 34 | *this = other; 35 | } 36 | 37 | QAVInOutFilter &QAVInOutFilter::operator=(const QAVInOutFilter &other) 38 | { 39 | d_ptr->ctx = other.d_ptr->ctx; 40 | d_ptr->name = other.d_ptr->name; 41 | return *this; 42 | } 43 | 44 | int QAVInOutFilter::configure(AVFilterGraph *graph, AVFilterInOut *in) 45 | { 46 | Q_D(QAVInOutFilter); 47 | Q_UNUSED(graph); 48 | if (in->name) 49 | d->name = QString::fromUtf8(in->name); 50 | return 0; 51 | } 52 | 53 | AVFilterContext *QAVInOutFilter::ctx() const 54 | { 55 | Q_D(const QAVInOutFilter); 56 | return d->ctx; 57 | } 58 | 59 | QString QAVInOutFilter::name() const 60 | { 61 | return d_func()->name; 62 | } 63 | 64 | QT_END_NAMESPACE 65 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavinoutfilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVINOUTFILTER_P_H 9 | #define QAVINOUTFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | struct AVFilterGraph; 28 | struct AVFilterInOut; 29 | struct AVFilterContext; 30 | class QAVInOutFilterPrivate; 31 | class QAVInOutFilter 32 | { 33 | public: 34 | QAVInOutFilter(); 35 | virtual ~QAVInOutFilter(); 36 | QAVInOutFilter(const QAVInOutFilter &other); 37 | QAVInOutFilter &operator=(const QAVInOutFilter &other); 38 | virtual int configure(AVFilterGraph *graph, AVFilterInOut *in); 39 | AVFilterContext *ctx() const; 40 | QString name() const; 41 | 42 | protected: 43 | std::unique_ptr d_ptr; 44 | QAVInOutFilter(QAVInOutFilterPrivate &d); 45 | Q_DECLARE_PRIVATE(QAVInOutFilter) 46 | }; 47 | 48 | QT_END_NAMESPACE 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavinoutfilter_p_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVINOUTFILTER_P_P_H 9 | #define QAVINOUTFILTER_P_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVInOutFilter; 27 | struct AVFilterContext; 28 | class QAVInOutFilterPrivate 29 | { 30 | public: 31 | QAVInOutFilterPrivate(QAVInOutFilter *q) : q_ptr(q) { } 32 | virtual ~QAVInOutFilterPrivate() = default; 33 | 34 | QAVInOutFilter *q_ptr = nullptr; 35 | AVFilterContext *ctx = nullptr; 36 | QString name; 37 | }; 38 | 39 | QT_END_NAMESPACE 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qaviodevice.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qaviodevice.h" 9 | #include 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | #include 15 | #include 16 | } 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | struct ReadRequest 21 | { 22 | ReadRequest() = default; 23 | ReadRequest(unsigned char *data, int maxSize): data(data), maxSize(maxSize) { } 24 | int wroteBytes = 0; 25 | unsigned char *data = nullptr; 26 | int maxSize = 0; 27 | }; 28 | 29 | class QAVIODevicePrivate 30 | { 31 | Q_DECLARE_PUBLIC(QAVIODevice) 32 | public: 33 | explicit QAVIODevicePrivate(QAVIODevice *q, const QSharedPointer &device) 34 | : q_ptr(q) 35 | , device(device) 36 | , buffer(static_cast(av_malloc(buffer_size))) 37 | , ctx(avio_alloc_context(buffer, static_cast(buffer_size), 0, this, &QAVIODevicePrivate::read, nullptr, !device->isSequential() ? &QAVIODevicePrivate::seek : nullptr)) 38 | { 39 | if (!device->isSequential()) 40 | ctx->seekable = AVIO_SEEKABLE_NORMAL; 41 | } 42 | 43 | ~QAVIODevicePrivate() 44 | { 45 | av_free(ctx); 46 | } 47 | 48 | void readData() 49 | { 50 | QMutexLocker locker(&mutex); 51 | // if no request or it is being processed 52 | if (readRequest.data == nullptr || readRequest.wroteBytes) 53 | return; 54 | 55 | readRequest.wroteBytes = !device->atEnd() ? device->read((char *)readRequest.data, readRequest.maxSize) : AVERROR_EOF; 56 | // Unblock the decoder thread when there is available bytes 57 | if (readRequest.wroteBytes) { 58 | waitCond.wakeAll(); 59 | wakeRead = true; 60 | } 61 | } 62 | 63 | static int read(void *opaque, unsigned char *data, int maxSize) 64 | { 65 | auto d = static_cast(opaque); 66 | QMutexLocker locker(&d->mutex); 67 | if (d->aborted) 68 | return ECANCELED; 69 | 70 | d->readRequest = { data, maxSize }; 71 | // When decoder thread is the same as current 72 | d->wakeRead = false; 73 | locker.unlock(); 74 | // Reading is done on thread where the object is created 75 | QMetaObject::invokeMethod(d->q_ptr, [d]() -> void { d->readData(); }); 76 | locker.relock(); 77 | // Blocks until data is available 78 | if (!d->wakeRead) 79 | d->waitCond.wait(&d->mutex); 80 | 81 | int bytes = d->readRequest.wroteBytes; 82 | d->readRequest = {}; 83 | return bytes; 84 | } 85 | 86 | static int64_t seek(void *opaque, int64_t offset, int whence) 87 | { 88 | auto d = static_cast(opaque); 89 | QMutexLocker locker(&d->mutex); 90 | if (d->aborted) 91 | return ECANCELED; 92 | 93 | int64_t pos = 0; 94 | bool wake = false; 95 | locker.unlock(); 96 | QMetaObject::invokeMethod(d->q_ptr, [&]() -> void { 97 | QMutexLocker locker(&d->mutex); 98 | if (whence == AVSEEK_SIZE) { 99 | pos = d->device->size() > 0 ? d->device->size() : 0; 100 | } else { 101 | if (whence == SEEK_END) 102 | offset = d->device->size() - offset; 103 | else if (whence == SEEK_CUR) 104 | offset = d->device->pos() + offset; 105 | 106 | pos = d->device->seek(offset) ? d->device->pos() : -1; 107 | } 108 | d->waitCond.wakeAll(); 109 | wake = true; 110 | }); 111 | 112 | locker.relock(); 113 | if (!wake) 114 | d->waitCond.wait(&d->mutex); 115 | 116 | return pos; 117 | } 118 | 119 | size_t buffer_size = 64 * 1024; 120 | QAVIODevice *q_ptr = nullptr; 121 | QSharedPointer device; 122 | unsigned char *buffer = nullptr; 123 | AVIOContext *ctx = nullptr; 124 | mutable QMutex mutex; 125 | QWaitCondition waitCond; 126 | bool aborted = false; 127 | bool wakeRead = false; 128 | ReadRequest readRequest; 129 | }; 130 | 131 | QAVIODevice::QAVIODevice(const QSharedPointer &device, QObject *parent) 132 | : QObject(parent) 133 | , d_ptr(new QAVIODevicePrivate(this, device)) 134 | { 135 | connect(device.get(), &QIODevice::readyRead, this, [this] { 136 | Q_D(QAVIODevice); 137 | d->readData(); 138 | }); 139 | } 140 | 141 | QAVIODevice::~QAVIODevice() 142 | { 143 | abort(true); 144 | } 145 | 146 | AVIOContext *QAVIODevice::ctx() const 147 | { 148 | return d_func()->ctx; 149 | } 150 | 151 | void QAVIODevice::abort(bool aborted) 152 | { 153 | Q_D(QAVIODevice); 154 | QMutexLocker locker(&d->mutex); 155 | d->aborted = aborted; 156 | d->waitCond.wakeAll(); 157 | } 158 | 159 | void QAVIODevice::setBufferSize(size_t size) 160 | { 161 | Q_D(QAVIODevice); 162 | QMutexLocker locker(&d->mutex); 163 | d->buffer_size = size; 164 | } 165 | 166 | size_t QAVIODevice::bufferSize() const 167 | { 168 | Q_D(const QAVIODevice); 169 | QMutexLocker locker(&d->mutex); 170 | return d->buffer_size; 171 | } 172 | 173 | QT_END_NAMESPACE 174 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qaviodevice.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFIODEVICE_P_H 9 | #define QAVFIODEVICE_P_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | struct AVIOContext; 19 | class QAVIODevicePrivate; 20 | class QAVIODevice : public QObject 21 | { 22 | public: 23 | QAVIODevice(const QSharedPointer &device, QObject *parent = nullptr); 24 | ~QAVIODevice(); 25 | 26 | AVIOContext *ctx() const; 27 | void abort(bool aborted); 28 | 29 | void setBufferSize(size_t size); 30 | size_t bufferSize() const; 31 | 32 | protected: 33 | std::unique_ptr d_ptr; 34 | 35 | private: 36 | Q_DECLARE_PRIVATE(QAVIODevice) 37 | }; 38 | 39 | QT_END_NAMESPACE 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavmuxer.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVMUXER_H 9 | #define QAVMUXER_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 20 | using Locker = QMutexLocker; 21 | #else 22 | using Locker = QMutexLocker; 23 | #endif 24 | 25 | class QAVPacket; 26 | /** 27 | * Allows to mux and write the input streams to output file 28 | */ 29 | class QAVMuxerPrivate; 30 | class QAVMuxer 31 | { 32 | public: 33 | virtual ~QAVMuxer(); 34 | 35 | // Loads the encoder based on parsed streams, format is negotiated from filename 36 | int load(const QList &streams, const QString &filename); 37 | // Stops and unloads the encoder 38 | void unload(); 39 | 40 | // Flushes buffer frames to the encoder 41 | int flush(); 42 | 43 | protected: 44 | QAVMuxer(); 45 | QAVMuxer(QAVMuxerPrivate &d); 46 | 47 | virtual void init(Locker &) = 0; 48 | int initMuxer(Locker &); 49 | virtual int initMuxer(const QAVStream &stream, AVStream *out_stream, Locker &) = 0; 50 | virtual int flushFrames(Locker &) = 0; 51 | virtual void reset(Locker &); 52 | void close(Locker &); 53 | 54 | Q_DISABLE_COPY(QAVMuxer) 55 | Q_DECLARE_PRIVATE(QAVMuxer) 56 | std::unique_ptr d_ptr; 57 | }; 58 | 59 | /** 60 | * Remuxes the same packets from demuxer 61 | */ 62 | class QAVMuxerPackets : public QAVMuxer 63 | { 64 | public: 65 | QAVMuxerPackets() = default; 66 | ~QAVMuxerPackets() override; 67 | 68 | // Writes the packet directly to the encoder 69 | int write(const QAVPacket &packet); 70 | 71 | private: 72 | void init(Locker &) override; 73 | int initMuxer(const QAVStream &stream, AVStream *out_stream, Locker &) override; 74 | int flushFrames(Locker &) override; 75 | // Need to make a copy of packet 76 | int write(QAVPacket packet, int streamIndex, Locker &); 77 | }; 78 | 79 | /** 80 | * Reencodes the frames using the same encoder 81 | */ 82 | class QAVMuxerFramesPrivate; 83 | class QAVMuxerFrames : public QAVMuxer 84 | { 85 | public: 86 | QAVMuxerFrames(); 87 | ~QAVMuxerFrames() override; 88 | 89 | // Adds the frame to the queue 90 | void enqueue(const QAVFrame &frame); 91 | 92 | // Returns size of frames in the queue 93 | size_t size() const; 94 | 95 | // Directly writes to the encoder 96 | int write(const QAVFrame &frame); 97 | int write(const QAVSubtitleFrame &frame); 98 | 99 | private: 100 | void init(Locker &) override; 101 | int initMuxer(const QAVStream &stream, AVStream *out_stream, Locker &) override; 102 | // Need to make a copy of frame 103 | // streamIndex is needed to flush empty frame 104 | int write(QAVFrame frame, int streamIndex, Locker &); 105 | int write(QAVSubtitleFrame frame, int streamIndex, Locker &); 106 | void stop(Locker &); 107 | void reset(Locker &) override; 108 | int flushFrames(Locker &) override; 109 | 110 | Q_DECLARE_PRIVATE(QAVMuxerFrames) 111 | }; 112 | QT_END_NAMESPACE 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavpacket.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #include "qavpacket.h" 9 | #include "qavcodec_p.h" 10 | #include "qavstream.h" 11 | #include 12 | #include 13 | 14 | extern "C" { 15 | #include 16 | #include 17 | #include 18 | } 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | class QAVPacketPrivate 23 | { 24 | public: 25 | AVPacket *pkt = nullptr; 26 | QAVStream stream; 27 | }; 28 | 29 | QAVPacket::QAVPacket() 30 | : d_ptr(new QAVPacketPrivate) 31 | { 32 | d_ptr->pkt = av_packet_alloc(); 33 | d_ptr->pkt->size = 0; 34 | d_ptr->pkt->stream_index = -1; 35 | d_ptr->pkt->pts = AV_NOPTS_VALUE; 36 | } 37 | 38 | QAVPacket::QAVPacket(const QAVPacket &other) 39 | : QAVPacket() 40 | { 41 | *this = other; 42 | } 43 | 44 | QAVPacket &QAVPacket::operator=(const QAVPacket &other) 45 | { 46 | av_packet_unref(d_ptr->pkt); 47 | av_packet_ref(d_ptr->pkt, other.d_ptr->pkt); 48 | 49 | d_ptr->stream = other.d_ptr->stream; 50 | 51 | return *this; 52 | } 53 | 54 | QAVPacket::operator bool() const 55 | { 56 | Q_D(const QAVPacket); 57 | return d->pkt->size; 58 | } 59 | 60 | QAVPacket::~QAVPacket() 61 | { 62 | Q_D(QAVPacket); 63 | av_packet_free(&d->pkt); 64 | } 65 | 66 | AVPacket *QAVPacket::packet() const 67 | { 68 | return d_func()->pkt; 69 | } 70 | 71 | double QAVPacket::duration() const 72 | { 73 | Q_D(const QAVPacket); 74 | if (!d->stream) 75 | return 0.0; 76 | auto tb = d->stream.stream()->time_base; 77 | return tb.num && tb.den ? d->pkt->duration * av_q2d(tb) : 0.0; 78 | } 79 | 80 | double QAVPacket::pts() const 81 | { 82 | Q_D(const QAVPacket); 83 | if (!d->stream) 84 | return 0.0; 85 | auto tb = d->stream.stream()->time_base; 86 | return tb.num && tb.den ? d->pkt->pts * av_q2d(tb) : 0.0; 87 | } 88 | 89 | QAVStream QAVPacket::stream() const 90 | { 91 | Q_D(const QAVPacket); 92 | return d->stream; 93 | } 94 | 95 | void QAVPacket::setStream(const QAVStream &stream) 96 | { 97 | Q_D(QAVPacket); 98 | d->stream = stream; 99 | } 100 | 101 | int QAVPacket::receive() 102 | { 103 | Q_D(QAVPacket); 104 | return d->stream ? d->stream.codec()->read(*this) : 0; 105 | } 106 | 107 | int QAVPacket::send() const 108 | { 109 | Q_D(const QAVPacket); 110 | return d->stream ? d->stream.codec()->write(*this) : 0; 111 | } 112 | 113 | QT_END_NAMESPACE 114 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavpacket.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVPACKET_H 9 | #define QAVPACKET_H 10 | 11 | #include "qavframe.h" 12 | #include "qavstream.h" 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | struct AVPacket; 18 | class QAVPacketPrivate; 19 | class QAVPacket 20 | { 21 | public: 22 | QAVPacket(); 23 | ~QAVPacket(); 24 | QAVPacket(const QAVPacket &other); 25 | QAVPacket &operator=(const QAVPacket &other); 26 | operator bool() const; 27 | 28 | AVPacket *packet() const; 29 | double duration() const; 30 | double pts() const; 31 | 32 | QAVStream stream() const; 33 | void setStream(const QAVStream &stream); 34 | 35 | // Receives a data from the codec from the stream 36 | int receive(); 37 | 38 | // Sends the packet to the codec 39 | int send() const; 40 | 41 | protected: 42 | std::unique_ptr d_ptr; 43 | 44 | private: 45 | Q_DECLARE_PRIVATE(QAVPacket) 46 | }; 47 | 48 | QT_END_NAMESPACE 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavplayer.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVPLAYER_H 9 | #define QAVPLAYER_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | QT_BEGIN_NAMESPACE 20 | 21 | struct AVFormatContext; 22 | class QAVIODevice; 23 | class QAVPlayerPrivate; 24 | class QAVPlayer : public QObject 25 | { 26 | Q_OBJECT 27 | Q_ENUMS(State) 28 | Q_ENUMS(MediaStatus) 29 | Q_ENUMS(Error) 30 | 31 | public: 32 | enum State 33 | { 34 | StoppedState, 35 | PlayingState, 36 | PausedState 37 | }; 38 | 39 | enum MediaStatus 40 | { 41 | NoMedia, 42 | LoadedMedia, 43 | EndOfMedia, 44 | InvalidMedia 45 | }; 46 | 47 | enum Error 48 | { 49 | NoError, 50 | ResourceError, 51 | FilterError 52 | }; 53 | 54 | QAVPlayer(QObject *parent = nullptr); 55 | ~QAVPlayer(); 56 | 57 | void setSource(const QString &url, const QSharedPointer &dev = {}); 58 | QString source() const; 59 | 60 | /** 61 | * Writes the original packets to the output filename 62 | */ 63 | void setOutput(const QString &filename); 64 | QString output() const; 65 | 66 | /** 67 | * Returns all available streams after LoadedMedia 68 | */ 69 | QList availableStreams() const; 70 | 71 | QList availableVideoStreams() const; 72 | QList currentVideoStreams() const; 73 | void setVideoStream(const QAVStream &stream); 74 | void setVideoStreams(const QList &streams); 75 | 76 | QList availableAudioStreams() const; 77 | QList currentAudioStreams() const; 78 | void setAudioStream(const QAVStream &stream); 79 | void setAudioStreams(const QList &streams); 80 | 81 | QList availableSubtitleStreams() const; 82 | QList currentSubtitleStreams() const; 83 | void setSubtitleStream(const QAVStream &stream); 84 | void setSubtitleStreams(const QList &streams); 85 | 86 | AVFormatContext *avctx() const; 87 | 88 | State state() const; 89 | MediaStatus mediaStatus() const; 90 | qint64 duration() const; 91 | qint64 position() const; 92 | qreal speed() const; 93 | double videoFrameRate() const; 94 | 95 | void setFilter(const QString &desc); 96 | void setFilters(const QList &filters); 97 | QList filters() const; 98 | 99 | void setBitstreamFilter(const QString &desc); 100 | QString bitstreamFilter() const; 101 | 102 | bool isSeekable() const; 103 | 104 | bool isSynced() const; 105 | void setSynced(bool sync); 106 | 107 | QString inputFormat() const; 108 | void setInputFormat(const QString &format); 109 | 110 | QString inputVideoCodec() const; 111 | void setInputVideoCodec(const QString &codec); 112 | static QStringList supportedVideoCodecs(); 113 | 114 | QMap inputOptions() const; 115 | void setInputOptions(const QMap &opts); 116 | 117 | QMap videoCodecOptions() const; 118 | void setVideoCodecOptions(const QMap &opts); 119 | 120 | QAVStream::Progress progress(const QAVStream &stream) const; 121 | 122 | public Q_SLOTS: 123 | void play(); 124 | void pause(); 125 | void stop(); 126 | void seek(qint64 position); 127 | void setSpeed(qreal rate); 128 | void stepForward(); 129 | void stepBackward(); 130 | 131 | Q_SIGNALS: 132 | void sourceChanged(const QString &url); 133 | void outputChanged(const QString &filename); 134 | void stateChanged(QAVPlayer::State newState); 135 | void mediaStatusChanged(QAVPlayer::MediaStatus status); 136 | void errorOccurred(QAVPlayer::Error, const QString &str); 137 | void durationChanged(qint64 duration); 138 | void seekableChanged(bool seekable); 139 | void speedChanged(qreal rate); 140 | void videoFrameRateChanged(double rate); 141 | void videoStreamsChanged(const QList &streams); 142 | void audioStreamsChanged(const QList &streams); 143 | void subtitleStreamsChanged(const QList &streams); 144 | void played(qint64 pos); 145 | void paused(qint64 pos); 146 | void stopped(qint64 pos); 147 | void stepped(qint64 pos); 148 | void seeked(qint64 pos); 149 | void filtersChanged(const QList &filters); 150 | void bitstreamFilterChanged(const QString &desc); 151 | void syncedChanged(bool sync); 152 | void inputFormatChanged(const QString &format); 153 | void inputVideoCodecChanged(const QString &codec); 154 | void inputOptionsChanged(const QMap &opts); 155 | void videoCodecOptionsChanged(const QMap &opts); 156 | 157 | void videoFrame(const QAVVideoFrame &frame); 158 | void audioFrame(const QAVAudioFrame &frame); 159 | void subtitleFrame(const QAVSubtitleFrame &frame); 160 | 161 | public: 162 | static void setLogsLevelBackend(int level); 163 | 164 | protected: 165 | std::unique_ptr d_ptr; 166 | 167 | private: 168 | Q_DISABLE_COPY(QAVPlayer) 169 | Q_DECLARE_PRIVATE(QAVPlayer) 170 | }; 171 | 172 | #ifndef QT_NO_DEBUG_STREAM 173 | QDebug operator<<(QDebug, QAVPlayer::State); 174 | QDebug operator<<(QDebug, QAVPlayer::MediaStatus); 175 | QDebug operator<<(QDebug, QAVPlayer::Error); 176 | #endif 177 | 178 | Q_DECLARE_METATYPE(QAVPlayer::State) 179 | Q_DECLARE_METATYPE(QAVPlayer::MediaStatus) 180 | Q_DECLARE_METATYPE(QAVPlayer::Error) 181 | 182 | QT_END_NAMESPACE 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavstream.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVSTREAM_H 9 | #define QAVSTREAM_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | struct AVStream; 19 | struct AVFormatContext; 20 | class QAVCodec; 21 | class QAVStreamPrivate; 22 | class QAVStream 23 | { 24 | public: 25 | QAVStream(); 26 | QAVStream(int index, AVFormatContext *ctx = nullptr, const QSharedPointer &codec = {}); 27 | QAVStream(const QAVStream &other); 28 | ~QAVStream(); 29 | QAVStream &operator=(const QAVStream &other); 30 | operator bool() const; 31 | 32 | int index() const; 33 | AVStream *stream() const; 34 | double duration() const; 35 | int64_t framesCount() const; 36 | double frameRate() const; 37 | QMap metadata() const; 38 | 39 | QSharedPointer codec() const; 40 | 41 | class Progress 42 | { 43 | public: 44 | Progress(double duration = 0.0, qint64 frames = 0, double fr = 0.0); 45 | Progress(const Progress &other); 46 | Progress &operator=(const Progress &other); 47 | 48 | double pts() const; 49 | double duration() const; 50 | qint64 framesCount() const; 51 | qint64 expectedFramesCount() const; 52 | double frameRate() const; 53 | double expectedFrameRate() const; 54 | unsigned fps() const; 55 | 56 | void onFrameSent(double pts); 57 | private: 58 | double m_pts = 0.0; 59 | double m_duration = 0.0; 60 | qint64 m_framesCount = 0; 61 | qint64 m_expectedFramesCount = 0; 62 | double m_expectedFrameRate = 0.0; 63 | qint64 m_time = 0; 64 | qint64 m_diffs = 0; 65 | }; 66 | 67 | private: 68 | std::unique_ptr d_ptr; 69 | Q_DECLARE_PRIVATE(QAVStream) 70 | }; 71 | 72 | bool operator==(const QAVStream &lhs, const QAVStream &rhs); 73 | 74 | Q_DECLARE_METATYPE(QAVStream) 75 | 76 | #ifndef QT_NO_DEBUG_STREAM 77 | QDebug operator<<(QDebug, const QAVStream &); 78 | QDebug operator<<(QDebug, const QAVStream::Progress &); 79 | #endif 80 | 81 | QT_END_NAMESPACE 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavstreamframe.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #include "qavstreamframe.h" 9 | #include "qavstreamframe_p.h" 10 | #include "qavframe_p.h" 11 | #include "qavcodec_p.h" 12 | #include 13 | 14 | extern "C" { 15 | #include 16 | } 17 | 18 | QT_BEGIN_NAMESPACE 19 | 20 | QAVStreamFrame::QAVStreamFrame() 21 | : QAVStreamFrame(*new QAVStreamFramePrivate) 22 | { 23 | } 24 | 25 | QAVStreamFrame::QAVStreamFrame(const QAVStreamFrame &other) 26 | : QAVStreamFrame() 27 | { 28 | *this = other; 29 | } 30 | 31 | QAVStreamFrame::QAVStreamFrame(QAVStreamFramePrivate &d) 32 | : d_ptr(&d) 33 | { 34 | } 35 | 36 | QAVStreamFrame::~QAVStreamFrame() 37 | { 38 | } 39 | 40 | QAVStream QAVStreamFrame::stream() const 41 | { 42 | return d_ptr->stream; 43 | } 44 | 45 | void QAVStreamFrame::setStream(const QAVStream &stream) 46 | { 47 | Q_D(QAVStreamFrame); 48 | d->stream = stream; 49 | } 50 | 51 | QAVStreamFrame &QAVStreamFrame::operator=(const QAVStreamFrame &other) 52 | { 53 | d_ptr->stream = other.d_ptr->stream; 54 | return *this; 55 | } 56 | 57 | QAVStreamFrame::operator bool() const 58 | { 59 | Q_D(const QAVStreamFrame); 60 | return d->stream; 61 | } 62 | 63 | double QAVStreamFrame::pts() const 64 | { 65 | Q_D(const QAVStreamFrame); 66 | return d->pts(); 67 | } 68 | 69 | double QAVStreamFrame::duration() const 70 | { 71 | Q_D(const QAVStreamFrame); 72 | return d->duration(); 73 | } 74 | 75 | int QAVStreamFrame::receive() 76 | { 77 | Q_D(QAVStreamFrame); 78 | return d->stream ? d->stream.codec()->read(*this) : 0; 79 | } 80 | 81 | int QAVStreamFrame::send() const 82 | { 83 | Q_D(const QAVStreamFrame); 84 | return d->stream ? d->stream.codec()->write(*this) : 0; 85 | } 86 | 87 | QT_END_NAMESPACE 88 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavstreamframe.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVSTREAMFRAME_H 9 | #define QAVSTREAMFRAME_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QAVStreamFramePrivate; 18 | class QAVStreamFrame 19 | { 20 | public: 21 | QAVStreamFrame(); 22 | QAVStreamFrame(const QAVStreamFrame &other); 23 | ~QAVStreamFrame(); 24 | QAVStreamFrame &operator=(const QAVStreamFrame &other); 25 | 26 | QAVStream stream() const; 27 | void setStream(const QAVStream &stream); 28 | operator bool() const; 29 | 30 | double pts() const; 31 | double duration() const; 32 | 33 | // Receives a data from the codec from the stream 34 | int receive(); 35 | 36 | // Sends the frame to the codec 37 | int send() const; 38 | 39 | protected: 40 | QAVStreamFrame(QAVStreamFramePrivate &d); 41 | 42 | std::unique_ptr d_ptr; 43 | Q_DECLARE_PRIVATE(QAVStreamFrame) 44 | }; 45 | 46 | QT_END_NAMESPACE 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavstreamframe_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVSTREAMFRAME_P_H 9 | #define QAVSTREAMFRAME_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavstream.h" 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVStreamFramePrivate 28 | { 29 | public: 30 | QAVStreamFramePrivate() = default; 31 | virtual ~QAVStreamFramePrivate() = default; 32 | 33 | virtual double pts() const { return NAN; } 34 | virtual double duration() const { return 0.0; } 35 | 36 | QAVStream stream; 37 | }; 38 | 39 | QT_END_NAMESPACE 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavsubtitlecodec.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #include "qavsubtitlecodec_p.h" 9 | #include "qavcodec_p_p.h" 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | } 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QAVSubtitleCodecPrivate : public QAVCodecPrivate 19 | { 20 | Q_DECLARE_PUBLIC(QAVSubtitleCodec) 21 | public: 22 | QAVSubtitleCodecPrivate(QAVSubtitleCodec *q) : q_ptr(q) { } 23 | 24 | QAVSubtitleCodec *q_ptr = nullptr; 25 | QAVSubtitleFrame frame; 26 | int gotOutput = 0; 27 | QAVPacket pkt; 28 | const int subtitle_out_max_size = 1024 * 1024; 29 | }; 30 | 31 | QAVSubtitleCodec::QAVSubtitleCodec(const AVCodec *codec) 32 | : QAVCodec(*new QAVSubtitleCodecPrivate(this), codec) 33 | { 34 | } 35 | 36 | int QAVSubtitleCodec::write(const QAVPacket &pkt) 37 | { 38 | Q_D(QAVSubtitleCodec); 39 | if (!d->avctx) 40 | return AVERROR(EINVAL); 41 | d->frame.setStream(pkt.stream()); 42 | return avcodec_decode_subtitle2( 43 | d->avctx, 44 | d->frame.subtitle(), 45 | &d->gotOutput, 46 | const_cast(pkt.packet())); 47 | } 48 | 49 | int QAVSubtitleCodec::write(const QAVStreamFrame &frame) 50 | { 51 | Q_D(QAVSubtitleCodec); 52 | if (!d->avctx) 53 | return AVERROR(EINVAL); 54 | d->pkt.setStream(frame.stream()); 55 | auto pkt = d->pkt.packet(); 56 | int ret = av_new_packet(pkt, d->subtitle_out_max_size); 57 | if (ret < 0) 58 | return AVERROR(ENOMEM); 59 | auto f = static_cast(&frame); 60 | auto subtitle_out_size = avcodec_encode_subtitle( 61 | d->avctx, 62 | pkt->data, 63 | pkt->size, 64 | f->subtitle()); 65 | if (subtitle_out_size < 0) { 66 | return subtitle_out_size; 67 | } 68 | av_shrink_packet(pkt, subtitle_out_size); 69 | #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 0, 0) 70 | auto sub = f->subtitle(); 71 | pkt->time_base = AV_TIME_BASE_Q; 72 | pkt->pts = sub->pts; 73 | pkt->duration = av_rescale_q(sub->end_display_time, AVRational{ 1, 1000 }, pkt->time_base); 74 | auto enc = frame.stream().codec()->avctx(); 75 | if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE) { 76 | if (frame.stream().index() == 0) 77 | pkt->pts += av_rescale_q(sub->start_display_time, AVRational{ 1, 1000 }, pkt->time_base); 78 | else 79 | pkt->pts += av_rescale_q(sub->end_display_time, AVRational{ 1, 1000 }, pkt->time_base); 80 | } 81 | pkt->dts = pkt->pts; 82 | #endif 83 | return 0; 84 | } 85 | 86 | int QAVSubtitleCodec::read(QAVStreamFrame &frame) 87 | { 88 | Q_D(QAVSubtitleCodec); 89 | if (!d->avctx) 90 | return AVERROR(EINVAL); 91 | if (!d->gotOutput) 92 | return AVERROR(EAGAIN); 93 | *static_cast(&frame) = d->frame; 94 | d->gotOutput = 0; 95 | d->frame = {}; 96 | return 0; 97 | } 98 | 99 | int QAVSubtitleCodec::read(QAVPacket &pkt) 100 | { 101 | Q_D(QAVSubtitleCodec); 102 | if (!d->avctx) 103 | return AVERROR(EINVAL); 104 | if (!d->pkt) 105 | return AVERROR(EAGAIN); 106 | pkt = d->pkt; 107 | d->pkt = {}; 108 | return 0; 109 | } 110 | 111 | QT_END_NAMESPACE 112 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavsubtitlecodec_p.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVSUBTITLECODEC_P_H 9 | #define QAVSUBTITLECODEC_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavsubtitleframe.h" 23 | #include "qavcodec_p.h" 24 | #include "qavpacket.h" 25 | 26 | QT_BEGIN_NAMESPACE 27 | 28 | class QAVSubtitleCodecPrivate; 29 | class QAVSubtitleCodec : public QAVCodec 30 | { 31 | public: 32 | QAVSubtitleCodec(const AVCodec *codec = nullptr); 33 | 34 | int write(const QAVPacket &pkt) override; 35 | int write(const QAVStreamFrame &frame) override; 36 | int read(QAVStreamFrame &frame) override; 37 | int read(QAVPacket &pkt) override; 38 | 39 | private: 40 | Q_DECLARE_PRIVATE(QAVSubtitleCodec) 41 | }; 42 | 43 | QT_END_NAMESPACE 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavsubtitleframe.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavsubtitleframe.h" 9 | #include "qavstreamframe_p.h" 10 | #include 11 | 12 | extern "C" { 13 | #include "libavcodec/avcodec.h" 14 | #include "libavformat/avformat.h" 15 | } 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | class QAVSubtitleFramePrivate : public QAVStreamFramePrivate 20 | { 21 | public: 22 | QSharedPointer subtitle; 23 | 24 | double pts() const override; 25 | double duration() const override; 26 | }; 27 | 28 | static void subtitle_free(AVSubtitle *subtitle) 29 | { 30 | avsubtitle_free(subtitle); 31 | delete subtitle; 32 | } 33 | 34 | QAVSubtitleFrame::QAVSubtitleFrame() 35 | : QAVStreamFrame(*new QAVSubtitleFramePrivate) 36 | { 37 | Q_D(QAVSubtitleFrame); 38 | d->subtitle.reset(new AVSubtitle, subtitle_free); 39 | memset(d->subtitle.data(), 0, sizeof(*d->subtitle.data())); 40 | } 41 | 42 | QAVSubtitleFrame::~QAVSubtitleFrame() 43 | { 44 | } 45 | 46 | QAVSubtitleFrame::QAVSubtitleFrame(const QAVSubtitleFrame &other) 47 | : QAVSubtitleFrame() 48 | { 49 | operator=(other); 50 | } 51 | 52 | QAVSubtitleFrame &QAVSubtitleFrame::operator=(const QAVSubtitleFrame &other) 53 | { 54 | Q_D(QAVSubtitleFrame); 55 | QAVStreamFrame::operator=(other); 56 | d->subtitle = static_cast(other.d_ptr.get())->subtitle; 57 | 58 | return *this; 59 | } 60 | 61 | AVSubtitle *QAVSubtitleFrame::subtitle() const 62 | { 63 | Q_D(const QAVSubtitleFrame); 64 | return d->subtitle.data(); 65 | } 66 | 67 | double QAVSubtitleFramePrivate::pts() const 68 | { 69 | if (!subtitle) 70 | return NAN; 71 | AVRational tb; 72 | tb.num = 1; 73 | tb.den = AV_TIME_BASE; 74 | return subtitle->pts == AV_NOPTS_VALUE ? NAN : subtitle->pts * av_q2d(tb); 75 | } 76 | 77 | double QAVSubtitleFramePrivate::duration() const 78 | { 79 | if (!subtitle) 80 | return 0.0; 81 | return (subtitle->end_display_time - subtitle->start_display_time) / 1000.0; 82 | } 83 | 84 | QT_END_NAMESPACE 85 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavsubtitleframe.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFSUBTITLERAME_H 9 | #define QAVFSUBTITLERAME_H 10 | 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | struct AVSubtitle; 16 | class QAVSubtitleFramePrivate; 17 | class QAVSubtitleFrame : public QAVStreamFrame 18 | { 19 | public: 20 | QAVSubtitleFrame(); 21 | ~QAVSubtitleFrame(); 22 | QAVSubtitleFrame(const QAVSubtitleFrame &other); 23 | QAVSubtitleFrame &operator=(const QAVSubtitleFrame &other); 24 | 25 | AVSubtitle *subtitle() const; 26 | 27 | private: 28 | Q_DECLARE_PRIVATE(QAVSubtitleFrame) 29 | }; 30 | 31 | Q_DECLARE_METATYPE(QAVSubtitleFrame) 32 | 33 | QT_END_NAMESPACE 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideobuffer_cpu.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavvideobuffer_cpu_p.h" 9 | 10 | extern "C" { 11 | #include 12 | #include 13 | } 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | QAVVideoFrame::MapData QAVVideoBuffer_CPU::map() 18 | { 19 | QAVVideoFrame::MapData mapData; 20 | auto frame = m_frame.frame(); 21 | if (frame->format == AV_PIX_FMT_NONE) 22 | return mapData; 23 | 24 | mapData.size = av_image_get_buffer_size(AVPixelFormat(frame->format), frame->width, frame->height, 1); 25 | mapData.format = AVPixelFormat(frame->format); 26 | 27 | for (int i = 0; i < 4; ++i) { 28 | if (!frame->linesize[i]) 29 | break; 30 | 31 | mapData.bytesPerLine[i] = frame->linesize[i]; 32 | mapData.data[i] = static_cast(frame->data[i]); 33 | } 34 | 35 | return mapData; 36 | } 37 | 38 | QT_END_NAMESPACE 39 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideobuffer_cpu_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVVIDEOBUFFER_CPU_P_H 9 | #define QAVVIDEOBUFFER_CPU_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavvideobuffer_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVVideoBuffer_CPU : public QAVVideoBuffer 27 | { 28 | public: 29 | QAVVideoBuffer_CPU() = default; 30 | ~QAVVideoBuffer_CPU() = default; 31 | explicit QAVVideoBuffer_CPU(const QAVVideoFrame &frame) : QAVVideoBuffer(frame) { } 32 | 33 | QAVVideoFrame::MapData map() override; 34 | }; 35 | 36 | QT_END_NAMESPACE 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideobuffer_gpu.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavvideobuffer_gpu_p.h" 9 | #include 10 | 11 | extern "C" { 12 | #include 13 | #include 14 | } 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | QAVVideoFrame::MapData QAVVideoBuffer_GPU::map() 19 | { 20 | auto mapData = m_cpu.map(); 21 | if (mapData.format == AV_PIX_FMT_NONE) { 22 | int ret = av_hwframe_transfer_data(m_cpu.frame().frame(), m_frame.frame(), 0); 23 | if (ret < 0) { 24 | qWarning() << "Could not av_hwframe_transfer_data:" << ret; 25 | return {}; 26 | } 27 | m_frame = QAVVideoFrame(); 28 | mapData = m_cpu.map(); 29 | } 30 | 31 | return mapData; 32 | } 33 | 34 | QT_END_NAMESPACE 35 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideobuffer_gpu_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVVIDEOBUFFER_GPU_P_H 9 | #define QAVVIDEOBUFFER_GPU_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavvideobuffer_p.h" 23 | #include "qavvideobuffer_cpu_p.h" 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QAVVideoBuffer_GPU : public QAVVideoBuffer 28 | { 29 | public: 30 | QAVVideoBuffer_GPU() = default; 31 | explicit QAVVideoBuffer_GPU(const QAVVideoFrame &frame) : QAVVideoBuffer(frame) { } 32 | ~QAVVideoBuffer_GPU() = default; 33 | 34 | QAVVideoFrame::MapData map() override; 35 | 36 | protected: 37 | QAVVideoBuffer_CPU m_cpu; 38 | }; 39 | 40 | QT_END_NAMESPACE 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideobuffer_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVVIDEOBUFFER_P_H 9 | #define QAVVIDEOBUFFER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QRhi; 28 | class QAVVideoBuffer 29 | { 30 | public: 31 | QAVVideoBuffer() = default; 32 | explicit QAVVideoBuffer(const QAVVideoFrame &frame) : m_frame(frame) { } 33 | virtual ~QAVVideoBuffer() = default; 34 | const QAVVideoFrame &frame() const { return m_frame; } 35 | 36 | virtual QAVVideoFrame::MapData map() = 0; 37 | virtual QAVVideoFrame::HandleType handleType() const { return QAVVideoFrame::NoHandle; } 38 | virtual QVariant handle(QRhi */*rhi*/ = nullptr) const { return {}; } 39 | protected: 40 | QAVVideoFrame m_frame; 41 | }; 42 | 43 | QT_END_NAMESPACE 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideocodec.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #include "qavvideocodec_p.h" 9 | #include "qavhwdevice_p.h" 10 | #include "qavcodec_p_p.h" 11 | #include "qavpacket.h" 12 | #include "qavframe.h" 13 | #include "qavvideoframe.h" 14 | #include 15 | 16 | extern "C" { 17 | #include 18 | #include 19 | } 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | class QAVVideoCodecPrivate : public QAVCodecPrivate 24 | { 25 | public: 26 | QSharedPointer hw_device; 27 | }; 28 | 29 | static bool isSoftwarePixelFormat(AVPixelFormat from) 30 | { 31 | switch (from) { 32 | case AV_PIX_FMT_VAAPI: 33 | case AV_PIX_FMT_VDPAU: 34 | case AV_PIX_FMT_MEDIACODEC: 35 | case AV_PIX_FMT_VIDEOTOOLBOX: 36 | case AV_PIX_FMT_D3D11: 37 | case AV_PIX_FMT_D3D11VA_VLD: 38 | #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 0, 0) 39 | case AV_PIX_FMT_OPENCL: 40 | #endif 41 | case AV_PIX_FMT_CUDA: 42 | case AV_PIX_FMT_DXVA2_VLD: 43 | #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 58, 101) && LIBAVUTIL_VERSION_INT < AV_VERSION_INT(59, 8, 0) 44 | case AV_PIX_FMT_XVMC: 45 | #endif 46 | #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 134, 0) 47 | case AV_PIX_FMT_VULKAN: 48 | #endif 49 | case AV_PIX_FMT_DRM_PRIME: 50 | case AV_PIX_FMT_MMAL: 51 | case AV_PIX_FMT_QSV: 52 | return false; 53 | default: 54 | return true; 55 | } 56 | } 57 | 58 | static AVPixelFormat negotiate_pixel_format(AVCodecContext *c, const AVPixelFormat *f) 59 | { 60 | auto d = reinterpret_cast(c->opaque); 61 | 62 | QList supported; 63 | #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 0, 0) 64 | for (int i = 0;; ++i) { 65 | const AVCodecHWConfig *config = avcodec_get_hw_config(c->codec, i); 66 | if (!config) 67 | break; 68 | 69 | if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) 70 | supported.append(config->device_type); 71 | } 72 | 73 | if (!supported.isEmpty()) { 74 | qDebug() << c->codec->name << ": supported hardware device contexts:"; 75 | for (auto a: supported) 76 | qDebug() << " " << av_hwdevice_get_type_name(a); 77 | } else { 78 | qWarning() << "None of the hardware accelerations are supported"; 79 | } 80 | #endif 81 | 82 | QList softwareFormats; 83 | QList hardwareFormats; 84 | for (int i = 0; f[i] != AV_PIX_FMT_NONE; ++i) { 85 | if (!isSoftwarePixelFormat(f[i])) { 86 | hardwareFormats.append(f[i]); 87 | continue; 88 | } 89 | softwareFormats.append(f[i]); 90 | } 91 | 92 | qDebug() << "Available pixel formats:"; 93 | for (auto a : softwareFormats) { 94 | auto dsc = av_pix_fmt_desc_get(a); 95 | qDebug() << " " << dsc->name << ": AVPixelFormat(" << a << ")"; 96 | } 97 | 98 | for (auto a : hardwareFormats) { 99 | auto dsc = av_pix_fmt_desc_get(a); 100 | qDebug() << " " << dsc->name << ": AVPixelFormat(" << a << ")"; 101 | } 102 | 103 | AVPixelFormat pf = !softwareFormats.isEmpty() ? softwareFormats[0] : AV_PIX_FMT_NONE; 104 | const char *decStr = "software"; 105 | if (d->hw_device) { 106 | for (auto f : hardwareFormats) { 107 | if (f == d->hw_device->format()) { 108 | d->hw_device->init(c); 109 | pf = d->hw_device->format(); 110 | decStr = "hardware"; 111 | break; 112 | } 113 | } 114 | } 115 | 116 | auto dsc = av_pix_fmt_desc_get(pf); 117 | if (dsc) 118 | qDebug() << "Using" << decStr << "decoding in" << dsc->name; 119 | else 120 | qDebug() << "None of the pixel formats"; 121 | 122 | return pf; 123 | } 124 | 125 | QAVVideoCodec::QAVVideoCodec(const AVCodec *codec) 126 | : QAVFrameCodec(*new QAVVideoCodecPrivate, codec) 127 | { 128 | d_ptr->avctx->opaque = d_ptr.get(); 129 | d_ptr->avctx->get_format = negotiate_pixel_format; 130 | } 131 | 132 | QAVVideoCodec::~QAVVideoCodec() 133 | { 134 | av_buffer_unref(&avctx()->hw_device_ctx); 135 | } 136 | 137 | void QAVVideoCodec::setDevice(const QSharedPointer &d) 138 | { 139 | d_func()->hw_device = d; 140 | } 141 | 142 | QAVHWDevice *QAVVideoCodec::device() const 143 | { 144 | return d_func()->hw_device.data(); 145 | } 146 | 147 | QT_END_NAMESPACE 148 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideocodec_p.h: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * Copyright (C) 2020, 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | ***************************************************************/ 7 | 8 | #ifndef QAVVIDEOCODEC_P_H 9 | #define QAVVIDEOCODEC_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavframecodec_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVVideoCodecPrivate; 27 | class QAVHWDevice; 28 | class QAVVideoCodec : public QAVFrameCodec 29 | { 30 | public: 31 | QAVVideoCodec(const AVCodec *codec = nullptr); 32 | ~QAVVideoCodec(); 33 | 34 | void setDevice(const QSharedPointer &d); 35 | QAVHWDevice *device() const; 36 | 37 | private: 38 | Q_DISABLE_COPY(QAVVideoCodec) 39 | Q_DECLARE_PRIVATE(QAVVideoCodec) 40 | }; 41 | 42 | QT_END_NAMESPACE 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideofilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavvideofilter_p.h" 9 | #include "qavfilter_p_p.h" 10 | #include "qavcodec_p.h" 11 | #include "qavvideoframe.h" 12 | #include "qavstream.h" 13 | #include 14 | 15 | extern "C" { 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | } 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | class QAVVideoFilterPrivate : public QAVFilterPrivate 26 | { 27 | public: 28 | QAVVideoFilterPrivate(QAVFilter *q, QMutex &mutex) : QAVFilterPrivate(q, mutex) { } 29 | 30 | QList inputs; 31 | QList outputs; 32 | }; 33 | 34 | QAVVideoFilter::QAVVideoFilter( 35 | const QAVStream &stream, 36 | const QString &name, 37 | const QList &inputs, 38 | const QList &outputs, 39 | QMutex &mutex) 40 | : QAVFilter( 41 | stream, 42 | name, 43 | *new QAVVideoFilterPrivate(this, mutex)) 44 | { 45 | Q_D(QAVVideoFilter); 46 | d->inputs = inputs; 47 | d->outputs = outputs; 48 | } 49 | 50 | int QAVVideoFilter::write(const QAVFrame &frame) 51 | { 52 | Q_D(QAVVideoFilter); 53 | if (!frame || frame.stream().stream()->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { 54 | qWarning() << "Frame is not video"; 55 | return AVERROR(EINVAL); 56 | } 57 | if (!d->isEmpty) 58 | return AVERROR(EAGAIN); 59 | 60 | d->sourceFrame = frame; 61 | for (const auto &filter : d->inputs) { 62 | if (!filter.supports(d->sourceFrame)) { 63 | d->sourceFrame = {}; 64 | return AVERROR(ENOTSUP); 65 | } 66 | QAVFrame ref = d->sourceFrame; 67 | QMutexLocker locker(&d->graphMutex); 68 | int ret = av_buffersrc_add_frame_flags(filter.ctx(), ref.frame(), AV_BUFFERSRC_FLAG_PUSH); 69 | if (ret < 0) 70 | return ret; 71 | } 72 | 73 | d->isEmpty = false; 74 | return 0; 75 | } 76 | 77 | int QAVVideoFilter::read(QAVFrame &frame) 78 | { 79 | Q_D(QAVVideoFilter); 80 | if (d->outputs.isEmpty() || d->isEmpty) { 81 | int ret = AVERROR(EAGAIN); 82 | if (d->sourceFrame && d->outputs.isEmpty()) { 83 | frame = d->sourceFrame; 84 | ret = 0; 85 | } 86 | d->sourceFrame = {}; 87 | d->isEmpty = true; 88 | return ret; 89 | } 90 | 91 | int ret = 0; 92 | if (d->outputFrames.isEmpty()) { 93 | for (int i = 0; i < d->outputs.size(); ++i) { 94 | const auto &filter = d->outputs[i]; 95 | while (true) { 96 | QAVFrame out = d->sourceFrame; 97 | // av_buffersink_get_frame_flags allocates frame's data 98 | av_frame_unref(out.frame()); 99 | { 100 | QMutexLocker locker(&d->graphMutex); 101 | ret = av_buffersink_get_frame_flags(filter.ctx(), out.frame(), 0); 102 | } 103 | if (ret < 0) 104 | break; 105 | 106 | #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 30, 0) 107 | if (!out.frame()->pkt_duration) 108 | out.frame()->pkt_duration = d->sourceFrame.frame()->pkt_duration; 109 | #else 110 | if (out.frame()->duration == AV_NOPTS_VALUE || out.frame()->duration == 0) 111 | out.frame()->duration = d->sourceFrame.frame()->duration; 112 | #endif 113 | out.setFrameRate(av_buffersink_get_frame_rate(filter.ctx())); 114 | out.setTimeBase(av_buffersink_get_time_base(filter.ctx())); 115 | out.setFilterName( 116 | !filter.name().isEmpty() 117 | ? filter.name() 118 | : QString(QLatin1String("%1:%2")).arg(d->name).arg(QString::number(i))); 119 | if (!out.stream()) 120 | out.setStream(d->stream); 121 | d->outputFrames.push_back(out); 122 | } 123 | } 124 | } 125 | 126 | ret = AVERROR(EAGAIN); 127 | if (!d->outputFrames.isEmpty()) { 128 | frame = d->outputFrames.takeFirst(); 129 | ret = 0; 130 | } 131 | if (d->outputFrames.isEmpty()) { 132 | d->sourceFrame = {}; 133 | d->isEmpty = true; 134 | } 135 | return ret; 136 | } 137 | 138 | void QAVVideoFilter::flush() 139 | { 140 | Q_D(QAVVideoFilter); 141 | for (const auto &filter : d->inputs) { 142 | int ret = av_buffersrc_add_frame(filter.ctx(), nullptr); 143 | if (ret < 0) 144 | qWarning() << "Could not flush:" << ret; 145 | } 146 | d->isEmpty = false; 147 | } 148 | 149 | QT_END_NAMESPACE 150 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideofilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVVIDEOFILTER_P_H 9 | #define QAVVIDEOFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavfilter_p.h" 23 | #include "qavvideoinputfilter_p.h" 24 | #include "qavvideooutputfilter_p.h" 25 | #include 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QAVVideoFilterPrivate; 30 | class QAVVideoFilter : public QAVFilter 31 | { 32 | public: 33 | QAVVideoFilter( 34 | const QAVStream &stream, 35 | const QString &name, 36 | const QList &inputs, 37 | const QList &outputs, 38 | QMutex &mutex); 39 | 40 | int write(const QAVFrame &frame) override; 41 | int read(QAVFrame &frame) override; 42 | void flush() override; 43 | 44 | protected: 45 | Q_DECLARE_PRIVATE(QAVVideoFilter) 46 | private: 47 | Q_DISABLE_COPY(QAVVideoFilter) 48 | }; 49 | 50 | QT_END_NAMESPACE 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideoframe.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVFVIDEORAME_H 9 | #define QAVFVIDEORAME_H 10 | 11 | #include 12 | #include 13 | #ifdef QT_AVPLAYER_MULTIMEDIA 14 | #include 15 | #endif 16 | 17 | extern "C" { 18 | #include 19 | } 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | class QAVVideoFramePrivate; 24 | class QAVCodec; 25 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 26 | class QRhi; 27 | #endif 28 | class QAVVideoFrame : public QAVFrame 29 | { 30 | public: 31 | enum HandleType 32 | { 33 | NoHandle, 34 | GLTextureHandle, 35 | MTLTextureHandle, 36 | D3D11Texture2DHandle 37 | }; 38 | 39 | QAVVideoFrame(); 40 | QAVVideoFrame(const QAVFrame &other); 41 | QAVVideoFrame(const QAVVideoFrame &other); 42 | QAVVideoFrame(const QSize &size, AVPixelFormat fmt); 43 | 44 | QAVVideoFrame &operator=(const QAVFrame &other); 45 | QAVVideoFrame &operator=(const QAVVideoFrame &other); 46 | 47 | QSize size() const; 48 | 49 | struct MapData 50 | { 51 | int size = 0; 52 | int bytesPerLine[4] = {0}; 53 | uchar *data[4] = {nullptr}; 54 | AVPixelFormat format = AV_PIX_FMT_NONE; 55 | }; 56 | 57 | MapData map() const; 58 | HandleType handleType() const; 59 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 60 | QVariant handle(QRhi *rhi = nullptr) const; 61 | #else 62 | QVariant handle() const; 63 | #endif 64 | AVPixelFormat format() const; 65 | QString formatName() const; 66 | QAVVideoFrame convertTo(AVPixelFormat fmt) const; 67 | #ifdef QT_AVPLAYER_MULTIMEDIA 68 | operator QVideoFrame() const; 69 | #endif 70 | 71 | protected: 72 | Q_DECLARE_PRIVATE(QAVVideoFrame) 73 | }; 74 | 75 | Q_DECLARE_METATYPE(QAVVideoFrame) 76 | Q_DECLARE_METATYPE(AVPixelFormat) 77 | 78 | QT_END_NAMESPACE 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideoinputfilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavframe.h" 9 | #include "qavvideoinputfilter_p.h" 10 | #include "qavinoutfilter_p_p.h" 11 | #include "qavdemuxer_p.h" 12 | #include 13 | 14 | extern "C" { 15 | #include 16 | #include 17 | #include 18 | } 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | class QAVVideoInputFilterPrivate : public QAVInOutFilterPrivate 23 | { 24 | public: 25 | QAVVideoInputFilterPrivate(QAVInOutFilter *q) 26 | : QAVInOutFilterPrivate(q) 27 | { } 28 | 29 | AVPixelFormat format = AV_PIX_FMT_NONE; 30 | int width = 0; 31 | int height = 0; 32 | AVRational sample_aspect_ratio{}; 33 | AVRational time_base{}; 34 | AVRational frame_rate{}; 35 | }; 36 | 37 | QAVVideoInputFilter::QAVVideoInputFilter() 38 | : QAVInOutFilter(*new QAVVideoInputFilterPrivate(this)) 39 | { 40 | } 41 | 42 | QAVVideoInputFilter::QAVVideoInputFilter(const QAVFrame &frame) 43 | : QAVVideoInputFilter() 44 | { 45 | Q_D(QAVVideoInputFilter); 46 | const auto & frm = frame.frame(); 47 | const auto & stream = frame.stream().stream(); 48 | d->format = frm->format != AV_PIX_FMT_NONE ? AVPixelFormat(frm->format) : AVPixelFormat(stream->codecpar->format); 49 | d->width = frm->width ? frm->width : stream->codecpar->width; 50 | d->height = frm->height ? frm->height : stream->codecpar->height; 51 | d->sample_aspect_ratio = frm->sample_aspect_ratio.num && frm->sample_aspect_ratio.den ? frm->sample_aspect_ratio : stream->codecpar->sample_aspect_ratio; 52 | d->time_base = stream->time_base; 53 | d->frame_rate = stream->avg_frame_rate; 54 | } 55 | 56 | QAVVideoInputFilter::QAVVideoInputFilter(const QAVVideoInputFilter &other) 57 | : QAVVideoInputFilter() 58 | { 59 | *this = other; 60 | } 61 | 62 | QAVVideoInputFilter::~QAVVideoInputFilter() = default; 63 | 64 | QAVVideoInputFilter &QAVVideoInputFilter::operator=(const QAVVideoInputFilter &other) 65 | { 66 | Q_D(QAVVideoInputFilter); 67 | QAVInOutFilter::operator=(other); 68 | d->format = other.d_func()->format; 69 | d->width = other.d_func()->width; 70 | d->height = other.d_func()->height; 71 | d->sample_aspect_ratio = other.d_func()->sample_aspect_ratio; 72 | d->time_base = other.d_func()->time_base; 73 | d->frame_rate = other.d_func()->frame_rate; 74 | return *this; 75 | } 76 | 77 | int QAVVideoInputFilter::configure(AVFilterGraph *graph, AVFilterInOut *in) 78 | { 79 | QAVInOutFilter::configure(graph, in); 80 | Q_D(QAVVideoInputFilter); 81 | AVBPrint args; 82 | av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC); 83 | av_bprintf(&args, 84 | "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" 85 | "pixel_aspect=%d/%d", 86 | d->width, d->height, d->format, 87 | d->time_base.num, d->time_base.den, 88 | d->sample_aspect_ratio.num, qMax(d->sample_aspect_ratio.den, 1)); 89 | if (d->frame_rate.num && d->frame_rate.den) 90 | av_bprintf(&args, ":frame_rate=%d/%d", d->frame_rate.num, d->frame_rate.den); 91 | 92 | static int index = 0; 93 | char name[255]; 94 | snprintf(name, sizeof(name), "buffer_%d", index++); 95 | 96 | int ret = avfilter_graph_create_filter(&d->ctx, 97 | avfilter_get_by_name("buffer"), 98 | name, args.str, nullptr, graph); 99 | if (ret < 0) 100 | return ret; 101 | 102 | return avfilter_link(d->ctx, 0, in->filter_ctx, in->pad_idx); 103 | } 104 | 105 | bool QAVVideoInputFilter::supports(const QAVFrame &frame) const 106 | { 107 | Q_D(const QAVVideoInputFilter); 108 | if (!frame) 109 | return true; 110 | const auto & frm = frame.frame(); 111 | return d->width == frm->width 112 | && d->height == frm->height 113 | && d->format == frm->format; 114 | } 115 | 116 | QT_END_NAMESPACE 117 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideoinputfilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVVIDEOINPUTFILTER_P_H 9 | #define QAVVIDEOINPUTFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavinoutfilter_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVFrame; 27 | class QAVVideoInputFilterPrivate; 28 | class QAVVideoInputFilter : public QAVInOutFilter 29 | { 30 | public: 31 | QAVVideoInputFilter(const QAVFrame &frame); 32 | QAVVideoInputFilter(const QAVVideoInputFilter &other); 33 | ~QAVVideoInputFilter(); 34 | QAVVideoInputFilter &operator=(const QAVVideoInputFilter &other); 35 | 36 | int configure(AVFilterGraph *graph, AVFilterInOut *in) override; 37 | bool supports(const QAVFrame &frame) const; 38 | 39 | protected: 40 | QAVVideoInputFilter(); 41 | Q_DECLARE_PRIVATE(QAVVideoInputFilter) 42 | }; 43 | 44 | QT_END_NAMESPACE 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideooutputfilter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #include "qavvideooutputfilter_p.h" 9 | #include "qavinoutfilter_p_p.h" 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | } 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | QAVVideoOutputFilter::QAVVideoOutputFilter() 19 | : QAVInOutFilter(*new QAVInOutFilterPrivate(this)) 20 | { 21 | } 22 | 23 | QAVVideoOutputFilter::~QAVVideoOutputFilter() = default; 24 | 25 | int QAVVideoOutputFilter::configure(AVFilterGraph *graph, AVFilterInOut *out) 26 | { 27 | QAVInOutFilter::configure(graph, out); 28 | Q_D(QAVInOutFilter); 29 | static int index = 0; 30 | char name[255]; 31 | snprintf(name, sizeof(name), "buffersink_%d", index++); 32 | 33 | int ret = avfilter_graph_create_filter(&d->ctx, 34 | avfilter_get_by_name("buffersink"), 35 | name, nullptr, nullptr, graph); 36 | if (ret < 0) 37 | return ret; 38 | 39 | return avfilter_link(out->filter_ctx, out->pad_idx, d->ctx, 0); 40 | } 41 | 42 | QT_END_NAMESPACE 43 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavvideooutputfilter_p.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2021, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVVIDEOOUTPUTFILTER_P_H 9 | #define QAVVIDEOOUTPUTFILTER_P_H 10 | 11 | // 12 | // W A R N I N G 13 | // ------------- 14 | // 15 | // This file is not part of the Qt API. It exists purely as an 16 | // implementation detail. This header file may change from version to 17 | // version without notice, or even be removed. 18 | // 19 | // We mean it. 20 | // 21 | 22 | #include "qavinoutfilter_p.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QAVVideoOutputFilterPrivate; 27 | class QAVVideoOutputFilter : public QAVInOutFilter 28 | { 29 | public: 30 | QAVVideoOutputFilter(); 31 | ~QAVVideoOutputFilter(); 32 | 33 | int configure(AVFilterGraph *graph, AVFilterInOut *out) override; 34 | }; 35 | 36 | QT_END_NAMESPACE 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qavwidget_opengl.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2025, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QAVWIDGET_OPENGL_H 9 | #define QAVWIDGET_OPENGL_H 10 | 11 | #include "qavvideoframe.h" 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QAVWidget_OpenGLPrivate; 19 | class QAVWidget_OpenGL : public QOpenGLWidget, public QOpenGLFunctions_3_0 20 | { 21 | Q_OBJECT 22 | public: 23 | QAVWidget_OpenGL(QWidget *parent = nullptr); 24 | ~QAVWidget_OpenGL(); 25 | 26 | void setVideoFrame(const QAVVideoFrame &frame); 27 | 28 | private: 29 | void initializeGL() override; 30 | void paintGL() override; 31 | void resizeGL(int width, int height) override; 32 | 33 | std::unique_ptr d_ptr; 34 | Q_DISABLE_COPY(QAVWidget_OpenGL) 35 | Q_DECLARE_PRIVATE(QAVWidget_OpenGL) 36 | }; 37 | 38 | QT_END_NAMESPACE 39 | 40 | #endif // QAVGLWIDGET_H 41 | -------------------------------------------------------------------------------- /src/QtAVPlayer/qtavplayerglobal.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | * Copyright (C) 2020, Val Doroshchuk * 3 | * * 4 | * This file is part of QtAVPlayer. * 5 | * Free Qt Media Player based on FFmpeg. * 6 | *********************************************************/ 7 | 8 | #ifndef QTAVPLAYERGLOBAL_H 9 | #define QTAVPLAYERGLOBAL_H 10 | 11 | #include 12 | #if defined(QT_AVPLAYER_VA_DRM) 13 | #include 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /tests/auto/integration/qavdemuxer/files.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ../testdata/test.wav 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/auto/integration/qavdemuxer/qavdemuxer.pro: -------------------------------------------------------------------------------- 1 | TARGET = tst_qavdemuxer 2 | INCLUDEPATH += ../../../../src/ ../../../../src/QtAVPlayer 3 | include(../../../../src/QtAVPlayer/QtAVPlayer.pri) 4 | 5 | QT -= gui 6 | QT += testlib 7 | CONFIG += c++17 testcase console 8 | RESOURCES += files.qrc 9 | 10 | SOURCES += \ 11 | tst_qavdemuxer.cpp 12 | 13 | -------------------------------------------------------------------------------- /tests/auto/integration/qavplayer/qavplayer.pro: -------------------------------------------------------------------------------- 1 | TARGET = tst_qavplayer 2 | DEFINES+="QT_AVPLAYER_MULTIMEDIA" 3 | INCLUDEPATH += ../../../../src/ ../../../../src/QtAVPlayer 4 | include(../../../../src/QtAVPlayer/QtAVPlayer.pri) 5 | 6 | QT -= gui 7 | QT += testlib 8 | CONFIG += testcase console c++17 9 | SOURCES += \ 10 | tst_qavplayer.cpp 11 | -------------------------------------------------------------------------------- /tests/auto/integration/testdata/1.dv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/1.dv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/20190821_075842.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/20190821_075842.jpg -------------------------------------------------------------------------------- /tests/auto/integration/testdata/7_BCL02006_ffv1_20s_1.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/7_BCL02006_ffv1_20s_1.mkv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/7_BCL02006_ffv1_20s_2.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/7_BCL02006_ffv1_20s_2.mkv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/BAVC1010958_DV000107.dv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/BAVC1010958_DV000107.dv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/DHC0413_CreaseOrNot.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/DHC0413_CreaseOrNot.mp4 -------------------------------------------------------------------------------- /tests/auto/integration/testdata/Earth_Zoom_In.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/Earth_Zoom_In.mov -------------------------------------------------------------------------------- /tests/auto/integration/testdata/av_sample.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/av_sample.mkv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/colors.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/colors.mp4 -------------------------------------------------------------------------------- /tests/auto/integration/testdata/colors_subtitles.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/colors_subtitles.mkv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/colors_subtitles.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/colors_subtitles.mp4 -------------------------------------------------------------------------------- /tests/auto/integration/testdata/dv.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/dv.tar -------------------------------------------------------------------------------- /tests/auto/integration/testdata/dv25_pal__411_4-3_2ch_32k_bars_sine.dv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/dv25_pal__411_4-3_2ch_32k_bars_sine.dv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/dv_dsf_1_stype_1.dv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/dv_dsf_1_stype_1.dv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/guido.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/guido.mp4 -------------------------------------------------------------------------------- /tests/auto/integration/testdata/rotated_90.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/rotated_90.mp4 -------------------------------------------------------------------------------- /tests/auto/integration/testdata/shots0000.dv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/shots0000.dv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/small.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/small.mp4 -------------------------------------------------------------------------------- /tests/auto/integration/testdata/star_trails.mpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/star_trails.mpeg -------------------------------------------------------------------------------- /tests/auto/integration/testdata/test.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/test.mkv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/test.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/test.mov -------------------------------------------------------------------------------- /tests/auto/integration/testdata/test.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/test.mp3 -------------------------------------------------------------------------------- /tests/auto/integration/testdata/test.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/test.wav -------------------------------------------------------------------------------- /tests/auto/integration/testdata/test6g100.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/test6g100.mkv -------------------------------------------------------------------------------- /tests/auto/integration/testdata/test_5beeps.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valbok/QtAVPlayer/249f495ff519a71fc8847bc0749781028a59927a/tests/auto/integration/testdata/test_5beeps.mkv --------------------------------------------------------------------------------