ffmpeg_utility.h 6.8 KB

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