6#include <avfvideobuffer_p.h>
7#include <QtMultimedia/private/qavfhelpers_p.h>
8#include "private/qvideoframe_p.h"
10#include <QtMultimedia/qvideoframeformat.h>
12#include <avfvideosink_p.h>
15#include <QtCore/qdebug.h>
17#import <AVFoundation/AVFoundation.h>
18#include <CoreVideo/CVPixelBuffer.h>
19#include <CoreVideo/CVImageBuffer.h>
23@interface SubtitleDelegate : NSObject <AVPlayerItemLegibleOutputPushDelegate>
25 AVFVideoRendererControl *m_renderer;
28- (
void)legibleOutput:(AVPlayerItemLegibleOutput *)output
29 didOutputAttributedStrings:(NSArray<NSAttributedString *> *)strings
30 nativeSampleBuffers:(NSArray *)nativeSamples
31 forItemTime:(CMTime)itemTime;
35@implementation SubtitleDelegate
37-(id)initWithRenderer: (AVFVideoRendererControl *)renderer
39 if (!(self = [super init]))
42 m_renderer = renderer;
47- (
void)legibleOutput:(AVPlayerItemLegibleOutput *)output
48 didOutputAttributedStrings:(NSArray<NSAttributedString *> *)strings
49 nativeSampleBuffers:(NSArray *)nativeSamples
50 forItemTime:(CMTime)itemTime
53 for (NSAttributedString *s : strings) {
55 text += QChar::LineSeparator;
56 text += QString::fromNSString(s.string);
58 m_renderer->setSubtitleText(text);
64AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent)
67 m_displayLink =
new AVFDisplayLink(
this);
69 connect(m_displayLink, &AVFDisplayLink::tick,
this, &AVFVideoRendererControl::updateVideoFrame);
75 qDebug() << Q_FUNC_INFO;
77 m_displayLink->stop();
78 m_displayLink->disconnect(
this);
80 [m_videoOutput release];
82 [m_subtitleOutput release];
83 if (m_subtitleDelegate)
84 [m_subtitleDelegate release];
90 qDebug() <<
"reconfigure";
93 m_displayLink->stop();
97 QMutexLocker locker(&m_mutex);
99 m_displayLink->start();
106 if (m_layer == layer)
109 AVPlayerLayer *plLayer = playerLayer();
112 [[[plLayer player] currentItem] removeOutput:m_videoOutput];
114 if (m_subtitleOutput)
115 [[[plLayer player] currentItem] removeOutput:m_subtitleOutput];
118 if (!layer && m_sink)
119 m_sink->setVideoFrame(QVideoFrame());
121 AVFVideoSinkInterface::setLayer(layer);
126 m_rotation = rotation;
131 m_mirrored = mirrored;
144 auto *layer = playerLayer();
145 if (!layer.readyForDisplay)
150 size_t width, height;
151 QCFType<CVPixelBufferRef> pixelBuffer = copyPixelBufferFromLayer(width, height);
156 auto buffer = std::make_unique<AVFVideoBuffer>(
this, std::move(pixelBuffer));
158 const auto format = buffer->videoFormat();
159 frame = QVideoFramePrivate::createFrame(std::move(buffer), format);
160 frame.setRotation(m_rotation);
161 frame.setMirrored(m_mirrored);
162 m_sink->setVideoFrame(frame);
168 AVPlayerLayer *layer = playerLayer();
172 qWarning(
"copyPixelBufferFromLayer: invalid layer");
177 AVPlayerItem * item = [[layer player] currentItem];
179 if (!m_videoOutput) {
180 if (!m_outputSettings)
182 m_videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:m_outputSettings];
183 [m_videoOutput setDelegate:nil queue:nil];
185 if (!m_subtitleOutput) {
186 m_subtitleOutput = [[AVPlayerItemLegibleOutput alloc] init];
187 m_subtitleDelegate = [[SubtitleDelegate alloc] initWithRenderer:
this];
188 [m_subtitleOutput setDelegate:m_subtitleDelegate queue:dispatch_get_main_queue()];
190 if (![item.outputs containsObject:m_videoOutput])
191 [item addOutput:m_videoOutput];
192 if (![item.outputs containsObject:m_subtitleOutput])
193 [item addOutput:m_subtitleOutput];
195 CFTimeInterval currentCAFrameTime = CACurrentMediaTime();
196 CMTime currentCMFrameTime = [m_videoOutput itemTimeForHostTime:currentCAFrameTime];
198 if (CMTimeCompare(currentCMFrameTime, kCMTimeZero) < 0) {
202 if (![m_videoOutput hasNewPixelBufferForItemTime:currentCMFrameTime])
205 CVPixelBufferRef pixelBuffer = [m_videoOutput copyPixelBufferForItemTime:currentCMFrameTime
206 itemTimeForDisplay:nil];
209 qWarning(
"copyPixelBufferForItemTime returned nil");
210 CMTimeShow(currentCMFrameTime);
215 width = CVPixelBufferGetWidth(pixelBuffer);
216 height = CVPixelBufferGetHeight(pixelBuffer);
222 return QCFType<CVPixelBufferRef>{ pixelBuffer };
225#include "moc_avfvideorenderercontrol_p.cpp"
void setVideoMirrored(bool mirrored)
~AVFVideoRendererControl() override
void setVideoRotation(QtVideo::Rotation)
void reconfigure() override