1 /* 2 This file is part of Telegram Desktop, 3 the official desktop application for the Telegram messaging service. 4 5 For license and copyright information please follow this link: 6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL 7 */ 8 #pragma once 9 10 #include "base/bytes.h" 11 #include "base/algorithm.h" 12 13 #include <crl/crl_time.h> 14 15 #include <QSize> 16 #include <QString> 17 18 extern "C" { 19 #include <libavcodec/avcodec.h> 20 #include <libavformat/avformat.h> 21 #include <libswscale/swscale.h> 22 } // extern "C" 23 24 class QImage; 25 26 namespace FFmpeg { 27 28 inline constexpr auto kPixelBytesSize = 4; 29 inline constexpr auto kAVBlockSize = 4096; // 4Kb for ffmpeg blocksize 30 31 constexpr auto kUniversalTimeBase = AVRational{ 1, AV_TIME_BASE }; 32 constexpr auto kNormalAspect = AVRational{ 1, 1 }; 33 34 class AvErrorWrap { 35 public: _code(code)36 AvErrorWrap(int code = 0) : _code(code) { 37 } 38 failed()39 [[nodiscard]] bool failed() const { 40 return (_code < 0); 41 } 42 [[nodiscard]] explicit operator bool() const { 43 return failed(); 44 } 45 code()46 [[nodiscard]] int code() const { 47 return _code; 48 } 49 text()50 [[nodiscard]] QString text() const { 51 char string[AV_ERROR_MAX_STRING_SIZE] = { 0 }; 52 return QString::fromUtf8(av_make_error_string( 53 string, 54 sizeof(string), 55 _code)); 56 } 57 58 private: 59 int _code = 0; 60 61 }; 62 63 class Packet { 64 public: 65 Packet() = default; Packet(Packet && other)66 Packet(Packet &&other) : _data(base::take(other._data)) { 67 } 68 Packet &operator=(Packet &&other) { 69 if (this != &other) { 70 release(); 71 _data = base::take(other._data); 72 } 73 return *this; 74 } ~Packet()75 ~Packet() { 76 release(); 77 } 78 fields()79 [[nodiscard]] AVPacket &fields() { 80 if (!_data) { 81 _data = av_packet_alloc(); 82 } 83 return *_data; 84 } fields()85 [[nodiscard]] const AVPacket &fields() const { 86 if (!_data) { 87 _data = av_packet_alloc(); 88 } 89 return *_data; 90 } 91 empty()92 [[nodiscard]] bool empty() const { 93 return !_data || !fields().data; 94 } release()95 void release() { 96 av_packet_free(&_data); 97 } 98 99 private: 100 mutable AVPacket *_data = nullptr; 101 102 }; 103 104 struct IODeleter { 105 void operator()(AVIOContext *value); 106 }; 107 using IOPointer = std::unique_ptr<AVIOContext, IODeleter>; 108 [[nodiscard]] IOPointer MakeIOPointer( 109 void *opaque, 110 int(*read)(void *opaque, uint8_t *buffer, int bufferSize), 111 int(*write)(void *opaque, uint8_t *buffer, int bufferSize), 112 int64_t(*seek)(void *opaque, int64_t offset, int whence)); 113 114 struct FormatDeleter { 115 void operator()(AVFormatContext *value); 116 }; 117 using FormatPointer = std::unique_ptr<AVFormatContext, FormatDeleter>; 118 [[nodiscard]] FormatPointer MakeFormatPointer( 119 void *opaque, 120 int(*read)(void *opaque, uint8_t *buffer, int bufferSize), 121 int(*write)(void *opaque, uint8_t *buffer, int bufferSize), 122 int64_t(*seek)(void *opaque, int64_t offset, int whence)); 123 124 struct CodecDeleter { 125 void operator()(AVCodecContext *value); 126 }; 127 using CodecPointer = std::unique_ptr<AVCodecContext, CodecDeleter>; 128 [[nodiscard]] CodecPointer MakeCodecPointer(not_null<AVStream*> stream); 129 130 struct FrameDeleter { 131 void operator()(AVFrame *value); 132 }; 133 using FramePointer = std::unique_ptr<AVFrame, FrameDeleter>; 134 [[nodiscard]] FramePointer MakeFramePointer(); 135 [[nodiscard]] bool FrameHasData(AVFrame *frame); 136 void ClearFrameMemory(AVFrame *frame); 137 138 struct SwscaleDeleter { 139 QSize srcSize; 140 int srcFormat = int(AV_PIX_FMT_NONE); 141 QSize dstSize; 142 int dstFormat = int(AV_PIX_FMT_NONE); 143 144 void operator()(SwsContext *value); 145 }; 146 using SwscalePointer = std::unique_ptr<SwsContext, SwscaleDeleter>; 147 [[nodiscard]] SwscalePointer MakeSwscalePointer( 148 QSize srcSize, 149 int srcFormat, 150 QSize dstSize, 151 int dstFormat, // This field doesn't take part in caching! 152 SwscalePointer *existing = nullptr); 153 [[nodiscard]] SwscalePointer MakeSwscalePointer( 154 not_null<AVFrame*> frame, 155 QSize resize, 156 SwscalePointer *existing = nullptr); 157 158 void LogError(QLatin1String method); 159 void LogError(QLatin1String method, FFmpeg::AvErrorWrap error); 160 161 [[nodiscard]] crl::time PtsToTime(int64_t pts, AVRational timeBase); 162 // Used for full duration conversion. 163 [[nodiscard]] crl::time PtsToTimeCeil(int64_t pts, AVRational timeBase); 164 [[nodiscard]] int64_t TimeToPts(crl::time time, AVRational timeBase); 165 [[nodiscard]] crl::time PacketPosition( 166 const FFmpeg::Packet &packet, 167 AVRational timeBase); 168 [[nodiscard]] crl::time PacketDuration( 169 const FFmpeg::Packet &packet, 170 AVRational timeBase); 171 [[nodiscard]] int DurationByPacket( 172 const FFmpeg::Packet &packet, 173 AVRational timeBase); 174 [[nodiscard]] int ReadRotationFromMetadata(not_null<AVStream*> stream); 175 [[nodiscard]] AVRational ValidateAspectRatio(AVRational aspect); 176 [[nodiscard]] bool RotationSwapWidthHeight(int rotation); 177 [[nodiscard]] QSize CorrectByAspect(QSize size, AVRational aspect); 178 179 [[nodiscard]] bool GoodStorageForFrame(const QImage &storage, QSize size); 180 [[nodiscard]] QImage CreateFrameStorage(QSize size); 181 182 void UnPremultiply(QImage &to, const QImage &from); 183 void PremultiplyInplace(QImage &image); 184 185 } // namespace FFmpeg 186