File indexing completed on 2024-05-12 04:44:37

0001 /*
0002     Copyright (C) 2010-2021 Harald Sitter <sitter@kde.org>
0003 
0004     This library is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU Lesser General Public
0006     License as published by the Free Software Foundation; either
0007     version 2.1 of the License, or (at your option) version 3, or any
0008     later version accepted by the membership of KDE e.V. (or its
0009     successor approved by the membership of KDE e.V.), Nokia Corporation
0010     (or its successors, if any) and the KDE Free Qt Foundation, which shall
0011     act as a proxy defined in Section 6 of version 3 of the license.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Lesser General Public License for more details.
0017 
0018     You should have received a copy of the GNU Lesser General Public
0019     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0020 */
0021 
0022 #include "videodataoutput.h"
0023 
0024 #include <phonon/medianode.h>
0025 #include <phonon/audiooutput.h>
0026 #include <phonon/experimental/abstractvideodataoutput.h>
0027 
0028 #include <QMetaObject>
0029 
0030 #include "utils/debug.h"
0031 #include "media.h"
0032 #include "mediaobject.h"
0033 
0034 using namespace Phonon::Experimental;
0035 
0036 namespace Phonon
0037 {
0038 namespace VLC
0039 {
0040 
0041 VideoDataOutput::VideoDataOutput(QObject *parent)
0042     : QObject(parent)
0043     , m_frontend(0)
0044 {
0045 }
0046 
0047 VideoDataOutput::~VideoDataOutput()
0048 {
0049 }
0050 
0051 void VideoDataOutput::handleConnectToMediaObject(MediaObject *mediaObject)
0052 {
0053     Q_UNUSED(mediaObject);
0054     setCallbacks(m_player);
0055 }
0056 
0057 void VideoDataOutput::handleDisconnectFromMediaObject(MediaObject *mediaObject)
0058 {
0059     Q_UNUSED(mediaObject);
0060     unsetCallbacks(m_player);
0061 }
0062 
0063 void VideoDataOutput::handleAddToMedia(Media *media)
0064 {
0065     media->addOption(":video");
0066 }
0067 
0068 Experimental::AbstractVideoDataOutput *VideoDataOutput::frontendObject() const
0069 {
0070     return m_frontend;
0071 }
0072 
0073 void VideoDataOutput::setFrontendObject(Experimental::AbstractVideoDataOutput *frontend)
0074 {
0075     m_frontend = frontend;
0076 }
0077 
0078 void *VideoDataOutput::lockCallback(void **planes)
0079 {
0080     m_mutex.lock();
0081     DEBUG_BLOCK;
0082     planes[0] = reinterpret_cast<void *>(m_frame.data0.data());
0083     planes[1] = reinterpret_cast<void *>(m_frame.data1.data());
0084     planes[2] = reinterpret_cast<void *>(m_frame.data2.data());
0085     return 0;
0086 }
0087 
0088 void VideoDataOutput::unlockCallback(void *picture, void *const*planes)
0089 {
0090     Q_UNUSED(picture);
0091     Q_UNUSED(planes);
0092     DEBUG_BLOCK;
0093 
0094     // For some reason VLC yields BGR24, so we swap it to RGB
0095     if (m_frame.format == Experimental::VideoFrame2::Format_RGB888) {
0096         uchar *data = (uchar *) m_frame.data0.data();
0097         uchar tmp;
0098         for (int i = 0; i < m_frame.data0.size(); i += 3) {
0099             tmp = data[i];
0100             data[i] = data[i+2];
0101             data[i+2] = tmp;
0102         }
0103     }
0104 
0105     if (m_frontend)
0106         m_frontend->frameReady(m_frame);
0107 
0108     m_mutex.unlock();
0109 }
0110 
0111 void VideoDataOutput::displayCallback(void *picture)
0112 {
0113     Q_UNUSED(picture);
0114     DEBUG_BLOCK;
0115     // We send the frame while unlocking as we could loose syncing otherwise.
0116     // With VDO the consumer is expected to ensure syncness while not blocking
0117     // unlock for long periods of time. Good luck with that... -.-
0118 }
0119 
0120 static VideoFrame2::Format fourccToFormat(const char *fourcc)
0121 {
0122     if (qstrcmp(fourcc, "RV24"))
0123         return VideoFrame2::Format_RGB888;
0124     else if (qstrcmp(fourcc, "RV32"))
0125         return VideoFrame2::Format_RGB32;
0126     else if (qstrcmp(fourcc, "YV12"))
0127         return VideoFrame2::Format_YV12;
0128     else if (qstrcmp(fourcc, "YUY2"))
0129         return VideoFrame2::Format_YUY2;
0130     else
0131         return VideoFrame2::Format_Invalid;
0132 }
0133 
0134 static uint32_t setFormat(VideoFrame2::Format format, char **chroma)
0135 {
0136     switch (format) {
0137     case VideoFrame2::Format_Invalid:
0138         *chroma = nullptr;
0139         return 0;
0140     case VideoFrame2::Format_RGB32:
0141         qstrcpy(*chroma, "RV32");
0142         return VLC_CODEC_RGB32;
0143     case VideoFrame2::Format_RGB888:
0144         qstrcpy(*chroma, "RV24");
0145         return VLC_CODEC_RGB24;
0146     case VideoFrame2::Format_YV12:
0147         qstrcpy(*chroma, "YV12");
0148         return VLC_CODEC_YV12;
0149     case VideoFrame2::Format_YUY2:
0150         qstrcpy(*chroma, "YUY2");
0151         return VLC_CODEC_YUYV;
0152     }
0153     return 0;
0154 }
0155 
0156 unsigned VideoDataOutput::formatCallback(char *chroma,
0157                                          unsigned *width, unsigned *height,
0158                                          unsigned *pitches, unsigned *lines)
0159 {
0160     DEBUG_BLOCK;
0161 
0162     m_frame.width = *width;
0163     m_frame.height = *height;
0164 
0165     uint32_t fourcc = 0;
0166 
0167     QSet<VideoFrame2::Format> allowedFormats = m_frontend->allowedFormats();
0168     VideoFrame2::Format suggestedFormat = fourccToFormat(chroma);
0169     if (suggestedFormat != VideoFrame2::Format_Invalid
0170             && allowedFormats.contains(suggestedFormat)) { // Use suggested
0171         fourcc = setFormat(suggestedFormat, &chroma);
0172         m_frame.format = suggestedFormat;
0173     } else { // Pick first and use that
0174         foreach (const VideoFrame2::Format &format, allowedFormats) {
0175             fourcc = setFormat(format, &chroma);
0176             if (fourcc > 0) {
0177                 m_frame.format = format;
0178                 break;
0179             }
0180         }
0181     }
0182 
0183     Q_ASSERT(fourcc > 0);
0184 
0185     unsigned int bufferSize = setPitchAndLines(fourcc, *width, *height, pitches, lines);
0186 
0187     m_frame.data0.resize(pitches[0] * lines[0]);
0188     m_frame.data1.resize(pitches[1] * lines[1]);
0189     m_frame.data2.resize(pitches[2] * lines[0]);
0190 
0191     return bufferSize;
0192 }
0193 
0194 void VideoDataOutput::formatCleanUpCallback()
0195 {
0196     DEBUG_BLOCK;
0197 }
0198 
0199 } // namespace VLC
0200 } // namespace Phonon