CAudioStream.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. #include "CAudioStream.h"
  2. #include <cassert>
  3. #include <iostream>
  4. #include <math.h>
  5. extern int g_AudioVolume;
  6. using namespace WallpaperEngine::Audio;
  7. // callback for sdl to play our audio
  8. void audio_callback (void* userdata, uint8_t* stream, int length)
  9. {
  10. auto audioStream = static_cast <CAudioStream*> (userdata);
  11. int len1, audio_size;
  12. static uint8_t audio_buf[(MAX_AUDIO_FRAME_SIZE * 3) / 2];
  13. static unsigned int audio_buf_size = 0;
  14. static unsigned int audio_buf_index = 0;
  15. while (length > 0)
  16. {
  17. if (audio_buf_index >= audio_buf_size)
  18. {
  19. /* We have already sent all our data; get more */
  20. audio_size = audioStream->decodeFrame (audio_buf, sizeof (audio_buf));
  21. if (audio_size < 0)
  22. {
  23. /* If error, output silence */
  24. audio_buf_size = 1024; // arbitrary?
  25. memset(audio_buf, 0, audio_buf_size);
  26. }
  27. else
  28. {
  29. audio_buf_size = audio_size;
  30. }
  31. audio_buf_index = 0;
  32. }
  33. len1 = audio_buf_size - audio_buf_index;
  34. if (len1 > length)
  35. len1 = length;
  36. // mix the audio so the volume is right
  37. SDL_MixAudio (stream, (uint8_t*) audio_buf + audio_buf_index, len1, g_AudioVolume);
  38. length -= len1;
  39. stream += len1;
  40. audio_buf_index += len1;
  41. if (audioStream->isInitialized () == false)
  42. break;
  43. }
  44. }
  45. int audio_read_thread (void* arg)
  46. {
  47. CAudioStream* stream = static_cast <CAudioStream*> (arg);
  48. AVPacket* packet = av_packet_alloc ();
  49. int ret = 0;
  50. while (ret >= 0)
  51. {
  52. ret = av_read_frame (stream->getFormatContext (), packet);
  53. if (ret == AVERROR_EOF)
  54. {
  55. // seek to the beginning of the file again
  56. av_seek_frame (stream->getFormatContext (), stream->getAudioStream (), 0, AVSEEK_FLAG_FRAME);
  57. avcodec_flush_buffers (stream->getContext ());
  58. continue;
  59. }
  60. // TODO: PROPERLY IMPLEMENT THIS
  61. if (packet->stream_index == stream->getAudioStream ())
  62. stream->queuePacket (packet);
  63. else
  64. av_packet_unref (packet);
  65. if (stream->isInitialized () == false)
  66. break;
  67. }
  68. return 0;
  69. }
  70. static int audio_read_data_callback (void* streamarg, uint8_t* buffer, int buffer_size)
  71. {
  72. auto stream = static_cast <CAudioStream*> (streamarg);
  73. int left = stream->getLength () - stream->getPosition ();
  74. buffer_size = FFMIN (buffer_size, left);
  75. memcpy (buffer, (uint8_t*) stream->getBuffer () + stream->getPosition (), buffer_size);
  76. // update position
  77. stream->setPosition (stream->getPosition () + buffer_size);
  78. return buffer_size;
  79. }
  80. int64_t audio_seek_data_callback (void* streamarg, int64_t offset, int whence)
  81. {
  82. auto stream = static_cast <CAudioStream*> (streamarg);
  83. if (whence & AVSEEK_SIZE)
  84. return stream->getLength ();
  85. switch (whence)
  86. {
  87. case SEEK_CUR:
  88. stream->setPosition (stream->getPosition () + offset);
  89. break;
  90. case SEEK_SET:
  91. stream->setPosition (offset);
  92. break;
  93. }
  94. return offset;
  95. }
  96. CAudioStream::CAudioStream (const std::string& filename)
  97. {
  98. // do not do anything if sdl audio was not initialized
  99. if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
  100. return;
  101. this->loadCustomContent (filename.c_str ());
  102. }
  103. CAudioStream::CAudioStream (void* buffer, int length)
  104. {
  105. // do not do anything if sdl audio was not initialized
  106. if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
  107. return;
  108. // setup a custom context first
  109. this->m_formatContext = avformat_alloc_context ();
  110. if (this->m_formatContext == nullptr)
  111. throw std::runtime_error ("Cannot allocate format context");
  112. this->m_buffer = buffer;
  113. this->m_length = length;
  114. this->m_position = 0;
  115. // setup custom io for it
  116. this->m_formatContext->pb = avio_alloc_context (
  117. static_cast <uint8_t*> (av_malloc (4096)),
  118. 4096,
  119. 0,
  120. static_cast <void*> (this),
  121. &audio_read_data_callback,
  122. nullptr,
  123. &audio_seek_data_callback
  124. );
  125. if (this->m_formatContext->pb == nullptr)
  126. throw std::runtime_error ("Cannot create avio context");
  127. // continue the normal load procedure
  128. this->loadCustomContent ();
  129. }
  130. CAudioStream::CAudioStream(AVCodecContext* context)
  131. : m_context (context),
  132. m_queue (new PacketQueue)
  133. {
  134. // do not do anything if sdl audio was not initialized
  135. if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
  136. return;
  137. this->initialize ();
  138. }
  139. void CAudioStream::loadCustomContent (const char* filename)
  140. {
  141. const AVCodec* aCodec = nullptr;
  142. AVCodecContext* avCodecContext = nullptr;
  143. if (avformat_open_input (&this->m_formatContext, filename, nullptr, nullptr) != 0)
  144. throw std::runtime_error ("Cannot open audio file");
  145. if (avformat_find_stream_info (this->m_formatContext, nullptr) < 0)
  146. throw std::runtime_error ("Cannot determine file format");
  147. // find the audio stream
  148. for (int i = 0; i< this->m_formatContext->nb_streams; i ++)
  149. {
  150. if (this->m_formatContext->streams [i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && this->m_audioStream < 0)
  151. this->m_audioStream = i;
  152. }
  153. if (this->m_audioStream == -1)
  154. throw std::runtime_error ("Cannot find audio stream in file");
  155. // get the decoder for it and alloc the required context
  156. aCodec = avcodec_find_decoder (this->m_formatContext->streams [this->m_audioStream]->codecpar->codec_id);
  157. if (aCodec == nullptr)
  158. throw std::runtime_error ("Cannot initialize audio decoder");
  159. // alocate context
  160. avCodecContext = avcodec_alloc_context3 (aCodec);
  161. if (avcodec_parameters_to_context (avCodecContext, this->m_formatContext->streams [this->m_audioStream]->codecpar) != 0)
  162. throw std::runtime_error ("Cannot initialize audio decoder parameters");
  163. // finally open
  164. avcodec_open2 (avCodecContext, aCodec, nullptr);
  165. // initialize default data
  166. this->m_context = avCodecContext;
  167. this->m_queue = new PacketQueue;
  168. this->initialize ();
  169. // initialize an SDL thread to read the file
  170. SDL_CreateThread (audio_read_thread, this);
  171. }
  172. void CAudioStream::initialize ()
  173. {
  174. // allocate the FIFO buffer
  175. this->m_queue->packetList = av_fifo_alloc (sizeof (MyAVPacketList));
  176. // setup the queue information
  177. this->m_queue->mutex = SDL_CreateMutex ();
  178. this->m_queue->cond = SDL_CreateCond ();
  179. // take control of the audio device
  180. SDL_AudioSpec requestedSpec, finalSpec;
  181. // Set audio settings from codec info
  182. requestedSpec.freq = this->m_context->sample_rate;
  183. requestedSpec.format = AUDIO_S16SYS;
  184. requestedSpec.channels = this->m_context->channels;
  185. requestedSpec.silence = 0;
  186. requestedSpec.samples = SDL_AUDIO_BUFFER_SIZE;
  187. requestedSpec.callback = audio_callback;
  188. requestedSpec.userdata = this;
  189. if (SDL_OpenAudio (&requestedSpec, &finalSpec) < 0) {
  190. std::cerr << "SDL_OpenAudio: " << SDL_GetError () << std::endl;
  191. return;
  192. }
  193. SDL_PauseAudio (0);
  194. this->m_initialized = true;
  195. }
  196. void CAudioStream::queuePacket(AVPacket *pkt)
  197. {
  198. // clone the packet
  199. AVPacket* clone = av_packet_alloc ();
  200. if (clone == nullptr)
  201. {
  202. av_packet_unref (clone);
  203. return;
  204. }
  205. av_packet_move_ref (clone, pkt);
  206. SDL_LockMutex (this->m_queue->mutex);
  207. bool gotQueued = this->doQueue (clone);
  208. SDL_UnlockMutex (this->m_queue->mutex);
  209. if (gotQueued == false)
  210. av_packet_free (&pkt);
  211. }
  212. bool CAudioStream::doQueue (AVPacket* pkt)
  213. {
  214. MyAVPacketList entry;
  215. // ensure the FIFO has enough space to hold the new entry
  216. if (av_fifo_space (this->m_queue->packetList) < sizeof (entry))
  217. {
  218. if (av_fifo_grow (this->m_queue->packetList, sizeof (entry)) < 0)
  219. {
  220. return false;
  221. }
  222. }
  223. entry.packet = pkt;
  224. // write to the FIFO
  225. av_fifo_generic_write (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
  226. this->m_queue->nb_packets ++;
  227. this->m_queue->size += entry.packet->size + sizeof (entry);
  228. this->m_queue->duration += entry.packet->duration;
  229. SDL_CondSignal (this->m_queue->cond);
  230. return true;
  231. }
  232. void CAudioStream::dequeuePacket (AVPacket* output)
  233. {
  234. MyAVPacketList entry;
  235. SDL_LockMutex (this->m_queue->mutex);
  236. while (true)
  237. {
  238. // enough data available, read it
  239. if (av_fifo_size (this->m_queue->packetList) >= sizeof (entry))
  240. {
  241. av_fifo_generic_read (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
  242. this->m_queue->nb_packets --;
  243. this->m_queue->size -= entry.packet->duration;
  244. // move the reference and free the old one
  245. av_packet_move_ref (output, entry.packet);
  246. av_packet_free (&entry.packet);
  247. break;
  248. }
  249. // make the thread wait if nothing was available
  250. SDL_CondWait (this->m_queue->cond, this->m_queue->mutex);
  251. }
  252. SDL_UnlockMutex (this->m_queue->mutex);
  253. }
  254. AVCodecContext* CAudioStream::getContext ()
  255. {
  256. return this->m_context;
  257. }
  258. AVFormatContext* CAudioStream::getFormatContext ()
  259. {
  260. return this->m_formatContext;
  261. }
  262. int CAudioStream::getAudioStream ()
  263. {
  264. return this->m_audioStream;
  265. }
  266. bool CAudioStream::isInitialized ()
  267. {
  268. return this->m_initialized;
  269. }
  270. void CAudioStream::setRepeat (bool newRepeat)
  271. {
  272. this->m_repeat = newRepeat;
  273. }
  274. bool CAudioStream::isRepeat ()
  275. {
  276. return this->m_repeat;
  277. }
  278. void* CAudioStream::getBuffer ()
  279. {
  280. return this->m_buffer;
  281. }
  282. int CAudioStream::getLength ()
  283. {
  284. return this->m_length;
  285. }
  286. int CAudioStream::getPosition ()
  287. {
  288. return this->m_position;
  289. }
  290. void CAudioStream::setPosition (int current)
  291. {
  292. this->m_position = current;
  293. }
  294. void CAudioStream::stop ()
  295. {
  296. if (this->isInitialized () == false)
  297. return;
  298. // pause audio
  299. SDL_PauseAudio (1);
  300. // stop the threads running
  301. this->m_initialized = false;
  302. }
  303. int CAudioStream::resampleAudio (
  304. AVFrame * decoded_audio_frame,
  305. enum AVSampleFormat out_sample_fmt,
  306. int out_channels,
  307. int out_sample_rate,
  308. uint8_t * out_buf
  309. )
  310. {
  311. SwrContext * swr_ctx = NULL;
  312. int ret = 0;
  313. int64_t in_channel_layout = this->getContext ()->channel_layout;
  314. int64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
  315. int out_nb_channels = 0;
  316. int out_linesize = 0;
  317. int in_nb_samples = 0;
  318. int out_nb_samples = 0;
  319. int max_out_nb_samples = 0;
  320. uint8_t ** resampled_data = NULL;
  321. int resampled_data_size = 0;
  322. swr_ctx = swr_alloc();
  323. if (!swr_ctx)
  324. {
  325. printf("swr_alloc error.\n");
  326. return -1;
  327. }
  328. // get input audio channels
  329. in_channel_layout = (this->getContext ()->channels ==
  330. av_get_channel_layout_nb_channels(this->getContext ()->channel_layout)) ? // 2
  331. this->getContext ()->channel_layout :
  332. av_get_default_channel_layout(this->getContext ()->channels);
  333. // check input audio channels correctly retrieved
  334. if (in_channel_layout <= 0)
  335. {
  336. printf("in_channel_layout error.\n");
  337. return -1;
  338. }
  339. // set output audio channels based on the input audio channels
  340. if (out_channels == 1)
  341. {
  342. out_channel_layout = AV_CH_LAYOUT_MONO;
  343. }
  344. else if (out_channels == 2)
  345. {
  346. out_channel_layout = AV_CH_LAYOUT_STEREO;
  347. }
  348. else
  349. {
  350. out_channel_layout = AV_CH_LAYOUT_SURROUND;
  351. }
  352. // retrieve number of audio samples (per channel)
  353. in_nb_samples = decoded_audio_frame->nb_samples;
  354. if (in_nb_samples <= 0)
  355. {
  356. printf("in_nb_samples error.\n");
  357. return -1;
  358. }
  359. // Set SwrContext parameters for resampling
  360. av_opt_set_int( // 3
  361. swr_ctx,
  362. "in_channel_layout",
  363. in_channel_layout,
  364. 0
  365. );
  366. // Set SwrContext parameters for resampling
  367. av_opt_set_int(
  368. swr_ctx,
  369. "in_sample_rate",
  370. this->getContext ()->sample_rate,
  371. 0
  372. );
  373. // Set SwrContext parameters for resampling
  374. av_opt_set_sample_fmt(
  375. swr_ctx,
  376. "in_sample_fmt",
  377. this->getContext ()->sample_fmt,
  378. 0
  379. );
  380. // Set SwrContext parameters for resampling
  381. av_opt_set_int(
  382. swr_ctx,
  383. "out_channel_layout",
  384. out_channel_layout,
  385. 0
  386. );
  387. // Set SwrContext parameters for resampling
  388. av_opt_set_int(
  389. swr_ctx,
  390. "out_sample_rate",
  391. out_sample_rate,
  392. 0
  393. );
  394. // Set SwrContext parameters for resampling
  395. av_opt_set_sample_fmt(
  396. swr_ctx,
  397. "out_sample_fmt",
  398. out_sample_fmt,
  399. 0
  400. );
  401. // Once all values have been set for the SwrContext, it must be initialized
  402. // with swr_init().
  403. ret = swr_init(swr_ctx);;
  404. if (ret < 0)
  405. {
  406. printf("Failed to initialize the resampling context.\n");
  407. return -1;
  408. }
  409. max_out_nb_samples = out_nb_samples = av_rescale_rnd(
  410. in_nb_samples,
  411. out_sample_rate,
  412. this->getContext ()->sample_rate,
  413. AV_ROUND_UP
  414. );
  415. // check rescaling was successful
  416. if (max_out_nb_samples <= 0)
  417. {
  418. printf("av_rescale_rnd error.\n");
  419. return -1;
  420. }
  421. // get number of output audio channels
  422. out_nb_channels = av_get_channel_layout_nb_channels(out_channel_layout);
  423. ret = av_samples_alloc_array_and_samples(
  424. &resampled_data,
  425. &out_linesize,
  426. out_nb_channels,
  427. out_nb_samples,
  428. out_sample_fmt,
  429. 0
  430. );
  431. if (ret < 0)
  432. {
  433. printf("av_samples_alloc_array_and_samples() error: Could not allocate destination samples.\n");
  434. return -1;
  435. }
  436. // retrieve output samples number taking into account the progressive delay
  437. out_nb_samples = av_rescale_rnd(
  438. swr_get_delay(swr_ctx, this->getContext ()->sample_rate) + in_nb_samples,
  439. out_sample_rate,
  440. this->getContext ()->sample_rate,
  441. AV_ROUND_UP
  442. );
  443. // check output samples number was correctly retrieved
  444. if (out_nb_samples <= 0)
  445. {
  446. printf("av_rescale_rnd error\n");
  447. return -1;
  448. }
  449. if (out_nb_samples > max_out_nb_samples)
  450. {
  451. // free memory block and set pointer to NULL
  452. av_free(resampled_data[0]);
  453. // Allocate a samples buffer for out_nb_samples samples
  454. ret = av_samples_alloc(
  455. resampled_data,
  456. &out_linesize,
  457. out_nb_channels,
  458. out_nb_samples,
  459. out_sample_fmt,
  460. 1
  461. );
  462. // check samples buffer correctly allocated
  463. if (ret < 0)
  464. {
  465. printf("av_samples_alloc failed.\n");
  466. return -1;
  467. }
  468. max_out_nb_samples = out_nb_samples;
  469. }
  470. if (swr_ctx)
  471. {
  472. // do the actual audio data resampling
  473. ret = swr_convert(
  474. swr_ctx,
  475. resampled_data,
  476. out_nb_samples,
  477. (const uint8_t **) decoded_audio_frame->data,
  478. decoded_audio_frame->nb_samples
  479. );
  480. // check audio conversion was successful
  481. if (ret < 0)
  482. {
  483. printf("swr_convert_error.\n");
  484. return -1;
  485. }
  486. // Get the required buffer size for the given audio parameters
  487. resampled_data_size = av_samples_get_buffer_size(
  488. &out_linesize,
  489. out_nb_channels,
  490. ret,
  491. out_sample_fmt,
  492. 1
  493. );
  494. // check audio buffer size
  495. if (resampled_data_size < 0)
  496. {
  497. printf("av_samples_get_buffer_size error.\n");
  498. return -1;
  499. }
  500. }
  501. else
  502. {
  503. printf("swr_ctx null error.\n");
  504. return -1;
  505. }
  506. // copy the resampled data to the output buffer
  507. memcpy(out_buf, resampled_data[0], resampled_data_size);
  508. /*
  509. * Memory Cleanup.
  510. */
  511. if (resampled_data)
  512. {
  513. // free memory block and set pointer to NULL
  514. av_freep(&resampled_data[0]);
  515. }
  516. av_freep(&resampled_data);
  517. resampled_data = NULL;
  518. if (swr_ctx)
  519. {
  520. // Free the given SwrContext and set the pointer to NULL
  521. swr_free(&swr_ctx);
  522. }
  523. return resampled_data_size;
  524. }
  525. int CAudioStream::decodeFrame (uint8_t* audioBuffer, int bufferSize)
  526. {
  527. AVPacket *pkt = av_packet_alloc ();
  528. static uint8_t *audio_pkt_data = NULL;
  529. static int audio_pkt_size = 0;
  530. int len1, data_size = 0;
  531. // allocate a new frame, used to decode audio packets
  532. static AVFrame * avFrame = NULL;
  533. avFrame = av_frame_alloc();
  534. if (!avFrame)
  535. {
  536. printf("Could not allocate AVFrame.\n");
  537. return -1;
  538. }
  539. for (;;) {
  540. while (audio_pkt_size > 0) {
  541. int got_frame = 0;
  542. int ret = avcodec_receive_frame(this->getContext (), avFrame);
  543. if (ret == 0)
  544. {
  545. got_frame = 1;
  546. }
  547. if (ret == AVERROR(EAGAIN))
  548. {
  549. ret = 0;
  550. }
  551. if (ret == 0)
  552. {
  553. ret = avcodec_send_packet(this->getContext (), pkt);
  554. }
  555. if (ret == AVERROR(EAGAIN))
  556. {
  557. ret = 0;
  558. }
  559. else if (ret < 0)
  560. {
  561. return -1;
  562. }
  563. else
  564. {
  565. len1 = pkt->size;
  566. }
  567. if (len1 < 0)
  568. {
  569. // if error, skip frame
  570. audio_pkt_size = 0;
  571. break;
  572. }
  573. audio_pkt_data += len1;
  574. audio_pkt_size -= len1;
  575. data_size = 0;
  576. if (got_frame) {
  577. // audio resampling
  578. data_size = this->resampleAudio (
  579. avFrame,
  580. AV_SAMPLE_FMT_S16,
  581. this->getContext ()->channels,
  582. this->getContext ()->sample_rate,
  583. audioBuffer
  584. );
  585. assert(data_size <= bufferSize);
  586. }
  587. if (data_size <= 0) {
  588. /* No data yet, get more frames */
  589. continue;
  590. }
  591. /* We have data, return it and come back for more later */
  592. return data_size;
  593. }
  594. if (pkt->data)
  595. av_packet_unref(pkt);
  596. this->dequeuePacket (pkt);
  597. audio_pkt_data = pkt->data;
  598. audio_pkt_size = pkt->size;
  599. }
  600. }