media_audio_ffmpeg_loader.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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 "media/audio/media_audio.h"
  9. #include "media/audio/media_audio_loader.h"
  10. #include "media/streaming/media_streaming_utility.h"
  11. extern "C" {
  12. #include <libavcodec/avcodec.h>
  13. #include <libavformat/avformat.h>
  14. #include <libavutil/opt.h>
  15. #include <libswresample/swresample.h>
  16. #include <libavfilter/avfilter.h>
  17. } // extern "C"
  18. #include <al.h>
  19. namespace Core {
  20. class FileLocation;
  21. } // namespace Core
  22. namespace Media {
  23. class AbstractFFMpegLoader : public AudioPlayerLoader {
  24. public:
  25. AbstractFFMpegLoader(
  26. const Core::FileLocation &file,
  27. const QByteArray &data,
  28. bytes::vector &&buffer)
  29. : AudioPlayerLoader(file, data, std::move(buffer)) {
  30. }
  31. bool open(crl::time positionMs, float64 speed = 1.) override;
  32. crl::time duration() override {
  33. return _duration;
  34. }
  35. void overrideDuration(int64 startedAtSample, crl::time duration) {
  36. _startedAtSample = startedAtSample;
  37. _duration = duration;
  38. }
  39. int samplesFrequency() override {
  40. return _samplesFrequency;
  41. }
  42. #if !DA_FFMPEG_NEW_CHANNEL_LAYOUT
  43. static uint64_t ComputeChannelLayout(
  44. uint64_t channel_layout,
  45. int channels);
  46. #endif // !DA_FFMPEG_NEW_CHANNEL_LAYOUT
  47. [[nodiscard]] int64 startedAtSample() const {
  48. return _startedAtSample;
  49. }
  50. ~AbstractFFMpegLoader();
  51. protected:
  52. static int64 Mul(int64 value, AVRational rational);
  53. int _samplesFrequency = Media::Player::kDefaultFrequency;
  54. int64 _startedAtSample = 0;
  55. crl::time _duration = 0;
  56. uchar *ioBuffer = nullptr;
  57. AVIOContext *ioContext = nullptr;
  58. AVFormatContext *fmtContext = nullptr;
  59. #if LIBAVFORMAT_VERSION_MAJOR >= 59
  60. const AVCodec *codec = nullptr;
  61. #else
  62. AVCodec *codec = nullptr;
  63. #endif
  64. int32 streamId = 0;
  65. bool _opened = false;
  66. private:
  67. static int ReadData(void *opaque, uint8_t *buf, int buf_size);
  68. static int64_t SeekData(void *opaque, int64_t offset, int whence);
  69. static int ReadBytes(void *opaque, uint8_t *buf, int buf_size);
  70. static int64_t SeekBytes(void *opaque, int64_t offset, int whence);
  71. static int ReadFile(void *opaque, uint8_t *buf, int buf_size);
  72. static int64_t SeekFile(void *opaque, int64_t offset, int whence);
  73. };
  74. class AbstractAudioFFMpegLoader : public AbstractFFMpegLoader {
  75. public:
  76. AbstractAudioFFMpegLoader(
  77. const Core::FileLocation &file,
  78. const QByteArray &data,
  79. bytes::vector &&buffer);
  80. void dropFramesTill(int64 samples) override;
  81. int64 startReadingQueuedFrames(float64 newSpeed) override;
  82. int samplesFrequency() override {
  83. return _swrDstRate;
  84. }
  85. int sampleSize() override {
  86. return _outputSampleSize;
  87. }
  88. int format() override {
  89. return _outputFormat;
  90. }
  91. ~AbstractAudioFFMpegLoader();
  92. protected:
  93. bool initUsingContext(not_null<AVCodecContext*> context, float64 speed);
  94. [[nodiscard]] ReadResult readFromReadyContext(
  95. not_null<AVCodecContext*> context);
  96. // Streaming player provides the first frame to the ChildFFMpegLoader
  97. // so we replace our allocated frame with the one provided.
  98. [[nodiscard]] ReadResult replaceFrameAndRead(FFmpeg::FramePointer frame);
  99. private:
  100. struct EnqueuedFrame {
  101. int64 position = 0;
  102. int64 samples = 0;
  103. FFmpeg::FramePointer frame;
  104. };
  105. [[nodiscard]] ReadResult readFromReadyFrame();
  106. [[nodiscard]] ReadResult readOrBufferForFilter(
  107. not_null<AVFrame*> frame,
  108. int64 samplesOverride);
  109. bool frameHasDesiredFormat(not_null<AVFrame*> frame) const;
  110. bool initResampleForFrame();
  111. bool initResampleUsingFormat();
  112. bool ensureResampleSpaceAvailable(int samples);
  113. bool changeSpeedFilter(float64 speed);
  114. void createSpeedFilter(float64 speed);
  115. void enqueueNormalFrame(
  116. not_null<AVFrame*> frame,
  117. int64 samples = 0);
  118. void enqueueFramesFinished();
  119. [[nodiscard]] auto fillFrameFromQueued()
  120. -> std::variant<not_null<const EnqueuedFrame*>, ReadError>;
  121. FFmpeg::FramePointer _frame;
  122. FFmpeg::FramePointer _resampledFrame;
  123. FFmpeg::FramePointer _filteredFrame;
  124. int _resampledFrameCapacity = 0;
  125. int64 _framesQueuedSamples = 0;
  126. std::deque<EnqueuedFrame> _framesQueued;
  127. int _framesQueuedIndex = -1;
  128. int _outputFormat = AL_FORMAT_STEREO16;
  129. int _outputChannels = 2;
  130. int _outputSampleSize = 2 * sizeof(uint16);
  131. SwrContext *_swrContext = nullptr;
  132. int _swrSrcRate = 0;
  133. AVSampleFormat _swrSrcSampleFormat = AV_SAMPLE_FMT_NONE;
  134. const int _swrDstRate = Media::Player::kDefaultFrequency;
  135. AVSampleFormat _swrDstSampleFormat = AV_SAMPLE_FMT_S16;
  136. #if DA_FFMPEG_NEW_CHANNEL_LAYOUT
  137. AVChannelLayout _swrSrcChannelLayout = AV_CHANNEL_LAYOUT_STEREO;
  138. AVChannelLayout _swrDstChannelLayout = AV_CHANNEL_LAYOUT_STEREO;
  139. #else // DA_FFMPEG_NEW_CHANNEL_LAYOUT
  140. uint64_t _swrSrcChannelLayout = 0;
  141. uint64_t _swrDstChannelLayout = AV_CH_LAYOUT_STEREO;
  142. #endif // DA_FFMPEG_NEW_CHANNEL_LAYOUT
  143. AVFilterGraph *_filterGraph = nullptr;
  144. float64 _filterSpeed = 1.;
  145. AVFilterContext *_filterSrc = nullptr;
  146. AVFilterContext *_atempo = nullptr;
  147. AVFilterContext *_filterSink = nullptr;
  148. };
  149. class FFMpegLoader : public AbstractAudioFFMpegLoader {
  150. public:
  151. FFMpegLoader(
  152. const Core::FileLocation &file,
  153. const QByteArray &data,
  154. bytes::vector &&buffer);
  155. bool open(crl::time positionMs, float64 speed = 1.) override;
  156. ReadResult readMore() override;
  157. ~FFMpegLoader();
  158. private:
  159. bool openCodecContext();
  160. bool seekTo(crl::time positionMs);
  161. AVCodecContext *_codecContext = nullptr;
  162. AVPacket _packet;
  163. bool _readTillEnd = false;
  164. };
  165. } // namespace Media