5#include "private/qvideotexturehelper_p.h"
6#include "private/qmultimediautils_p.h"
9#include <QtCore/qthread.h>
12#include <libavutil/pixdesc.h>
13#include <libavutil/hdr_dynamic_metadata.h>
14#include <libavutil/mastering_display_metadata.h>
19using namespace QFFmpeg;
24 for (
int i = 0; i < AV_NUM_DATA_POINTERS && frame.data[i]; ++i) {
25 if (frame.linesize[i] < 0)
36 if (frame->hw_frames_ctx) {
37 m_hwFrame = std::move(frame);
38 m_pixelFormat = toQtPixelFormat(HWAccel::format(m_hwFrame.get()));
42 m_swFrame = std::move(frame);
43 m_pixelFormat = toQtPixelFormat(AVPixelFormat(m_swFrame->format));
54 const auto actualAVPixelFormat = AVPixelFormat(m_swFrame->format);
55 const auto targetAVPixelFormat = toAVPixelFormat(m_pixelFormat);
57 const QSize actualSize = frameSize(m_swFrame);
58 if (actualAVPixelFormat != targetAVPixelFormat || isFrameFlipped(*m_swFrame)
59 || m_size != actualSize) {
60 Q_ASSERT(toQtPixelFormat(targetAVPixelFormat) == m_pixelFormat);
62 SwsContextUPtr scaleContext = createSwsContext(actualSize, actualAVPixelFormat, m_size,
63 targetAVPixelFormat, SWS_BICUBIC);
65 auto newFrame = makeAVFrame();
66 newFrame->width = m_size.width();
67 newFrame->height = m_size.height();
68 newFrame->format = targetAVPixelFormat;
69 const int status = av_frame_get_buffer(newFrame.get(), 0);
72 <<
"Failed to allocate frame buffer:" << AVError(status);
76 sws_scale(scaleContext.get(), m_swFrame->data, m_swFrame->linesize, 0, m_swFrame->height,
77 newFrame->data, newFrame->linesize);
78 if (m_frame == m_swFrame.get())
79 m_frame = newFrame.get();
80 m_swFrame = std::move(newFrame);
90 ensureTextureConverter(rhi);
97 HwFrameContextData &frameContextData = HwFrameContextData::ensure(*m_hwFrame);
98 TextureConverter *converter = frameContextData.textureConverterMapper.get(&rhi);
102 std::tie(converter, added) =
103 frameContextData.textureConverterMapper.tryMap(rhi, TextureConverter(rhi));
106 Q_ASSERT(converter && added);
117 HwFrameContextData &frameContextData = HwFrameContextData::ensure(*m_hwFrame);
118 return frameContextData.textureConverterMapper.findRhi(
119 [](QRhi &rhi) {
return rhi.thread()->isCurrentThread(); });
124 return fromAvColorSpace(m_frame->colorspace);
129 return fromAvColorTransfer(m_frame->color_trc);
134 return fromAvColorRange(m_frame->color_range);
140 for (
int i = 0; i < m_frame->nb_side_data; ++i) {
141 AVFrameSideData *sd = m_frame->side_data[i];
143 if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
144 auto *data =
reinterpret_cast<AVMasteringDisplayMetadata *>(sd->data);
146 if (!data->has_luminance)
148 auto maybeLum = QFFmpeg::toReal(data->max_luminance);
150 maxNits =
float(*maybeLum);
159 Q_ASSERT(m_hwFrame && m_hwFrame->hw_frames_ctx);
160 m_swFrame = makeAVFrame();
162 int ret = av_hwframe_transfer_data(m_swFrame.get(), m_hwFrame.get(), 0);
164 qWarning() <<
"Error transferring the data to system memory:" << ret;
173 auto *desc = QVideoTextureHelper::textureDescription(pixelFormat());
174 mapData.planeCount = desc->nplanes;
175 for (
int i = 0; i < mapData.planeCount; ++i) {
176 Q_ASSERT(m_swFrame->linesize[i] >= 0);
178 mapData.data[i] = m_swFrame->data[i];
179 mapData.bytesPerLine[i] = m_swFrame->linesize[i];
180 mapData.dataSize[i] = mapData.bytesPerLine[i]*desc->heightForPlane(m_swFrame->height, i);
183 if ((mode & QVideoFrame::WriteOnly) != 0 && m_hwFrame)
193 m_mode = QVideoFrame::NotMapped;
196QVideoFrameTexturesUPtr
QFFmpegVideoBuffer::mapTextures(QRhi &rhi, QVideoFrameTexturesUPtr& oldTextures)
198 Q_ASSERT(rhi.thread()->isCurrentThread());
200 return createTexturesFromHwFrame(rhi, oldTextures);
203QVideoFrameTexturesUPtr
QFFmpegVideoBuffer::createTexturesFromHwFrame(QRhi &rhi, QVideoFrameTexturesUPtr& oldTextures) {
213 constexpr bool initTextureConverterForAnyRhi =
false;
215 TextureConverter *converter = initTextureConverterForAnyRhi
216 ? &ensureTextureConverter(rhi)
217 : HwFrameContextData::ensure(*m_hwFrame).textureConverterMapper.get(&rhi);
222 if (!converter->init(*m_hwFrame))
225 const QVideoFrameTextures *oldTexturesRaw = oldTextures.get();
226 if (QVideoFrameTexturesUPtr newTextures = converter->createTextures(*m_hwFrame, oldTextures))
229 Q_ASSERT(oldTextures.get() == oldTexturesRaw);
231 QVideoFrameTexturesHandlesUPtr oldTextureHandles =
232 oldTextures ? oldTextures->takeHandles() :
nullptr;
233 QVideoFrameTexturesHandlesUPtr newTextureHandles =
234 converter->createTextureHandles(*m_hwFrame,
std::move(oldTextureHandles));
236 if (newTextureHandles) {
237 QVideoFrameTexturesUPtr newTextures = QVideoTextureHelper::createTexturesFromHandles(
238 std::move(newTextureHandles), rhi, m_pixelFormat, frameSize(m_hwFrame));
243 static thread_local int lastFormat = 0;
244 if (std::exchange(lastFormat, m_hwFrame->format) != m_hwFrame->format)
245 qWarning() <<
" failed to get textures for frame; format:" << m_hwFrame->format;
252 return m_pixelFormat;
260QVideoFrameFormat::PixelFormat
QFFmpegVideoBuffer::toQtPixelFormat(AVPixelFormat avPixelFormat,
bool *needsConversion)
263 *needsConversion =
false;
265 switch (avPixelFormat) {
268 case AV_PIX_FMT_NONE:
269 Q_ASSERT(!
"Invalid avPixelFormat!");
270 return QVideoFrameFormat::Format_Invalid;
271 case AV_PIX_FMT_ARGB:
272 return QVideoFrameFormat::Format_ARGB8888;
273 case AV_PIX_FMT_0RGB:
274 return QVideoFrameFormat::Format_XRGB8888;
275 case AV_PIX_FMT_BGRA:
276 return QVideoFrameFormat::Format_BGRA8888;
277 case AV_PIX_FMT_BGR0:
278 return QVideoFrameFormat::Format_BGRX8888;
279 case AV_PIX_FMT_ABGR:
280 return QVideoFrameFormat::Format_ABGR8888;
281 case AV_PIX_FMT_0BGR:
282 return QVideoFrameFormat::Format_XBGR8888;
283 case AV_PIX_FMT_RGBA:
284 return QVideoFrameFormat::Format_RGBA8888;
285 case AV_PIX_FMT_RGB0:
286 return QVideoFrameFormat::Format_RGBX8888;
288 case AV_PIX_FMT_YUV422P:
289 return QVideoFrameFormat::Format_YUV422P;
290 case AV_PIX_FMT_YUV420P:
291 return QVideoFrameFormat::Format_YUV420P;
292 case AV_PIX_FMT_YUV420P10:
293 return QVideoFrameFormat::Format_YUV420P10;
294 case AV_PIX_FMT_UYVY422:
295 return QVideoFrameFormat::Format_UYVY;
296 case AV_PIX_FMT_YUYV422:
297 return QVideoFrameFormat::Format_YUYV;
298 case AV_PIX_FMT_NV12:
299 return QVideoFrameFormat::Format_NV12;
300 case AV_PIX_FMT_NV21:
301 return QVideoFrameFormat::Format_NV21;
302 case AV_PIX_FMT_GRAY8:
303 return QVideoFrameFormat::Format_Y8;
304 case AV_PIX_FMT_GRAY16:
305 return QVideoFrameFormat::Format_Y16;
307 case AV_PIX_FMT_P010:
308 return QVideoFrameFormat::Format_P010;
309 case AV_PIX_FMT_P016:
310 return QVideoFrameFormat::Format_P016;
311 case AV_PIX_FMT_MEDIACODEC:
312 return QVideoFrameFormat::Format_SamplerExternalOES;
316 *needsConversion =
true;
318 const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avPixelFormat);
320 if (descriptor->flags & AV_PIX_FMT_FLAG_RGB)
321 return QVideoFrameFormat::Format_RGBA8888;
323 if (descriptor->comp[0].depth > 8)
324 return QVideoFrameFormat::Format_P016;
325 return QVideoFrameFormat::Format_YUV420P;
330 switch (pixelFormat) {
332 case QVideoFrameFormat::Format_Invalid:
333 case QVideoFrameFormat::Format_AYUV:
334 case QVideoFrameFormat::Format_AYUV_Premultiplied:
335 case QVideoFrameFormat::Format_YV12:
336 case QVideoFrameFormat::Format_IMC1:
337 case QVideoFrameFormat::Format_IMC2:
338 case QVideoFrameFormat::Format_IMC3:
339 case QVideoFrameFormat::Format_IMC4:
340 return AV_PIX_FMT_NONE;
341 case QVideoFrameFormat::Format_Jpeg:
343 return AV_PIX_FMT_BGRA;
344 case QVideoFrameFormat::Format_ARGB8888:
345 return AV_PIX_FMT_ARGB;
346 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
347 case QVideoFrameFormat::Format_XRGB8888:
348 return AV_PIX_FMT_0RGB;
349 case QVideoFrameFormat::Format_BGRA8888:
350 return AV_PIX_FMT_BGRA;
351 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
352 case QVideoFrameFormat::Format_BGRX8888:
353 return AV_PIX_FMT_BGR0;
354 case QVideoFrameFormat::Format_ABGR8888:
355 return AV_PIX_FMT_ABGR;
356 case QVideoFrameFormat::Format_XBGR8888:
357 return AV_PIX_FMT_0BGR;
358 case QVideoFrameFormat::Format_RGBA8888:
359 return AV_PIX_FMT_RGBA;
362 case QVideoFrameFormat::Format_RGBX8888:
363 return AV_PIX_FMT_RGB0;
365 case QVideoFrameFormat::Format_YUV422P:
366 return AV_PIX_FMT_YUV422P;
367 case QVideoFrameFormat::Format_YUV420P:
368 return AV_PIX_FMT_YUV420P;
369 case QVideoFrameFormat::Format_YUV420P10:
370 return AV_PIX_FMT_YUV420P10;
371 case QVideoFrameFormat::Format_UYVY:
372 return AV_PIX_FMT_UYVY422;
373 case QVideoFrameFormat::Format_YUYV:
374 return AV_PIX_FMT_YUYV422;
375 case QVideoFrameFormat::Format_NV12:
376 return AV_PIX_FMT_NV12;
377 case QVideoFrameFormat::Format_NV21:
378 return AV_PIX_FMT_NV21;
379 case QVideoFrameFormat::Format_Y8:
380 return AV_PIX_FMT_GRAY8;
381 case QVideoFrameFormat::Format_Y16:
382 return AV_PIX_FMT_GRAY16;
384 case QVideoFrameFormat::Format_P010:
385 return AV_PIX_FMT_P010;
386 case QVideoFrameFormat::Format_P016:
387 return AV_PIX_FMT_P016;
389 case QVideoFrameFormat::Format_SamplerExternalOES:
390 return AV_PIX_FMT_MEDIACODEC;
QVideoFrameFormat::PixelFormat pixelFormat() const
QVideoFrameFormat::ColorSpace colorSpace() const
void unmap() override
Releases the memory mapped by the map() function.
MapData map(QVideoFrame::MapMode mode) override
Maps the planes of a video buffer to memory.
QVideoFrameFormat::ColorTransfer colorTransfer() const
QVideoFrameFormat::ColorRange colorRange() const
QFFmpegVideoBuffer(AVFrameUPtr frame, AVRational pixelAspectRatio={ 1, 1 })
~QFFmpegVideoBuffer() override
QRhi * associatedCurrentThreadRhi() const override
static bool isFrameFlipped(const AVFrame &frame)
#define qCWarning(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)