@@ -159,7 +159,8 @@ SPOOL_TEST_MAIN("mpv-video-item")
159159 Spool::MpvVideoItem videoItem (window.contentItem ());
160160 // Match production's anchors.fill: parent. UIKit can replace requested
161161 // window geometry asynchronously with the fullscreen television surface.
162- const auto fitSurface = [&] { videoItem.setSize (window.contentItem ()->size ()); };
162+ qreal viewportFraction = 1.0 ;
163+ const auto fitSurface = [&] { videoItem.setSize (window.contentItem ()->size () * viewportFraction); };
163164 QObject::connect (window.contentItem (), &QQuickItem::widthChanged, &videoItem, fitSurface);
164165 QObject::connect (window.contentItem (), &QQuickItem::heightChanged, &videoItem, fitSurface);
165166 fitSurface ();
@@ -174,13 +175,35 @@ SPOOL_TEST_MAIN("mpv-video-item")
174175 },
175176 Qt::DirectConnection);
176177#endif
178+ #ifdef Q_OS_TVOS
179+ window.showFullScreen ();
180+ #else
177181 window.show ();
182+ #endif
178183 app.processEvents ();
184+ const auto captureItem = [&] {
185+ const QImage image = window.grabWindow ();
186+ #ifdef Q_OS_TVOS
187+ if (image.isNull ())
188+ return image;
189+ const qreal xScale = qreal (image.width ()) / window.contentItem ()->width ();
190+ const qreal yScale = qreal (image.height ()) / window.contentItem ()->height ();
191+ return image.copy (0 , 0 , qRound (videoItem.width () * xScale), qRound (videoItem.height () * yScale));
192+ #else
193+ return image;
194+ #endif
195+ };
179196
180197 // Reusing an item after detach must reset first-frame state and publish
181198 // the new context, including when Qt replaces the render target on resize.
182199 for (const QSize size : { QSize (320 , 180 ), QSize (480 , 270 ) }) {
200+ #ifdef Q_OS_TVOS
201+ // UIKit owns the fullscreen native window; resize the real video
202+ // viewport instead of requesting an unsupported television window size.
203+ viewportFraction = size.width () == 320 ? 1.0 : 2.0 / 3.0 ;
204+ #else
183205 window.resize (size);
206+ #endif
184207 fitSurface ();
185208 std::setlocale (LC_NUMERIC , " C" );
186209 mpv_handle *handle = mpv_create ();
@@ -234,7 +257,7 @@ SPOOL_TEST_MAIN("mpv-video-item")
234257 timer.start ();
235258 while (!rendered && timer.elapsed () < 5000 ) {
236259 app.processEvents (QEventLoop::AllEvents, 20 );
237- rendered = isRightWayUp (window. grabWindow ());
260+ rendered = isRightWayUp (captureItem ());
238261 QThread::msleep (10 );
239262 }
240263
@@ -246,7 +269,7 @@ SPOOL_TEST_MAIN("mpv-video-item")
246269 int (display.hdrAvailable ), int (display.preferredFormat ), double (display.sdrWhiteNits ),
247270 double (display.minLuminanceNits ), double (display.maxLuminanceNits ));
248271
249- const bool upright = rendered && isRightWayUp (window. grabWindow ());
272+ const bool upright = rendered && isRightWayUp (captureItem ());
250273 char *pixelFormat = mpv_get_property_string (handle, " video-target-params/pixelformat" );
251274 const QByteArray actualFormat = pixelFormat ? QByteArray (pixelFormat) : QByteArray ();
252275 mpv_free (pixelFormat);
@@ -259,14 +282,14 @@ SPOOL_TEST_MAIN("mpv-video-item")
259282 std::fprintf (stderr, " rendered SDR target: RHI=%d mpv=%s\n " , textureFormat.load (),
260283 actualFormat.isEmpty () ? " (legacy renderer)" : actualFormat.constData ());
261284#endif
262- const QImage beforeOsd = window. grabWindow ();
285+ const QImage beforeOsd = captureItem ();
263286 const char *osdCommand[] = { " show-text" , " SDR white" , " 10000" , nullptr };
264287 bool neutralOsd = false ;
265288 if (mpv_command (handle, osdCommand) >= 0 ) {
266289 timer.restart ();
267290 while (!neutralOsd && timer.elapsed () < 5000 ) {
268291 app.processEvents (QEventLoop::AllEvents, 20 );
269- neutralOsd = containsNeutralOsd (window. grabWindow (), beforeOsd);
292+ neutralOsd = containsNeutralOsd (captureItem (), beforeOsd);
270293 QThread::msleep (10 );
271294 }
272295 }
0 commit comments