28 switch (pixelFormat) {
30 case QVideoFrameFormat::Format_Invalid:
31 return AV_PIX_FMT_NONE;
32 case QVideoFrameFormat::Format_AYUV:
33 case QVideoFrameFormat::Format_AYUV_Premultiplied:
34 return AV_PIX_FMT_NONE;
35 case QVideoFrameFormat::Format_YV12:
36 case QVideoFrameFormat::Format_IMC1:
37 case QVideoFrameFormat::Format_IMC3:
38 case QVideoFrameFormat::Format_IMC2:
39 case QVideoFrameFormat::Format_IMC4:
40 return AV_PIX_FMT_YUV420P;
41 case QVideoFrameFormat::Format_Jpeg:
42 return AV_PIX_FMT_BGRA;
43 case QVideoFrameFormat::Format_ARGB8888:
44 return AV_PIX_FMT_ARGB;
45 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
46 case QVideoFrameFormat::Format_XRGB8888:
47 return AV_PIX_FMT_0RGB;
48 case QVideoFrameFormat::Format_BGRA8888:
49 return AV_PIX_FMT_BGRA;
50 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
51 case QVideoFrameFormat::Format_BGRX8888:
52 return AV_PIX_FMT_BGR0;
53 case QVideoFrameFormat::Format_ABGR8888:
54 return AV_PIX_FMT_ABGR;
55 case QVideoFrameFormat::Format_XBGR8888:
56 return AV_PIX_FMT_0BGR;
57 case QVideoFrameFormat::Format_RGBA8888:
58 return AV_PIX_FMT_RGBA;
59 case QVideoFrameFormat::Format_RGBX8888:
60 return AV_PIX_FMT_RGB0;
61 case QVideoFrameFormat::Format_YUV422P:
62 return AV_PIX_FMT_YUV422P;
63 case QVideoFrameFormat::Format_YUV420P:
64 return AV_PIX_FMT_YUV420P;
65 case QVideoFrameFormat::Format_YUV420P10:
66 return AV_PIX_FMT_YUV420P10;
67 case QVideoFrameFormat::Format_UYVY:
68 return AV_PIX_FMT_UYVY422;
69 case QVideoFrameFormat::Format_YUYV:
70 return AV_PIX_FMT_YUYV422;
71 case QVideoFrameFormat::Format_NV12:
72 return AV_PIX_FMT_NV12;
73 case QVideoFrameFormat::Format_NV21:
74 return AV_PIX_FMT_NV21;
75 case QVideoFrameFormat::Format_Y8:
76 return AV_PIX_FMT_GRAY8;
77 case QVideoFrameFormat::Format_Y16:
78 return AV_PIX_FMT_GRAY16;
79 case QVideoFrameFormat::Format_P010:
80 return AV_PIX_FMT_P010;
81 case QVideoFrameFormat::Format_P016:
82 return AV_PIX_FMT_P016;
83 case QVideoFrameFormat::Format_SamplerExternalOES:
84 return AV_PIX_FMT_MEDIACODEC;
97 switch (dst.pixelFormat()) {
98 case QVideoFrameFormat::Format_YV12:
99 case QVideoFrameFormat::Format_IMC1:
100 return { { dst.bits(0), dst.bits(2), dst.bits(1),
nullptr },
101 { dst.bytesPerLine(0), dst.bytesPerLine(2), dst.bytesPerLine(1), 0 } };
103 case QVideoFrameFormat::Format_IMC2:
104 return { { dst.bits(0), dst.bits(1) + dst.bytesPerLine(1) / 2, dst.bits(1),
nullptr },
105 { dst.bytesPerLine(0), dst.bytesPerLine(1), dst.bytesPerLine(1), 0 } };
107 case QVideoFrameFormat::Format_IMC4:
108 return { { dst.bits(0), dst.bits(1), dst.bits(1) + dst.bytesPerLine(1) / 2,
nullptr },
109 { dst.bytesPerLine(0), dst.bytesPerLine(1), dst.bytesPerLine(1), 0 } };
111 return { { dst.bits(0), dst.bits(1), dst.bits(2),
nullptr },
112 { dst.bytesPerLine(0), dst.bytesPerLine(1), dst.bytesPerLine(2), 0 } };
126 QVideoFrameFormat::ColorSpace colorSpace)
128 const int avRange = colorRange == QVideoFrameFormat::ColorRange_Video ? 0 : 1;
130 switch (colorSpace) {
131 case QVideoFrameFormat::ColorSpace_BT601:
132 if (colorRange == QVideoFrameFormat::ColorRange_Full)
133 return { SWS_CS_ITU709, 1 };
134 return { SWS_CS_ITU601, 0 };
135 case QVideoFrameFormat::ColorSpace_BT709:
136 return { SWS_CS_ITU709, avRange };
137 case QVideoFrameFormat::ColorSpace_AdobeRgb:
138 return { SWS_CS_ITU601, 1 };
139 case QVideoFrameFormat::ColorSpace_BT2020:
140 return { SWS_CS_BT2020, avRange };
141 case QVideoFrameFormat::ColorSpace_Undefined:
143 return { SWS_CS_DEFAULT, avRange };
152 const QSize &dstSize, PixelFormat dstPixFmt)
154 return QFFmpeg::createSwsContext(srcSize, toAVPixelFormat(srcPixFmt), dstSize, toAVPixelFormat(dstPixFmt), SWS_BILINEAR);
158 const QVideoFrameFormat &srcFormat,
159 const QVideoFrameFormat &dstFormat)
161 const SwsColorSpace src = toSwsColorSpace(srcFormat.colorRange(), srcFormat.colorSpace());
162 const SwsColorSpace dst = toSwsColorSpace(dstFormat.colorRange(), dstFormat.colorSpace());
164 constexpr int brightness = 0;
165 constexpr int contrast = 0;
166 constexpr int saturation = 0;
167 const int status = sws_setColorspaceDetails(context,
170 brightness, contrast, saturation);
175bool convert(SwsContext *context, QVideoFrame &src,
int srcHeight, QVideoFrame &dst)
177 if (!src.map(QVideoFrame::ReadOnly))
180 QScopeGuard unmapSrc{[&] {
184 if (!dst.map(QVideoFrame::WriteOnly))
187 QScopeGuard unmapDst{[&] {
194 constexpr int firstSrcSliceRow = 0;
195 const int scaledHeight = sws_scale(context,
196 srcData.bits.data(), srcData.stride.data(),
197 firstSrcSliceRow, srcHeight,
198 dstData.bits.data(), dstData.stride.data());
200 if (scaledHeight != srcHeight)
209 const auto* srcDesc = QVideoTextureHelper::textureDescription(srcFmt);
210 const auto* dstDesc = QVideoTextureHelper::textureDescription(dstFmt);
213 for (
const auto desc : { srcDesc, dstDesc }) {
214 for (
int i = 0; i < desc->nplanes; ++i) {
216 if (desc->sizeScale[i].x != 1)
217 output.setWidth(output.width() & ~1);
219 if (desc->sizeScale[i].y != 1)
220 output.setHeight(output.height() & ~1);
230QVideoFrame
convertFrame(QVideoFrame &src,
const QVideoFrameFormat &dstFormat)
232 if (src.size() != dstFormat.frameSize()) {
233 qCCritical(lc) <<
"Resizing is not supported";
238 const QSize size = adjustSize(src.size(), src.pixelFormat(), dstFormat.pixelFormat());
239 if (size != src.size())
240 qCWarning(lc) <<
"Input truncated to even width/height";
242 const QFFmpeg::SwsContextUPtr conv = createConverter(
243 size, src.pixelFormat(), size, dstFormat.pixelFormat());
246 qCCritical(lc) <<
"Failed to create SW converter";
250 if (!setColorSpaceDetails(conv.get(), src.surfaceFormat(), dstFormat)) {
251 qCCritical(lc) <<
"Failed to set color space details";
255 QVideoFrame dst{ dstFormat };
257 if (!convert(conv.get(), src, size.height(), dst)) {
258 qCCritical(lc) <<
"Frame conversion failed";