1/*
2 Copyright (C) 2010-2021 Harald Sitter <sitter@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), Nokia Corporation
10 (or its successors, if any) and the KDE Free Qt Foundation, which shall
11 act as a proxy defined in Section 6 of version 3 of the license.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "videodataoutput.h"
23
24#include <phonon/medianode.h>
25#include <phonon/audiooutput.h>
26#include <phonon/experimental/abstractvideodataoutput.h>
27
28#include <QMetaObject>
29
30#include "utils/debug.h"
31#include "media.h"
32#include "mediaobject.h"
33
34using namespace Phonon::Experimental;
35
36namespace Phonon
37{
38namespace VLC
39{
40
41VideoDataOutput::VideoDataOutput(QObject *parent)
42 : QObject(parent)
43 , m_frontend(0)
44{
45}
46
47VideoDataOutput::~VideoDataOutput()
48{
49}
50
51void VideoDataOutput::handleConnectToMediaObject(MediaObject *mediaObject)
52{
53 Q_UNUSED(mediaObject);
54 setCallbacks(m_player);
55}
56
57void VideoDataOutput::handleDisconnectFromMediaObject(MediaObject *mediaObject)
58{
59 Q_UNUSED(mediaObject);
60 unsetCallbacks(player: m_player);
61}
62
63void VideoDataOutput::handleAddToMedia(Media *media)
64{
65 media->addOption(option: ":video");
66}
67
68Experimental::AbstractVideoDataOutput *VideoDataOutput::frontendObject() const
69{
70 return m_frontend;
71}
72
73void VideoDataOutput::setFrontendObject(Experimental::AbstractVideoDataOutput *frontend)
74{
75 m_frontend = frontend;
76}
77
78void *VideoDataOutput::lockCallback(void **planes)
79{
80 m_mutex.lock();
81 DEBUG_BLOCK;
82 planes[0] = reinterpret_cast<void *>(m_frame.data0.data());
83 planes[1] = reinterpret_cast<void *>(m_frame.data1.data());
84 planes[2] = reinterpret_cast<void *>(m_frame.data2.data());
85 return 0;
86}
87
88void VideoDataOutput::unlockCallback(void *picture, void *const*planes)
89{
90 Q_UNUSED(picture);
91 Q_UNUSED(planes);
92 DEBUG_BLOCK;
93
94 // For some reason VLC yields BGR24, so we swap it to RGB
95 if (m_frame.format == Experimental::VideoFrame2::Format_RGB888) {
96 uchar *data = (uchar *) m_frame.data0.data();
97 uchar tmp;
98 for (int i = 0; i < m_frame.data0.size(); i += 3) {
99 tmp = data[i];
100 data[i] = data[i+2];
101 data[i+2] = tmp;
102 }
103 }
104
105 if (m_frontend)
106 m_frontend->frameReady(m_frame);
107
108 m_mutex.unlock();
109}
110
111void VideoDataOutput::displayCallback(void *picture)
112{
113 Q_UNUSED(picture);
114 DEBUG_BLOCK;
115 // We send the frame while unlocking as we could loose syncing otherwise.
116 // With VDO the consumer is expected to ensure syncness while not blocking
117 // unlock for long periods of time. Good luck with that... -.-
118}
119
120static VideoFrame2::Format fourccToFormat(const char *fourcc)
121{
122 if (qstrcmp(str1: fourcc, str2: "RV24"))
123 return VideoFrame2::Format_RGB888;
124 else if (qstrcmp(str1: fourcc, str2: "RV32"))
125 return VideoFrame2::Format_RGB32;
126 else if (qstrcmp(str1: fourcc, str2: "YV12"))
127 return VideoFrame2::Format_YV12;
128 else if (qstrcmp(str1: fourcc, str2: "YUY2"))
129 return VideoFrame2::Format_YUY2;
130 else
131 return VideoFrame2::Format_Invalid;
132}
133
134static uint32_t setFormat(VideoFrame2::Format format, char **chroma)
135{
136 switch (format) {
137 case VideoFrame2::Format_Invalid:
138 *chroma = nullptr;
139 return 0;
140 case VideoFrame2::Format_RGB32:
141 qstrcpy(dst: *chroma, src: "RV32");
142 return VLC_CODEC_RGB32;
143 case VideoFrame2::Format_RGB888:
144 qstrcpy(dst: *chroma, src: "RV24");
145 return VLC_CODEC_RGB24;
146 case VideoFrame2::Format_YV12:
147 qstrcpy(dst: *chroma, src: "YV12");
148 return VLC_CODEC_YV12;
149 case VideoFrame2::Format_YUY2:
150 qstrcpy(dst: *chroma, src: "YUY2");
151 return VLC_CODEC_YUYV;
152 }
153 return 0;
154}
155
156unsigned VideoDataOutput::formatCallback(char *chroma,
157 unsigned *width, unsigned *height,
158 unsigned *pitches, unsigned *lines)
159{
160 DEBUG_BLOCK;
161
162 m_frame.width = *width;
163 m_frame.height = *height;
164
165 uint32_t fourcc = 0;
166
167 QSet<VideoFrame2::Format> allowedFormats = m_frontend->allowedFormats();
168 VideoFrame2::Format suggestedFormat = fourccToFormat(fourcc: chroma);
169 if (suggestedFormat != VideoFrame2::Format_Invalid
170 && allowedFormats.contains(value: suggestedFormat)) { // Use suggested
171 fourcc = setFormat(format: suggestedFormat, chroma: &chroma);
172 m_frame.format = suggestedFormat;
173 } else { // Pick first and use that
174 foreach (const VideoFrame2::Format &format, allowedFormats) {
175 fourcc = setFormat(format, chroma: &chroma);
176 if (fourcc > 0) {
177 m_frame.format = format;
178 break;
179 }
180 }
181 }
182
183 Q_ASSERT(fourcc > 0);
184
185 unsigned int bufferSize = setPitchAndLines(fourcc, width: *width, height: *height, pitches, lines);
186
187 m_frame.data0.resize(size: pitches[0] * lines[0]);
188 m_frame.data1.resize(size: pitches[1] * lines[1]);
189 m_frame.data2.resize(size: pitches[2] * lines[0]);
190
191 return bufferSize;
192}
193
194void VideoDataOutput::formatCleanUpCallback()
195{
196 DEBUG_BLOCK;
197}
198
199} // namespace VLC
200} // namespace Phonon
201

source code of phonon-vlc/src/video/videodataoutput.cpp