AudioStream.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #include "AudioStream.h"
  2. #include "WallpaperEngine/Logging/Log.h"
  3. #include <cassert>
  4. #include <cmath>
  5. #include <iostream>
  6. // maximum size of the queue to prevent reading too much data
  7. using namespace WallpaperEngine::Audio;
  8. int audio_read_thread (void* arg) {
  9. SDL_mutex* waitMutex = SDL_CreateMutex ();
  10. auto* stream = static_cast<AudioStream*> (arg);
  11. AVPacket* packet = av_packet_alloc ();
  12. int ret = 0;
  13. if (waitMutex == nullptr)
  14. sLog.exception ("Cannot create mutex for audio playback waiting");
  15. while (ret >= 0 && stream->getAudioContext ().getApplicationContext ().state.general.keepRunning) {
  16. // give the cpu some time to play the queued frames if there's enough info there
  17. if (stream->getQueueSize () >= MAX_QUEUE_SIZE ||
  18. (stream->getQueuePacketCount () > MIN_FRAMES &&
  19. (av_q2d (stream->getTimeBase ()) * stream->getQueueDuration () > 1.0))) {
  20. SDL_LockMutex (waitMutex);
  21. SDL_CondWaitTimeout (stream->getWaitCondition (), waitMutex, 10);
  22. SDL_UnlockMutex (waitMutex);
  23. continue;
  24. }
  25. ret = av_read_frame (stream->getFormatContext (), packet);
  26. if (ret == AVERROR_EOF) {
  27. // seek to the beginning of the file again
  28. avformat_seek_file (stream->getFormatContext (), stream->getAudioStream (), 0, 0, 0, ~AVSEEK_FLAG_FRAME);
  29. avcodec_flush_buffers (stream->getContext ());
  30. // ensure the thread is not killed if audio has to be looped
  31. if (stream->isRepeat ())
  32. ret = 0;
  33. continue;
  34. }
  35. // TODO: PROPERLY IMPLEMENT THIS
  36. if (packet->stream_index == stream->getAudioStream ())
  37. stream->queuePacket (packet);
  38. else
  39. av_packet_unref (packet);
  40. if (!stream->isInitialized ())
  41. break;
  42. }
  43. // stop the audio too just in case
  44. stream->stop ();
  45. SDL_DestroyMutex (waitMutex);
  46. return 0;
  47. }
  48. static int audio_read_data_callback (void* streamarg, uint8_t* buffer, int buffer_size) {
  49. const auto stream = static_cast<AudioStream*> (streamarg);
  50. // check if we're at eof and return the right value
  51. if (stream->getBuffer ()->eof ()) {
  52. return AVERROR_EOF;
  53. }
  54. stream->getBuffer ()->read (reinterpret_cast<std::istream::char_type*> (buffer), buffer_size);
  55. if (stream->getBuffer ()->fail () && !stream->getBuffer ()->eof ()) {
  56. return AVERROR_INVALIDDATA;
  57. }
  58. // return read bytes only
  59. return stream->getBuffer ()->gcount ();
  60. }
  61. int64_t audio_seek_data_callback (void* streamarg, int64_t offset, int whence) {
  62. const auto stream = static_cast<AudioStream*> (streamarg);
  63. // reset error state
  64. stream->getBuffer ()->clear ();
  65. if (whence & AVSEEK_SIZE) {
  66. const auto current = stream->getBuffer ()->tellg ();
  67. stream->getBuffer ()->seekg (0, std::ios_base::end);
  68. const auto end = stream->getBuffer ()->tellg ();
  69. stream->getBuffer ()->seekg (current, std::ios_base::beg);
  70. return end;
  71. }
  72. switch (whence) {
  73. case SEEK_CUR: stream->getBuffer ()->seekg (offset, std::ios_base::cur); break;
  74. case SEEK_SET: stream->getBuffer ()->seekg (offset, std::ios_base::beg); break;
  75. case SEEK_END: stream->getBuffer ()->seekg (offset, std::ios_base::end); break;
  76. }
  77. return 0;
  78. }
  79. AudioStream::AudioStream (AudioContext& context, const std::string& filename) :
  80. m_audioContext (context) {
  81. this->loadCustomContent (filename.c_str ());
  82. }
  83. AudioStream::AudioStream (AudioContext& context, const ReadStreamSharedPtr& buffer) :
  84. m_audioContext (context) {
  85. // setup a custom context first
  86. this->m_formatContext = avformat_alloc_context ();
  87. if (this->m_formatContext == nullptr)
  88. sLog.exception ("Cannot allocate ffmpeg format context");
  89. this->m_buffer = buffer;
  90. // setup custom io for it
  91. this->m_formatContext->pb = avio_alloc_context (static_cast<uint8_t*> (av_malloc (4096)), 4096, 0, this,
  92. &audio_read_data_callback, nullptr, &audio_seek_data_callback);
  93. if (this->m_formatContext->pb == nullptr)
  94. sLog.exception ("Cannot create avio context");
  95. // continue the normal load procedure
  96. this->loadCustomContent ();
  97. }
  98. AudioStream::AudioStream (AudioContext& audioContext, AVCodecContext* context) :
  99. m_audioContext (audioContext),
  100. m_context (context),
  101. m_queue (new PacketQueue) {
  102. this->initialize ();
  103. }
  104. AudioStream::~AudioStream () {
  105. if (this->m_swrctx != nullptr && swr_is_initialized (this->m_swrctx) == true)
  106. swr_close (this->m_swrctx);
  107. if (this->m_swrctx != nullptr)
  108. swr_free (&this->m_swrctx);
  109. // TODO: FREE EVERYTHING ELSE THAT THIS CLASS HOLDS!
  110. }
  111. void AudioStream::loadCustomContent (const char* filename) {
  112. if (avformat_open_input (&this->m_formatContext, filename, nullptr, nullptr) != 0)
  113. sLog.exception ("Cannot open audio file: ", filename);
  114. if (avformat_find_stream_info (this->m_formatContext, nullptr) < 0)
  115. sLog.exception ("Cannot determine file format: ", filename);
  116. // find the audio stream
  117. for (unsigned int i = 0; i < this->m_formatContext->nb_streams; i++) {
  118. if (this->m_formatContext->streams [i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && this->m_audioStream == NO_AUDIO_STREAM) {
  119. this->m_audioStream = i;
  120. }
  121. }
  122. if (this->m_audioStream == NO_AUDIO_STREAM)
  123. sLog.exception ("Cannot find an audio stream in file ", filename);
  124. // get the decoder for it and alloc the required context
  125. const AVCodec* aCodec =
  126. avcodec_find_decoder (this->m_formatContext->streams [this->m_audioStream]->codecpar->codec_id);
  127. if (aCodec == nullptr)
  128. sLog.exception ("Cannot initialize audio decoder for file: ", filename);
  129. // alocate context
  130. AVCodecContext* avCodecContext = avcodec_alloc_context3 (aCodec);
  131. if (avcodec_parameters_to_context (avCodecContext,
  132. this->m_formatContext->streams [this->m_audioStream]->codecpar) != 0)
  133. sLog.exception ("Cannot initialize audio decoder parameters");
  134. // finally open
  135. avcodec_open2 (avCodecContext, aCodec, nullptr);
  136. // initialize default data
  137. this->m_context = avCodecContext;
  138. this->m_queue = new PacketQueue;
  139. this->initialize ();
  140. // initialize an SDL thread to read the file
  141. SDL_CreateThread (audio_read_thread, filename, this);
  142. }
  143. void AudioStream::initialize () {
  144. // allocate the FIFO buffer
  145. #if FF_API_FIFO_OLD_API
  146. this->m_queue->packetList = av_fifo_alloc (sizeof (MyAVPacketList));
  147. #else
  148. this->m_queue->packetList = av_fifo_alloc2 (1, sizeof (MyAVPacketList), AV_FIFO_FLAG_AUTO_GROW);
  149. #endif
  150. #if FF_API_OLD_CHANNEL_LAYOUT
  151. int64_t out_channel_layout;
  152. // set output audio channels based on the input audio channels
  153. switch (this->m_audioContext.getChannels ()) {
  154. case 1: out_channel_layout = AV_CH_LAYOUT_MONO; break;
  155. case 2: out_channel_layout = AV_CH_LAYOUT_STEREO; break;
  156. default: out_channel_layout = AV_CH_LAYOUT_SURROUND; break;
  157. }
  158. // initialize swrctx
  159. this->m_swrctx = swr_alloc_set_opts (nullptr, out_channel_layout, this->m_audioContext.getFormat (),
  160. this->m_audioContext.getSampleRate (), this->getContext ()->channel_layout,
  161. this->getContext ()->sample_fmt, this->getContext ()->sample_rate, 0, nullptr);
  162. #else
  163. AVChannelLayout out_channel_layout;
  164. int64_t out_channel_mask;
  165. // set output audio channels based on the input audio channels
  166. switch (this->m_audioContext.getChannels ()) {
  167. case 1: out_channel_mask = AV_CH_LAYOUT_MONO; break;
  168. case 2: out_channel_mask = AV_CH_LAYOUT_STEREO; break;
  169. default: out_channel_mask = AV_CH_LAYOUT_SURROUND; break;
  170. }
  171. if (av_channel_layout_from_mask (&out_channel_layout, out_channel_mask) != 0)
  172. sLog.exception ("Cannot get channel layout from mask");
  173. swr_alloc_set_opts2 (&this->m_swrctx, &out_channel_layout, this->m_audioContext.getFormat (),
  174. this->m_audioContext.getSampleRate (), &this->m_context->ch_layout,
  175. this->m_context->sample_fmt, this->m_context->sample_rate, 0, nullptr);
  176. #endif
  177. if (this->m_swrctx == nullptr)
  178. sLog.exception ("Cannot initialize swrctx for audio resampling");
  179. // initialize the context
  180. if (swr_init (this->m_swrctx) < 0)
  181. sLog.exception ("Failed to initialize the resampling context.");
  182. // setup the queue information
  183. this->m_queue->mutex = SDL_CreateMutex ();
  184. this->m_queue->cond = SDL_CreateCond ();
  185. this->m_queue->wait = SDL_CreateCond ();
  186. this->m_initialized = true;
  187. }
  188. void AudioStream::queuePacket (AVPacket* pkt) {
  189. // clone the packet
  190. AVPacket* clone = av_packet_alloc ();
  191. if (clone == nullptr) {
  192. av_packet_unref (clone);
  193. return;
  194. }
  195. av_packet_move_ref (clone, pkt);
  196. SDL_LockMutex (this->m_queue->mutex);
  197. const bool gotQueued = this->doQueue (clone);
  198. SDL_UnlockMutex (this->m_queue->mutex);
  199. if (!gotQueued)
  200. av_packet_free (&pkt);
  201. }
  202. bool AudioStream::doQueue (AVPacket* pkt) {
  203. MyAVPacketList entry {pkt};
  204. #if FF_API_FIFO_OLD_API
  205. if (av_fifo_space (this->m_queue->packetList) < static_cast <int> (sizeof (entry)))
  206. if (av_fifo_grow (this->m_queue->packetList, sizeof (entry)) < 0)
  207. return false;
  208. av_fifo_generic_write (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
  209. #else
  210. // write the entry if possible
  211. if (av_fifo_write (this->m_queue->packetList, &entry, 1) < 0)
  212. return false;
  213. #endif
  214. this->m_queue->nb_packets++;
  215. this->m_queue->size += entry.packet->size + sizeof (entry);
  216. this->m_queue->duration += entry.packet->duration;
  217. SDL_CondSignal (this->m_queue->cond);
  218. return true;
  219. }
  220. void AudioStream::dequeuePacket (AVPacket* output) {
  221. MyAVPacketList entry{};
  222. SDL_LockMutex (this->m_queue->mutex);
  223. while (this->m_audioContext.getApplicationContext ().state.general.keepRunning) {
  224. #if FF_API_FIFO_OLD_API
  225. int ret = -1;
  226. if (av_fifo_size (this->m_queue->packetList) >= static_cast <int> (sizeof (entry)))
  227. ret = av_fifo_generic_read (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
  228. #else
  229. const int ret = av_fifo_read (this->m_queue->packetList, &entry, 1);
  230. #endif
  231. // enough data available, read it
  232. if (ret >= 0) {
  233. this->m_queue->nb_packets--;
  234. this->m_queue->size -= entry.packet->size + sizeof (entry);
  235. this->m_queue->duration -= entry.packet->duration;
  236. // move the reference and free the old one
  237. av_packet_move_ref (output, entry.packet);
  238. av_packet_free (&entry.packet);
  239. break;
  240. }
  241. // make the thread wait if nothing was available
  242. SDL_CondWait (this->m_queue->cond, this->m_queue->mutex);
  243. }
  244. SDL_UnlockMutex (this->m_queue->mutex);
  245. }
  246. AVCodecContext* AudioStream::getContext () const {
  247. return this->m_context;
  248. }
  249. AVFormatContext* AudioStream::getFormatContext () const {
  250. return this->m_formatContext;
  251. }
  252. int AudioStream::getAudioStream () const {
  253. return this->m_audioStream;
  254. }
  255. bool AudioStream::isInitialized () const {
  256. return this->m_initialized;
  257. }
  258. void AudioStream::setRepeat (const bool newRepeat) {
  259. this->m_repeat = newRepeat;
  260. }
  261. bool AudioStream::isRepeat () const {
  262. return this->m_repeat;
  263. }
  264. ReadStreamSharedPtr& AudioStream::getBuffer () {
  265. return this->m_buffer;
  266. }
  267. SDL_cond* AudioStream::getWaitCondition () const {
  268. return this->m_queue->wait;
  269. }
  270. int AudioStream::getQueueSize () const {
  271. return this->m_queue->size;
  272. }
  273. int AudioStream::getQueuePacketCount () const {
  274. return this->m_queue->nb_packets;
  275. }
  276. AVRational AudioStream::getTimeBase () const {
  277. if (this->m_audioStream == NO_AUDIO_STREAM) {
  278. return {0, 0};
  279. }
  280. return this->m_formatContext->streams [this->m_audioStream]->time_base;
  281. }
  282. int64_t AudioStream::getQueueDuration () const {
  283. return this->m_queue->duration;
  284. }
  285. bool AudioStream::isQueueEmpty () const {
  286. return this->m_queue->nb_packets == 0;
  287. }
  288. SDL_mutex* AudioStream::getMutex () const {
  289. return this->m_queue->mutex;
  290. }
  291. void AudioStream::stop () {
  292. if (!this->isInitialized ())
  293. return;
  294. // stop the threads running
  295. this->m_initialized = false;
  296. }
  297. int AudioStream::resampleAudio (const AVFrame* decoded_audio_frame, uint8_t* out_buf) {
  298. int out_linesize = 0;
  299. int ret;
  300. int out_nb_channels;
  301. int out_nb_samples;
  302. uint8_t** resampled_data = nullptr;
  303. int resampled_data_size;
  304. // retrieve number of audio samples (per channel)
  305. const int in_nb_samples = decoded_audio_frame->nb_samples;
  306. if (in_nb_samples <= 0) {
  307. sLog.error ("in_nb_samples error.");
  308. return -1;
  309. }
  310. int max_out_nb_samples = out_nb_samples = av_rescale_rnd (in_nb_samples, this->m_audioContext.getSampleRate (),
  311. this->getContext ()->sample_rate, AV_ROUND_UP);
  312. // check rescaling was successful
  313. if (max_out_nb_samples <= 0) {
  314. sLog.error ("av_rescale_rnd error.");
  315. return -1;
  316. }
  317. // get number of output audio channels
  318. #if FF_API_OLD_CHANNEL_LAYOUT
  319. int64_t out_channel_layout;
  320. // set output audio channels based on the input audio channels
  321. switch (this->m_audioContext.getChannels ()) {
  322. case 1: out_channel_layout = AV_CH_LAYOUT_MONO; break;
  323. case 2: out_channel_layout = AV_CH_LAYOUT_STEREO; break;
  324. default: out_channel_layout = AV_CH_LAYOUT_SURROUND; break;
  325. }
  326. out_nb_channels = av_get_channel_layout_nb_channels (out_channel_layout);
  327. #else
  328. out_nb_channels = this->getContext ()->ch_layout.nb_channels;
  329. #endif
  330. ret = av_samples_alloc_array_and_samples (&resampled_data, &out_linesize, out_nb_channels, out_nb_samples,
  331. this->m_audioContext.getFormat (), 0);
  332. if (ret < 0) {
  333. sLog.error ("av_samples_alloc_array_and_samples() error: Could not allocate destination samples.");
  334. return -1;
  335. }
  336. // retrieve output samples number taking into account the progressive delay
  337. out_nb_samples =
  338. av_rescale_rnd (swr_get_delay (this->m_swrctx, this->getContext ()->sample_rate) + in_nb_samples,
  339. this->m_audioContext.getSampleRate (), this->getContext ()->sample_rate, AV_ROUND_UP);
  340. // check output samples number was correctly retrieved
  341. if (out_nb_samples <= 0) {
  342. sLog.error ("av_rescale_rnd error");
  343. return -1;
  344. }
  345. if (out_nb_samples > max_out_nb_samples) {
  346. // free memory block and set pointer to NULL
  347. av_freep (&resampled_data [0]);
  348. // Allocate a samples buffer for out_nb_samples samples
  349. ret = av_samples_alloc (resampled_data, &out_linesize, out_nb_channels, out_nb_samples,
  350. this->m_audioContext.getFormat (), 1);
  351. // check samples buffer correctly allocated
  352. if (ret < 0) {
  353. sLog.error ("av_samples_alloc failed.");
  354. return -1;
  355. }
  356. max_out_nb_samples = out_nb_samples;
  357. }
  358. // do the actual audio data resampling
  359. ret = swr_convert (this->m_swrctx, resampled_data, max_out_nb_samples,
  360. decoded_audio_frame->data, decoded_audio_frame->nb_samples);
  361. // check audio conversion was successful
  362. if (ret < 0) {
  363. sLog.error ("swr_convert_error.");
  364. return -1;
  365. }
  366. // Get the required buffer size for the given audio parameters
  367. resampled_data_size =
  368. av_samples_get_buffer_size (&out_linesize, out_nb_channels, ret, this->m_audioContext.getFormat (), 1);
  369. // check audio buffer size
  370. if (resampled_data_size < 0) {
  371. sLog.error ("av_samples_get_buffer_size error.");
  372. return -1;
  373. }
  374. // copy the resampled data to the output buffer
  375. memcpy (out_buf, resampled_data [0], resampled_data_size);
  376. /*
  377. * Memory Cleanup.
  378. */
  379. if (resampled_data) {
  380. // free memory block and set pointer to NULL
  381. av_freep (&resampled_data [0]);
  382. }
  383. av_freep (&resampled_data);
  384. return resampled_data_size;
  385. }
  386. int AudioStream::decodeFrame (uint8_t* audioBuffer, const int bufferSize) {
  387. static AVPacket* pkt = av_packet_alloc ();
  388. static uint8_t* audio_pkt_data = nullptr;
  389. static int audio_pkt_size = 0;
  390. int len1, data_size;
  391. // allocate a new frame, used to decode audio packets
  392. static AVFrame* avFrame = av_frame_alloc ();
  393. if (!avFrame) {
  394. sLog.error ("Could not allocate AVFrame.\n");
  395. return -1;
  396. }
  397. // block until there's any data in the buffers
  398. while (this->m_audioContext.getApplicationContext ().state.general.keepRunning) {
  399. while (audio_pkt_size > 0 && this->m_audioContext.getApplicationContext ().state.general.keepRunning) {
  400. int got_frame = 0;
  401. int ret = avcodec_receive_frame (this->getContext (), avFrame);
  402. if (ret == 0)
  403. got_frame = 1;
  404. if (ret == AVERROR (EAGAIN))
  405. ret = 0;
  406. if (ret == 0)
  407. ret = avcodec_send_packet (this->getContext (), pkt);
  408. if (ret < 0 && ret != AVERROR (EAGAIN))
  409. return -1;
  410. len1 = pkt->size;
  411. if (len1 < 0) {
  412. // if error, skip frame
  413. audio_pkt_size = 0;
  414. break;
  415. }
  416. audio_pkt_data += len1;
  417. audio_pkt_size -= len1;
  418. data_size = 0;
  419. if (got_frame) {
  420. // audio resampling
  421. data_size = this->resampleAudio (avFrame, audioBuffer);
  422. assert (data_size <= bufferSize);
  423. }
  424. if (data_size <= 0) {
  425. // no data found, keep waiting
  426. continue;
  427. }
  428. // some data was found
  429. return data_size;
  430. }
  431. if (pkt->data)
  432. av_packet_unref (pkt);
  433. this->dequeuePacket (pkt);
  434. audio_pkt_data = pkt->data;
  435. audio_pkt_size = pkt->size;
  436. }
  437. return 0;
  438. }
  439. AudioContext& AudioStream::getAudioContext () const {
  440. return this->m_audioContext;
  441. }