mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-09 05:03:54 +00:00
130 lines
2.9 KiB
Plaintext
130 lines
2.9 KiB
Plaintext
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
For license and copyright information please follow this link:
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
*/
|
|
#include "media/streaming/media_streaming_native_frame_mac.h"
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
#include "media/streaming/media_streaming_common.h"
|
|
#include "ffmpeg/ffmpeg_utility.h"
|
|
|
|
#include <CoreVideo/CoreVideo.h>
|
|
|
|
namespace Media::Streaming {
|
|
namespace {
|
|
|
|
class PixelBufferLock final {
|
|
public:
|
|
PixelBufferLock(CVPixelBufferRef buffer, CVPixelBufferLockFlags flags)
|
|
: _buffer(buffer)
|
|
, _flags(flags)
|
|
, _locked(CVPixelBufferLockBaseAddress(buffer, flags) == kCVReturnSuccess) {
|
|
}
|
|
|
|
PixelBufferLock(const PixelBufferLock &) = delete;
|
|
PixelBufferLock &operator=(const PixelBufferLock &) = delete;
|
|
PixelBufferLock(PixelBufferLock &&) = delete;
|
|
PixelBufferLock &operator=(PixelBufferLock &&) = delete;
|
|
|
|
~PixelBufferLock() {
|
|
if (_locked) {
|
|
CVPixelBufferUnlockBaseAddress(_buffer, _flags);
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool locked() const {
|
|
return _locked;
|
|
}
|
|
|
|
private:
|
|
CVPixelBufferRef _buffer;
|
|
CVPixelBufferLockFlags _flags;
|
|
bool _locked;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
QImage ConvertNativeFrameToARGB32(const NativeFrame &frame) {
|
|
if (!frame.pixelBuffer || frame.size.isEmpty()) {
|
|
return QImage();
|
|
}
|
|
const auto pixelBuffer = static_cast<CVPixelBufferRef>(frame.pixelBuffer);
|
|
const auto format = CVPixelBufferGetPixelFormatType(pixelBuffer);
|
|
if (format != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
|
|
&& format != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
|
|
return QImage();
|
|
}
|
|
const auto lock = PixelBufferLock(
|
|
pixelBuffer,
|
|
kCVPixelBufferLock_ReadOnly);
|
|
if (!lock.locked()) {
|
|
return QImage();
|
|
}
|
|
|
|
const auto y = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
|
|
const auto uv = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
|
|
if (!y || !uv) {
|
|
return QImage();
|
|
}
|
|
const auto yStride = int(
|
|
CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0));
|
|
const auto uvStride = int(
|
|
CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1));
|
|
if (yStride <= 0 || uvStride <= 0) {
|
|
return QImage();
|
|
}
|
|
|
|
auto storage = FFmpeg::CreateFrameStorage(frame.size);
|
|
if (storage.isNull() || !storage.bits()) {
|
|
return QImage();
|
|
}
|
|
const auto swscale = FFmpeg::MakeSwscalePointer(
|
|
frame.size,
|
|
AV_PIX_FMT_NV12,
|
|
frame.size,
|
|
AV_PIX_FMT_BGRA);
|
|
if (!swscale) {
|
|
return QImage();
|
|
}
|
|
|
|
const uint8_t *srcData[AV_NUM_DATA_POINTERS] = {
|
|
static_cast<const uint8_t*>(y),
|
|
static_cast<const uint8_t*>(uv),
|
|
nullptr,
|
|
nullptr,
|
|
};
|
|
int srcLinesize[AV_NUM_DATA_POINTERS] = {
|
|
yStride,
|
|
uvStride,
|
|
0,
|
|
0,
|
|
};
|
|
uint8_t *dstData[AV_NUM_DATA_POINTERS] = {
|
|
storage.bits(),
|
|
nullptr,
|
|
};
|
|
int dstLinesize[AV_NUM_DATA_POINTERS] = {
|
|
int(storage.bytesPerLine()),
|
|
0,
|
|
};
|
|
sws_scale(
|
|
swscale.get(),
|
|
srcData,
|
|
srcLinesize,
|
|
0,
|
|
frame.size.height(),
|
|
dstData,
|
|
dstLinesize);
|
|
|
|
return storage;
|
|
}
|
|
|
|
} // namespace Media::Streaming
|
|
|
|
#endif // Q_OS_MAC
|