alffplay.cpp 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358
  1. /*
  2. * An example showing how to play a stream sync'd to video, using ffmpeg.
  3. *
  4. * Requires C++14.
  5. */
  6. #include <algorithm>
  7. #include <array>
  8. #include <atomic>
  9. #include <cassert>
  10. #include <cerrno>
  11. #include <chrono>
  12. #include <cmath>
  13. #include <condition_variable>
  14. #include <cstdint>
  15. #include <cstdio>
  16. #include <cstdlib>
  17. #include <cstring>
  18. #include <deque>
  19. #include <functional>
  20. #include <future>
  21. #include <memory>
  22. #include <mutex>
  23. #include <ratio>
  24. #include <string>
  25. #include <string_view>
  26. #include <thread>
  27. #include <utility>
  28. #include <vector>
  29. #ifdef __GNUC__
  30. _Pragma("GCC diagnostic push")
  31. _Pragma("GCC diagnostic ignored \"-Wconversion\"")
  32. _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"")
  33. #endif
  34. extern "C" {
  35. #include "libavcodec/avcodec.h"
  36. #include "libavformat/avformat.h"
  37. #include "libavformat/avio.h"
  38. #include "libavutil/avutil.h"
  39. #include "libavutil/error.h"
  40. #include "libavutil/frame.h"
  41. #include "libavutil/mem.h"
  42. #include "libavutil/pixfmt.h"
  43. #include "libavutil/rational.h"
  44. #include "libavutil/samplefmt.h"
  45. #include "libavutil/time.h"
  46. #include "libavutil/channel_layout.h"
  47. #include "libswscale/swscale.h"
  48. #include "libswresample/swresample.h"
  49. struct SwsContext;
  50. }
  51. #define SDL_MAIN_HANDLED
  52. #include "SDL3/SDL_events.h"
  53. #include "SDL3/SDL_main.h"
  54. #include "SDL3/SDL_render.h"
  55. #include "SDL3/SDL_video.h"
  56. namespace {
  57. constexpr auto DefineSDLColorspace(SDL_ColorType type, SDL_ColorRange range,
  58. SDL_ColorPrimaries primaries, SDL_TransferCharacteristics transfer,
  59. SDL_MatrixCoefficients matrix, SDL_ChromaLocation chromaloc) noexcept
  60. {
  61. return SDL_DEFINE_COLORSPACE(type, range, primaries, transfer, matrix, chromaloc);
  62. }
  63. } // namespace
  64. #ifdef __GNUC__
  65. _Pragma("GCC diagnostic pop")
  66. #endif
  67. #include "AL/alc.h"
  68. #include "AL/al.h"
  69. #include "AL/alext.h"
  70. #include "almalloc.h"
  71. #include "alnumbers.h"
  72. #include "alnumeric.h"
  73. #include "alspan.h"
  74. #include "common/alhelpers.h"
  75. #include "fmt/core.h"
  76. #include "fmt/format.h"
  77. namespace {
  78. using voidp = void*;
  79. using fixed32 = std::chrono::duration<int64_t,std::ratio<1,(1_i64<<32)>>;
  80. using nanoseconds = std::chrono::nanoseconds;
  81. using microseconds = std::chrono::microseconds;
  82. using milliseconds = std::chrono::milliseconds;
  83. using seconds = std::chrono::seconds;
  84. using seconds_d64 = std::chrono::duration<double>;
  85. using std::chrono::duration_cast;
  86. #ifdef __GNUC__
  87. _Pragma("GCC diagnostic push")
  88. _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"")
  89. #endif
  90. constexpr auto AVNoPtsValue = AV_NOPTS_VALUE;
  91. constexpr auto AVErrorEOF = AVERROR_EOF;
  92. #ifdef __GNUC__
  93. _Pragma("GCC diagnostic pop")
  94. #endif
  95. const std::string AppName{"alffplay"};
  96. ALenum DirectOutMode{AL_FALSE};
  97. bool EnableWideStereo{false};
  98. bool EnableUhj{false};
  99. bool EnableSuperStereo{false};
  100. bool DisableVideo{false};
  101. LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
  102. LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT;
  103. LPALEVENTCONTROLSOFT alEventControlSOFT;
  104. LPALEVENTCALLBACKSOFT alEventCallbackSOFT;
  105. LPALBUFFERCALLBACKSOFT alBufferCallbackSOFT;
  106. const seconds AVNoSyncThreshold{10};
  107. #define VIDEO_PICTURE_QUEUE_SIZE 24
  108. const seconds_d64 AudioSyncThreshold{0.03};
  109. const milliseconds AudioSampleCorrectionMax{50};
  110. /* Averaging filter coefficient for audio sync. */
  111. #define AUDIO_DIFF_AVG_NB 20
  112. const double AudioAvgFilterCoeff{std::pow(0.01, 1.0/AUDIO_DIFF_AVG_NB)};
  113. /* Per-buffer size, in time */
  114. constexpr milliseconds AudioBufferTime{20};
  115. /* Buffer total size, in time (should be divisible by the buffer time) */
  116. constexpr milliseconds AudioBufferTotalTime{800};
  117. constexpr auto AudioBufferCount = AudioBufferTotalTime / AudioBufferTime;
  118. enum {
  119. FF_MOVIE_DONE_EVENT = SDL_EVENT_USER
  120. };
  121. enum class SyncMaster {
  122. Audio,
  123. Video,
  124. External,
  125. Default = Audio
  126. };
  127. inline microseconds get_avtime()
  128. { return microseconds{av_gettime()}; }
  129. /* Define unique_ptrs to auto-cleanup associated ffmpeg objects. */
  130. struct AVIOContextDeleter {
  131. void operator()(AVIOContext *ptr) { avio_closep(&ptr); }
  132. };
  133. using AVIOContextPtr = std::unique_ptr<AVIOContext,AVIOContextDeleter>;
  134. struct AVFormatCtxDeleter {
  135. void operator()(AVFormatContext *ptr) { avformat_close_input(&ptr); }
  136. };
  137. using AVFormatCtxPtr = std::unique_ptr<AVFormatContext,AVFormatCtxDeleter>;
  138. struct AVCodecCtxDeleter {
  139. void operator()(AVCodecContext *ptr) { avcodec_free_context(&ptr); }
  140. };
  141. using AVCodecCtxPtr = std::unique_ptr<AVCodecContext,AVCodecCtxDeleter>;
  142. struct AVPacketDeleter {
  143. void operator()(AVPacket *pkt) { av_packet_free(&pkt); }
  144. };
  145. using AVPacketPtr = std::unique_ptr<AVPacket,AVPacketDeleter>;
  146. struct AVFrameDeleter {
  147. void operator()(AVFrame *ptr) { av_frame_free(&ptr); }
  148. };
  149. using AVFramePtr = std::unique_ptr<AVFrame,AVFrameDeleter>;
  150. struct SwrContextDeleter {
  151. void operator()(SwrContext *ptr) { swr_free(&ptr); }
  152. };
  153. using SwrContextPtr = std::unique_ptr<SwrContext,SwrContextDeleter>;
  154. struct SwsContextDeleter {
  155. void operator()(SwsContext *ptr) { sws_freeContext(ptr); }
  156. };
  157. using SwsContextPtr = std::unique_ptr<SwsContext,SwsContextDeleter>;
  158. struct SDLProps {
  159. SDL_PropertiesID mProperties{};
  160. SDLProps() : mProperties{SDL_CreateProperties()} { }
  161. ~SDLProps() { SDL_DestroyProperties(mProperties); }
  162. SDLProps(const SDLProps&) = delete;
  163. auto operator=(const SDLProps&) -> SDLProps& = delete;
  164. [[nodiscard]]
  165. auto getid() const noexcept -> SDL_PropertiesID { return mProperties; }
  166. auto setPointer(const char *name, void *value) const
  167. { return SDL_SetPointerProperty(mProperties, name, value); }
  168. auto setString(const char *name, const char *value) const
  169. { return SDL_SetStringProperty(mProperties, name, value); }
  170. auto setInt(const char *name, Sint64 value) const
  171. { return SDL_SetNumberProperty(mProperties, name, value); }
  172. };
  173. struct TextureFormatEntry {
  174. AVPixelFormat avformat;
  175. SDL_PixelFormat sdlformat;
  176. };
  177. constexpr auto TextureFormatMap = std::array{
  178. TextureFormatEntry{AV_PIX_FMT_RGB8, SDL_PIXELFORMAT_RGB332},
  179. TextureFormatEntry{AV_PIX_FMT_RGB444, SDL_PIXELFORMAT_XRGB4444},
  180. TextureFormatEntry{AV_PIX_FMT_RGB555, SDL_PIXELFORMAT_XRGB1555},
  181. TextureFormatEntry{AV_PIX_FMT_BGR555, SDL_PIXELFORMAT_XBGR1555},
  182. TextureFormatEntry{AV_PIX_FMT_RGB565, SDL_PIXELFORMAT_RGB565},
  183. TextureFormatEntry{AV_PIX_FMT_BGR565, SDL_PIXELFORMAT_BGR565},
  184. TextureFormatEntry{AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB24},
  185. TextureFormatEntry{AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR24},
  186. TextureFormatEntry{AV_PIX_FMT_0RGB32, SDL_PIXELFORMAT_XRGB8888},
  187. TextureFormatEntry{AV_PIX_FMT_0BGR32, SDL_PIXELFORMAT_XBGR8888},
  188. TextureFormatEntry{AV_PIX_FMT_NE(RGB0, 0BGR), SDL_PIXELFORMAT_RGBX8888},
  189. TextureFormatEntry{AV_PIX_FMT_NE(BGR0, 0RGB), SDL_PIXELFORMAT_BGRX8888},
  190. TextureFormatEntry{AV_PIX_FMT_RGB32, SDL_PIXELFORMAT_ARGB8888},
  191. TextureFormatEntry{AV_PIX_FMT_RGB32_1, SDL_PIXELFORMAT_RGBA8888},
  192. TextureFormatEntry{AV_PIX_FMT_BGR32, SDL_PIXELFORMAT_ABGR8888},
  193. TextureFormatEntry{AV_PIX_FMT_BGR32_1, SDL_PIXELFORMAT_BGRA8888},
  194. TextureFormatEntry{AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV},
  195. TextureFormatEntry{AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2},
  196. TextureFormatEntry{AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY},
  197. TextureFormatEntry{AV_PIX_FMT_NV12, SDL_PIXELFORMAT_NV12},
  198. TextureFormatEntry{AV_PIX_FMT_NV21, SDL_PIXELFORMAT_NV21},
  199. };
  200. struct ChannelLayout : public AVChannelLayout {
  201. ChannelLayout() : AVChannelLayout{} { }
  202. ChannelLayout(const ChannelLayout &rhs) : AVChannelLayout{}
  203. { av_channel_layout_copy(this, &rhs); }
  204. ~ChannelLayout() { av_channel_layout_uninit(this); }
  205. auto operator=(const ChannelLayout &rhs) -> ChannelLayout&
  206. { av_channel_layout_copy(this, &rhs); return *this; }
  207. };
  208. class DataQueue {
  209. const size_t mSizeLimit;
  210. std::mutex mPacketMutex, mFrameMutex;
  211. std::condition_variable mPacketCond;
  212. std::condition_variable mInFrameCond, mOutFrameCond;
  213. std::deque<AVPacketPtr> mPackets;
  214. size_t mTotalSize{0};
  215. bool mFinished{false};
  216. auto getPacket() -> AVPacketPtr
  217. {
  218. auto plock = std::unique_lock{mPacketMutex};
  219. mPacketCond.wait(plock, [this] { return !mPackets.empty() || mFinished; });
  220. if(mPackets.empty())
  221. return nullptr;
  222. auto ret = std::move(mPackets.front());
  223. mPackets.pop_front();
  224. mTotalSize -= static_cast<unsigned int>(ret->size);
  225. return ret;
  226. }
  227. public:
  228. explicit DataQueue(size_t size_limit) : mSizeLimit{size_limit} { }
  229. int sendPacket(AVCodecContext *codecctx)
  230. {
  231. auto packet = getPacket();
  232. auto ret = int{};
  233. {
  234. auto flock = std::unique_lock{mFrameMutex};
  235. mInFrameCond.wait(flock, [this,codecctx,pkt=packet.get(),&ret]
  236. {
  237. ret = avcodec_send_packet(codecctx, pkt);
  238. if(ret != AVERROR(EAGAIN)) return true;
  239. mOutFrameCond.notify_one();
  240. return false;
  241. });
  242. }
  243. mOutFrameCond.notify_one();
  244. if(!packet)
  245. {
  246. if(!ret) return AVErrorEOF;
  247. fmt::println(stderr, "Failed to send flush packet: {}", ret);
  248. return ret;
  249. }
  250. if(ret < 0)
  251. fmt::println(stderr, "Failed to send packet: {}", ret);
  252. return ret;
  253. }
  254. int receiveFrame(AVCodecContext *codecctx, AVFrame *frame)
  255. {
  256. auto ret = int{};
  257. {
  258. auto flock = std::unique_lock{mFrameMutex};
  259. mOutFrameCond.wait(flock, [this,codecctx,frame,&ret]
  260. {
  261. ret = avcodec_receive_frame(codecctx, frame);
  262. if(ret != AVERROR(EAGAIN)) return true;
  263. mInFrameCond.notify_one();
  264. return false;
  265. });
  266. }
  267. mInFrameCond.notify_one();
  268. return ret;
  269. }
  270. void setFinished()
  271. {
  272. {
  273. auto plock = std::lock_guard{mPacketMutex};
  274. mFinished = true;
  275. }
  276. mPacketCond.notify_one();
  277. }
  278. void flush()
  279. {
  280. {
  281. auto plock = std::lock_guard{mPacketMutex};
  282. mFinished = true;
  283. mPackets.clear();
  284. mTotalSize = 0;
  285. }
  286. mPacketCond.notify_one();
  287. }
  288. auto put(const AVPacket *pkt) -> bool
  289. {
  290. {
  291. auto plock = std::lock_guard{mPacketMutex};
  292. if(mTotalSize >= mSizeLimit || mFinished)
  293. return false;
  294. auto *newpkt = mPackets.emplace_back(AVPacketPtr{av_packet_alloc()}).get();
  295. if(av_packet_ref(newpkt, pkt) == 0)
  296. mTotalSize += static_cast<unsigned int>(newpkt->size);
  297. else
  298. mPackets.pop_back();
  299. }
  300. mPacketCond.notify_one();
  301. return true;
  302. }
  303. };
  304. struct MovieState;
  305. struct AudioState {
  306. MovieState &mMovie;
  307. AVStream *mStream{nullptr};
  308. AVCodecCtxPtr mCodecCtx;
  309. DataQueue mQueue{2_uz*1024_uz*1024_uz};
  310. /* Used for clock difference average computation */
  311. seconds_d64 mClockDiffAvg{0};
  312. /* Time of the next sample to be buffered */
  313. nanoseconds mCurrentPts{0};
  314. /* Device clock time that the stream started at. */
  315. nanoseconds mDeviceStartTime{nanoseconds::min()};
  316. /* Decompressed sample frame, and swresample context for conversion */
  317. AVFramePtr mDecodedFrame;
  318. SwrContextPtr mSwresCtx;
  319. /* Conversion format, for what gets fed to OpenAL */
  320. uint64_t mDstChanLayout{0};
  321. AVSampleFormat mDstSampleFmt{AV_SAMPLE_FMT_NONE};
  322. /* Storage of converted samples */
  323. std::array<uint8_t*,1> mSamples{};
  324. al::span<uint8_t> mSamplesSpan;
  325. int mSamplesLen{0}; /* In samples */
  326. int mSamplesPos{0};
  327. int mSamplesMax{0};
  328. std::vector<uint8_t> mBufferData;
  329. std::atomic<size_t> mReadPos{0};
  330. std::atomic<size_t> mWritePos{0};
  331. /* OpenAL format */
  332. ALenum mFormat{AL_NONE};
  333. ALuint mFrameSize{0};
  334. std::mutex mSrcMutex;
  335. std::condition_variable mSrcCond;
  336. std::atomic_flag mConnected{};
  337. ALuint mSource{0};
  338. std::array<ALuint,AudioBufferCount> mBuffers{};
  339. ALuint mBufferIdx{0};
  340. explicit AudioState(MovieState &movie) : mMovie(movie)
  341. { mConnected.test_and_set(std::memory_order_relaxed); }
  342. ~AudioState()
  343. {
  344. if(mSource)
  345. alDeleteSources(1, &mSource);
  346. if(mBuffers[0])
  347. alDeleteBuffers(static_cast<ALsizei>(mBuffers.size()), mBuffers.data());
  348. av_freep(static_cast<void*>(mSamples.data()));
  349. }
  350. static void AL_APIENTRY eventCallbackC(ALenum eventType, ALuint object, ALuint param,
  351. ALsizei length, const ALchar *message, void *userParam) noexcept
  352. { static_cast<AudioState*>(userParam)->eventCallback(eventType, object, param, length, message); }
  353. void eventCallback(ALenum eventType, ALuint object, ALuint param, ALsizei length,
  354. const ALchar *message) noexcept;
  355. static ALsizei AL_APIENTRY bufferCallbackC(void *userptr, void *data, ALsizei size) noexcept
  356. { return static_cast<AudioState*>(userptr)->bufferCallback(data, size); }
  357. ALsizei bufferCallback(void *data, ALsizei size) noexcept;
  358. nanoseconds getClockNoLock();
  359. nanoseconds getClock()
  360. {
  361. std::lock_guard<std::mutex> lock{mSrcMutex};
  362. return getClockNoLock();
  363. }
  364. bool startPlayback();
  365. int getSync();
  366. int decodeFrame();
  367. bool readAudio(al::span<uint8_t> samples, unsigned int length, int &sample_skip);
  368. bool readAudio(int sample_skip);
  369. int handler();
  370. };
  371. struct VideoState {
  372. MovieState &mMovie;
  373. AVStream *mStream{nullptr};
  374. AVCodecCtxPtr mCodecCtx;
  375. DataQueue mQueue{14_uz*1024_uz*1024_uz};
  376. /* The pts of the currently displayed frame, and the time (av_gettime) it
  377. * was last updated - used to have running video pts
  378. */
  379. nanoseconds mDisplayPts{0};
  380. microseconds mDisplayPtsTime{microseconds::min()};
  381. std::mutex mDispPtsMutex;
  382. /* Swscale context for format conversion */
  383. SwsContextPtr mSwscaleCtx;
  384. struct Picture {
  385. AVFramePtr mFrame;
  386. nanoseconds mPts{nanoseconds::min()};
  387. };
  388. std::array<Picture,VIDEO_PICTURE_QUEUE_SIZE> mPictQ;
  389. std::atomic<size_t> mPictQRead{0u}, mPictQWrite{1u};
  390. std::mutex mPictQMutex;
  391. std::condition_variable mPictQCond;
  392. SDL_Texture *mImage{nullptr};
  393. int mWidth{0}, mHeight{0}; /* Full texture size */
  394. unsigned int mSDLFormat{SDL_PIXELFORMAT_UNKNOWN};
  395. int mAVFormat{AV_PIX_FMT_NONE};
  396. bool mFirstUpdate{true};
  397. std::atomic<bool> mEOS{false};
  398. std::atomic<bool> mFinalUpdate{false};
  399. explicit VideoState(MovieState &movie) : mMovie(movie) { }
  400. ~VideoState()
  401. {
  402. if(mImage)
  403. SDL_DestroyTexture(mImage);
  404. mImage = nullptr;
  405. }
  406. nanoseconds getClock();
  407. void display(SDL_Renderer *renderer, AVFrame *frame) const;
  408. void updateVideo(SDL_Window *screen, SDL_Renderer *renderer, bool redraw);
  409. int handler();
  410. };
  411. struct MovieState {
  412. AVIOContextPtr mIOContext;
  413. AVFormatCtxPtr mFormatCtx;
  414. SyncMaster mAVSyncType{SyncMaster::Default};
  415. microseconds mClockBase{microseconds::min()};
  416. std::atomic<bool> mQuit{false};
  417. AudioState mAudio;
  418. VideoState mVideo;
  419. std::mutex mStartupMutex;
  420. std::condition_variable mStartupCond;
  421. bool mStartupDone{false};
  422. std::thread mParseThread;
  423. std::thread mAudioThread;
  424. std::thread mVideoThread;
  425. std::string mFilename;
  426. explicit MovieState(std::string_view fname) : mAudio{*this}, mVideo{*this}, mFilename{fname}
  427. { }
  428. ~MovieState()
  429. {
  430. stop();
  431. if(mParseThread.joinable())
  432. mParseThread.join();
  433. }
  434. static int decode_interrupt_cb(void *ctx);
  435. bool prepare();
  436. void setTitle(SDL_Window *window) const;
  437. void stop();
  438. [[nodiscard]] nanoseconds getClock() const;
  439. [[nodiscard]] nanoseconds getMasterClock();
  440. [[nodiscard]] nanoseconds getDuration() const;
  441. bool streamComponentOpen(AVStream *stream);
  442. int parse_handler();
  443. };
  444. nanoseconds AudioState::getClockNoLock()
  445. {
  446. // The audio clock is the timestamp of the sample currently being heard.
  447. if(alcGetInteger64vSOFT)
  448. {
  449. // If device start time = min, we aren't playing yet.
  450. if(mDeviceStartTime == nanoseconds::min())
  451. return nanoseconds::zero();
  452. // Get the current device clock time and latency.
  453. auto device = alcGetContextsDevice(alcGetCurrentContext());
  454. std::array<ALCint64SOFT,2> devtimes{};
  455. alcGetInteger64vSOFT(device, ALC_DEVICE_CLOCK_LATENCY_SOFT, 2, devtimes.data());
  456. auto latency = nanoseconds{devtimes[1]};
  457. auto device_time = nanoseconds{devtimes[0]};
  458. // The clock is simply the current device time relative to the recorded
  459. // start time. We can also subtract the latency to get more a accurate
  460. // position of where the audio device actually is in the output stream.
  461. return device_time - mDeviceStartTime - latency;
  462. }
  463. if(!mBufferData.empty())
  464. {
  465. if(mDeviceStartTime == nanoseconds::min())
  466. return nanoseconds::zero();
  467. /* With a callback buffer and no device clock, mDeviceStartTime is
  468. * actually the timestamp of the first sample frame played. The audio
  469. * clock, then, is that plus the current source offset.
  470. */
  471. std::array<ALint64SOFT,2> offset{};
  472. if(alGetSourcei64vSOFT)
  473. alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_LATENCY_SOFT, offset.data());
  474. else
  475. {
  476. ALint ioffset;
  477. alGetSourcei(mSource, AL_SAMPLE_OFFSET, &ioffset);
  478. offset[0] = ALint64SOFT{ioffset} << 32;
  479. }
  480. /* NOTE: The source state must be checked last, in case an underrun
  481. * occurs and the source stops between getting the state and retrieving
  482. * the offset+latency.
  483. */
  484. ALint status;
  485. alGetSourcei(mSource, AL_SOURCE_STATE, &status);
  486. nanoseconds pts{};
  487. if(status == AL_PLAYING || status == AL_PAUSED)
  488. pts = mDeviceStartTime - nanoseconds{offset[1]} +
  489. duration_cast<nanoseconds>(fixed32{offset[0] / mCodecCtx->sample_rate});
  490. else
  491. {
  492. /* If the source is stopped, the pts of the next sample to be heard
  493. * is the pts of the next sample to be buffered, minus the amount
  494. * already in the buffer ready to play.
  495. */
  496. const size_t woffset{mWritePos.load(std::memory_order_acquire)};
  497. const size_t roffset{mReadPos.load(std::memory_order_relaxed)};
  498. const size_t readable{((woffset>=roffset) ? woffset : (mBufferData.size()+woffset)) -
  499. roffset};
  500. pts = mCurrentPts - nanoseconds{seconds{readable/mFrameSize}}/mCodecCtx->sample_rate;
  501. }
  502. return pts;
  503. }
  504. /* The source-based clock is based on 4 components:
  505. * 1 - The timestamp of the next sample to buffer (mCurrentPts)
  506. * 2 - The length of the source's buffer queue
  507. * (AudioBufferTime*AL_BUFFERS_QUEUED)
  508. * 3 - The offset OpenAL is currently at in the source (the first value
  509. * from AL_SAMPLE_OFFSET_LATENCY_SOFT)
  510. * 4 - The latency between OpenAL and the DAC (the second value from
  511. * AL_SAMPLE_OFFSET_LATENCY_SOFT)
  512. *
  513. * Subtracting the length of the source queue from the next sample's
  514. * timestamp gives the timestamp of the sample at the start of the source
  515. * queue. Adding the source offset to that results in the timestamp for the
  516. * sample at OpenAL's current position, and subtracting the source latency
  517. * from that gives the timestamp of the sample currently at the DAC.
  518. */
  519. nanoseconds pts{mCurrentPts};
  520. if(mSource)
  521. {
  522. std::array<ALint64SOFT,2> offset{};
  523. if(alGetSourcei64vSOFT)
  524. alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_LATENCY_SOFT, offset.data());
  525. else
  526. {
  527. ALint ioffset;
  528. alGetSourcei(mSource, AL_SAMPLE_OFFSET, &ioffset);
  529. offset[0] = ALint64SOFT{ioffset} << 32;
  530. }
  531. ALint queued, status;
  532. alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
  533. alGetSourcei(mSource, AL_SOURCE_STATE, &status);
  534. /* If the source is AL_STOPPED, then there was an underrun and all
  535. * buffers are processed, so ignore the source queue. The audio thread
  536. * will put the source into an AL_INITIAL state and clear the queue
  537. * when it starts recovery.
  538. */
  539. if(status != AL_STOPPED)
  540. {
  541. pts -= AudioBufferTime*queued;
  542. pts += duration_cast<nanoseconds>(fixed32{offset[0] / mCodecCtx->sample_rate});
  543. }
  544. /* Don't offset by the latency if the source isn't playing. */
  545. if(status == AL_PLAYING)
  546. pts -= nanoseconds{offset[1]};
  547. }
  548. return std::max(pts, nanoseconds::zero());
  549. }
  550. bool AudioState::startPlayback()
  551. {
  552. const size_t woffset{mWritePos.load(std::memory_order_acquire)};
  553. const size_t roffset{mReadPos.load(std::memory_order_relaxed)};
  554. const size_t readable{((woffset >= roffset) ? woffset : (mBufferData.size()+woffset)) -
  555. roffset};
  556. if(!mBufferData.empty())
  557. {
  558. if(readable == 0)
  559. return false;
  560. if(!alcGetInteger64vSOFT)
  561. mDeviceStartTime = mCurrentPts -
  562. nanoseconds{seconds{readable/mFrameSize}}/mCodecCtx->sample_rate;
  563. }
  564. else
  565. {
  566. ALint queued{};
  567. alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
  568. if(queued == 0) return false;
  569. }
  570. alSourcePlay(mSource);
  571. if(alcGetInteger64vSOFT)
  572. {
  573. /* Subtract the total buffer queue time from the current pts to get the
  574. * pts of the start of the queue.
  575. */
  576. std::array<int64_t,2> srctimes{};
  577. alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_CLOCK_SOFT, srctimes.data());
  578. auto device_time = nanoseconds{srctimes[1]};
  579. auto src_offset = duration_cast<nanoseconds>(fixed32{srctimes[0]}) /
  580. mCodecCtx->sample_rate;
  581. /* The mixer may have ticked and incremented the device time and sample
  582. * offset, so subtract the source offset from the device time to get
  583. * the device time the source started at. Also subtract startpts to get
  584. * the device time the stream would have started at to reach where it
  585. * is now.
  586. */
  587. if(!mBufferData.empty())
  588. {
  589. nanoseconds startpts{mCurrentPts -
  590. nanoseconds{seconds{readable/mFrameSize}}/mCodecCtx->sample_rate};
  591. mDeviceStartTime = device_time - src_offset - startpts;
  592. }
  593. else
  594. {
  595. nanoseconds startpts{mCurrentPts - AudioBufferTotalTime};
  596. mDeviceStartTime = device_time - src_offset - startpts;
  597. }
  598. }
  599. return true;
  600. }
  601. int AudioState::getSync()
  602. {
  603. if(mMovie.mAVSyncType == SyncMaster::Audio)
  604. return 0;
  605. auto ref_clock = mMovie.getMasterClock();
  606. auto diff = ref_clock - getClockNoLock();
  607. if(!(diff < AVNoSyncThreshold && diff > -AVNoSyncThreshold))
  608. {
  609. /* Difference is TOO big; reset accumulated average */
  610. mClockDiffAvg = seconds_d64::zero();
  611. return 0;
  612. }
  613. /* Accumulate the diffs */
  614. mClockDiffAvg = mClockDiffAvg*AudioAvgFilterCoeff + diff;
  615. auto avg_diff = mClockDiffAvg*(1.0 - AudioAvgFilterCoeff);
  616. if(avg_diff < AudioSyncThreshold/2.0 && avg_diff > -AudioSyncThreshold)
  617. return 0;
  618. /* Constrain the per-update difference to avoid exceedingly large skips */
  619. diff = std::min<nanoseconds>(diff, AudioSampleCorrectionMax);
  620. return static_cast<int>(duration_cast<seconds>(diff*mCodecCtx->sample_rate).count());
  621. }
  622. int AudioState::decodeFrame()
  623. {
  624. do {
  625. while(int ret{mQueue.receiveFrame(mCodecCtx.get(), mDecodedFrame.get())})
  626. {
  627. if(ret == AVErrorEOF) return 0;
  628. fmt::println(stderr, "Failed to receive frame: {}", ret);
  629. }
  630. } while(mDecodedFrame->nb_samples <= 0);
  631. /* If provided, update w/ pts */
  632. if(mDecodedFrame->best_effort_timestamp != AVNoPtsValue)
  633. mCurrentPts = duration_cast<nanoseconds>(seconds_d64{av_q2d(mStream->time_base) *
  634. static_cast<double>(mDecodedFrame->best_effort_timestamp)});
  635. if(mDecodedFrame->nb_samples > mSamplesMax)
  636. {
  637. av_freep(static_cast<void*>(mSamples.data()));
  638. av_samples_alloc(mSamples.data(), nullptr, mCodecCtx->ch_layout.nb_channels,
  639. mDecodedFrame->nb_samples, mDstSampleFmt, 0);
  640. mSamplesMax = mDecodedFrame->nb_samples;
  641. mSamplesSpan = {mSamples[0], static_cast<size_t>(mSamplesMax)*mFrameSize};
  642. }
  643. /* Return the amount of sample frames converted */
  644. const int data_size{swr_convert(mSwresCtx.get(), mSamples.data(), mDecodedFrame->nb_samples,
  645. mDecodedFrame->extended_data, mDecodedFrame->nb_samples)};
  646. av_frame_unref(mDecodedFrame.get());
  647. return data_size;
  648. }
  649. /* Duplicates the sample at in to out, count times. The frame size is a
  650. * multiple of the template type size.
  651. */
  652. template<typename T>
  653. void sample_dup(al::span<uint8_t> out, al::span<const uint8_t> in, size_t count, size_t frame_size)
  654. {
  655. auto sample = al::span{reinterpret_cast<const T*>(in.data()), in.size()/sizeof(T)};
  656. auto dst = al::span{reinterpret_cast<T*>(out.data()), out.size()/sizeof(T)};
  657. /* NOTE: frame_size is a multiple of sizeof(T). */
  658. const size_t type_mult{frame_size / sizeof(T)};
  659. if(type_mult == 1)
  660. std::fill_n(dst.begin(), count, sample.front());
  661. else for(size_t i{0};i < count;++i)
  662. {
  663. for(size_t j{0};j < type_mult;++j)
  664. dst[i*type_mult + j] = sample[j];
  665. }
  666. }
  667. void sample_dup(al::span<uint8_t> out, al::span<const uint8_t> in, size_t count, size_t frame_size)
  668. {
  669. if((frame_size&7) == 0)
  670. sample_dup<uint64_t>(out, in, count, frame_size);
  671. else if((frame_size&3) == 0)
  672. sample_dup<uint32_t>(out, in, count, frame_size);
  673. else if((frame_size&1) == 0)
  674. sample_dup<uint16_t>(out, in, count, frame_size);
  675. else
  676. sample_dup<uint8_t>(out, in, count, frame_size);
  677. }
  678. bool AudioState::readAudio(al::span<uint8_t> samples, unsigned int length, int &sample_skip)
  679. {
  680. unsigned int audio_size{0};
  681. /* Read the next chunk of data, refill the buffer, and queue it
  682. * on the source */
  683. length /= mFrameSize;
  684. while(mSamplesLen > 0 && audio_size < length)
  685. {
  686. unsigned int rem{length - audio_size};
  687. if(mSamplesPos >= 0)
  688. {
  689. rem = std::min(rem, static_cast<unsigned int>(mSamplesLen - mSamplesPos));
  690. const size_t boffset{static_cast<ALuint>(mSamplesPos) * size_t{mFrameSize}};
  691. std::copy_n(mSamplesSpan.cbegin()+ptrdiff_t(boffset), rem*size_t{mFrameSize},
  692. samples.begin());
  693. }
  694. else
  695. {
  696. rem = std::min(rem, static_cast<unsigned int>(-mSamplesPos));
  697. /* Add samples by copying the first sample */
  698. sample_dup(samples, mSamplesSpan, rem, mFrameSize);
  699. }
  700. mSamplesPos += static_cast<int>(rem);
  701. mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
  702. samples = samples.subspan(rem*size_t{mFrameSize});
  703. audio_size += rem;
  704. while(mSamplesPos >= mSamplesLen)
  705. {
  706. mSamplesLen = decodeFrame();
  707. mSamplesPos = std::min(mSamplesLen, sample_skip);
  708. if(mSamplesLen <= 0) break;
  709. sample_skip -= mSamplesPos;
  710. // Adjust the device start time and current pts by the amount we're
  711. // skipping/duplicating, so that the clock remains correct for the
  712. // current stream position.
  713. auto skip = nanoseconds{seconds{mSamplesPos}} / mCodecCtx->sample_rate;
  714. mDeviceStartTime -= skip;
  715. mCurrentPts += skip;
  716. }
  717. }
  718. if(audio_size <= 0)
  719. return false;
  720. if(audio_size < length)
  721. {
  722. const unsigned int rem{length - audio_size};
  723. std::fill_n(samples.begin(), rem*mFrameSize,
  724. (mDstSampleFmt == AV_SAMPLE_FMT_U8) ? 0x80 : 0x00);
  725. mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
  726. }
  727. return true;
  728. }
  729. bool AudioState::readAudio(int sample_skip)
  730. {
  731. size_t woffset{mWritePos.load(std::memory_order_acquire)};
  732. const size_t roffset{mReadPos.load(std::memory_order_relaxed)};
  733. while(mSamplesLen > 0)
  734. {
  735. const size_t nsamples{((roffset > woffset) ? roffset-woffset-1
  736. : (roffset == 0) ? (mBufferData.size()-woffset-1)
  737. : (mBufferData.size()-woffset)) / mFrameSize};
  738. if(!nsamples) break;
  739. if(mSamplesPos < 0)
  740. {
  741. const size_t rem{std::min<size_t>(nsamples, static_cast<ALuint>(-mSamplesPos))};
  742. sample_dup(al::span{mBufferData}.subspan(woffset), mSamplesSpan, rem, mFrameSize);
  743. woffset += rem * mFrameSize;
  744. if(woffset == mBufferData.size()) woffset = 0;
  745. mWritePos.store(woffset, std::memory_order_release);
  746. mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
  747. mSamplesPos += static_cast<int>(rem);
  748. continue;
  749. }
  750. const size_t rem{std::min<size_t>(nsamples, static_cast<ALuint>(mSamplesLen-mSamplesPos))};
  751. const size_t boffset{static_cast<ALuint>(mSamplesPos) * size_t{mFrameSize}};
  752. const size_t nbytes{rem * mFrameSize};
  753. std::copy_n(mSamplesSpan.cbegin()+ptrdiff_t(boffset), nbytes,
  754. mBufferData.begin()+ptrdiff_t(woffset));
  755. woffset += nbytes;
  756. if(woffset == mBufferData.size()) woffset = 0;
  757. mWritePos.store(woffset, std::memory_order_release);
  758. mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
  759. mSamplesPos += static_cast<int>(rem);
  760. while(mSamplesPos >= mSamplesLen)
  761. {
  762. mSamplesLen = decodeFrame();
  763. mSamplesPos = std::min(mSamplesLen, sample_skip);
  764. if(mSamplesLen <= 0) return false;
  765. sample_skip -= mSamplesPos;
  766. auto skip = nanoseconds{seconds{mSamplesPos}} / mCodecCtx->sample_rate;
  767. mDeviceStartTime -= skip;
  768. mCurrentPts += skip;
  769. }
  770. }
  771. return true;
  772. }
  773. void AL_APIENTRY AudioState::eventCallback(ALenum eventType, ALuint object, ALuint param,
  774. ALsizei length, const ALchar *message) noexcept
  775. {
  776. if(eventType == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT)
  777. {
  778. /* Temporarily lock the source mutex to ensure it's not between
  779. * checking the processed count and going to sleep.
  780. */
  781. std::unique_lock<std::mutex>{mSrcMutex}.unlock();
  782. mSrcCond.notify_one();
  783. return;
  784. }
  785. fmt::print("\n---- AL Event on AudioState {:p} ----\nEvent: ", voidp{this});
  786. switch(eventType)
  787. {
  788. case AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT: fmt::print("Buffer completed"); break;
  789. case AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT: fmt::print("Source state changed"); break;
  790. case AL_EVENT_TYPE_DISCONNECTED_SOFT: fmt::print("Disconnected"); break;
  791. default: fmt::print("{:#x}", as_unsigned(eventType)); break;
  792. }
  793. fmt::println("\n"
  794. "Object ID: {}\n"
  795. "Parameter: {}\n"
  796. "Message: {}\n----",
  797. object, param, std::string_view{message, static_cast<ALuint>(length)});
  798. if(eventType == AL_EVENT_TYPE_DISCONNECTED_SOFT)
  799. {
  800. {
  801. std::lock_guard<std::mutex> lock{mSrcMutex};
  802. mConnected.clear(std::memory_order_release);
  803. }
  804. mSrcCond.notify_one();
  805. }
  806. }
  807. ALsizei AudioState::bufferCallback(void *data, ALsizei size) noexcept
  808. {
  809. auto dst = al::span{static_cast<ALbyte*>(data), static_cast<ALuint>(size)};
  810. ALsizei got{0};
  811. size_t roffset{mReadPos.load(std::memory_order_acquire)};
  812. while(!dst.empty())
  813. {
  814. const size_t woffset{mWritePos.load(std::memory_order_relaxed)};
  815. if(woffset == roffset) break;
  816. size_t todo{((woffset < roffset) ? mBufferData.size() : woffset) - roffset};
  817. todo = std::min(todo, dst.size());
  818. std::copy_n(mBufferData.cbegin()+ptrdiff_t(roffset), todo, dst.begin());
  819. dst = dst.subspan(todo);
  820. got += static_cast<ALsizei>(todo);
  821. roffset += todo;
  822. if(roffset == mBufferData.size())
  823. roffset = 0;
  824. }
  825. mReadPos.store(roffset, std::memory_order_release);
  826. return got;
  827. }
  828. int AudioState::handler()
  829. {
  830. std::unique_lock<std::mutex> srclock{mSrcMutex, std::defer_lock};
  831. milliseconds sleep_time{AudioBufferTime / 3};
  832. struct EventControlManager {
  833. const std::array<ALenum,3> evt_types{{
  834. AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT,
  835. AL_EVENT_TYPE_DISCONNECTED_SOFT}};
  836. explicit EventControlManager(milliseconds &sleep_time)
  837. {
  838. if(alEventControlSOFT)
  839. {
  840. alEventControlSOFT(static_cast<ALsizei>(evt_types.size()), evt_types.data(),
  841. AL_TRUE);
  842. alEventCallbackSOFT(&AudioState::eventCallbackC, this);
  843. sleep_time = AudioBufferTotalTime;
  844. }
  845. }
  846. ~EventControlManager()
  847. {
  848. if(alEventControlSOFT)
  849. {
  850. alEventControlSOFT(static_cast<ALsizei>(evt_types.size()), evt_types.data(),
  851. AL_FALSE);
  852. alEventCallbackSOFT(nullptr, nullptr);
  853. }
  854. }
  855. };
  856. EventControlManager event_controller{sleep_time};
  857. std::vector<uint8_t> samples;
  858. ALsizei buffer_len{0};
  859. /* Note that ffmpeg assumes AmbiX (ACN layout, SN3D normalization). Only
  860. * support HOA when OpenAL can take AmbiX natively (if AmbiX -> FuMa
  861. * conversion is needed, we don't bother with higher order channels).
  862. */
  863. const auto has_bfmt = bool{alIsExtensionPresent("AL_EXT_BFORMAT") != AL_FALSE};
  864. const auto has_bfmt_ex = bool{alIsExtensionPresent("AL_SOFT_bformat_ex") != AL_FALSE};
  865. const auto has_bfmt_hoa = bool{has_bfmt_ex
  866. && alIsExtensionPresent("AL_SOFT_bformat_hoa") != AL_FALSE};
  867. /* AL_SOFT_bformat_hoa supports up to 14th order (225 channels). */
  868. const auto max_ambi_order = has_bfmt_hoa ? 14 : 1;
  869. auto ambi_order = 0;
  870. /* Find a suitable format for OpenAL. */
  871. const auto layoutmask = mCodecCtx->ch_layout.u.mask; /* NOLINT(*-union-access) */
  872. mDstChanLayout = 0;
  873. mFormat = AL_NONE;
  874. if((mCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLT || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLTP
  875. || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_DBL
  876. || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_DBLP
  877. || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S32
  878. || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S32P
  879. || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S64
  880. || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S64P)
  881. && alIsExtensionPresent("AL_EXT_FLOAT32"))
  882. {
  883. mDstSampleFmt = AV_SAMPLE_FMT_FLT;
  884. mFrameSize = 4;
  885. if(mCodecCtx->ch_layout.order == AV_CHANNEL_ORDER_NATIVE)
  886. {
  887. if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
  888. {
  889. if(layoutmask == AV_CH_LAYOUT_7POINT1)
  890. {
  891. mDstChanLayout = layoutmask;
  892. mFrameSize *= 8;
  893. mFormat = alGetEnumValue("AL_FORMAT_71CHN32");
  894. }
  895. if(layoutmask == AV_CH_LAYOUT_5POINT1 || layoutmask == AV_CH_LAYOUT_5POINT1_BACK)
  896. {
  897. mDstChanLayout = layoutmask;
  898. mFrameSize *= 6;
  899. mFormat = alGetEnumValue("AL_FORMAT_51CHN32");
  900. }
  901. if(layoutmask == AV_CH_LAYOUT_QUAD)
  902. {
  903. mDstChanLayout = layoutmask;
  904. mFrameSize *= 4;
  905. mFormat = EnableUhj ? AL_FORMAT_UHJ4CHN_FLOAT32_SOFT
  906. : alGetEnumValue("AL_FORMAT_QUAD32");
  907. }
  908. }
  909. if(layoutmask == AV_CH_LAYOUT_MONO)
  910. {
  911. mDstChanLayout = layoutmask;
  912. mFrameSize *= 1;
  913. mFormat = AL_FORMAT_MONO_FLOAT32;
  914. }
  915. }
  916. else if(mCodecCtx->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC && has_bfmt)
  917. {
  918. /* Calculate what should be the ambisonic order from the number of
  919. * channels, and confirm that's the number of channels. Opus allows
  920. * an optional non-diegetic stereo stream with the B-Format stream,
  921. * which we can ignore, so check for that too.
  922. */
  923. auto order = static_cast<int>(std::sqrt(mCodecCtx->ch_layout.nb_channels)) - 1;
  924. auto channels = ALuint(order+1) * ALuint(order+1);
  925. if(channels == ALuint(mCodecCtx->ch_layout.nb_channels)
  926. || channels+2 == ALuint(mCodecCtx->ch_layout.nb_channels))
  927. {
  928. /* OpenAL only supports first-order with AL_EXT_BFORMAT, which
  929. * is 4 channels for 3D buffers, unless AL_SOFT_bformat_hoa is
  930. * also supported.
  931. */
  932. ambi_order = std::min(order, max_ambi_order);
  933. mFrameSize *= ALuint(ambi_order+1) * ALuint(ambi_order+1);
  934. mFormat = alGetEnumValue("AL_FORMAT_BFORMAT3D_FLOAT32");
  935. }
  936. }
  937. if(!mFormat || mFormat == -1)
  938. {
  939. mDstChanLayout = AV_CH_LAYOUT_STEREO;
  940. mFrameSize *= 2;
  941. mFormat = EnableUhj ? AL_FORMAT_UHJ2CHN_FLOAT32_SOFT : AL_FORMAT_STEREO_FLOAT32;
  942. }
  943. }
  944. if(mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8 || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8P)
  945. {
  946. mDstSampleFmt = AV_SAMPLE_FMT_U8;
  947. mFrameSize = 1;
  948. if(mCodecCtx->ch_layout.order == AV_CHANNEL_ORDER_NATIVE)
  949. {
  950. if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
  951. {
  952. if(layoutmask == AV_CH_LAYOUT_7POINT1)
  953. {
  954. mDstChanLayout = layoutmask;
  955. mFrameSize *= 8;
  956. mFormat = alGetEnumValue("AL_FORMAT_71CHN8");
  957. }
  958. if(layoutmask == AV_CH_LAYOUT_5POINT1 || layoutmask == AV_CH_LAYOUT_5POINT1_BACK)
  959. {
  960. mDstChanLayout = layoutmask;
  961. mFrameSize *= 6;
  962. mFormat = alGetEnumValue("AL_FORMAT_51CHN8");
  963. }
  964. if(layoutmask == AV_CH_LAYOUT_QUAD)
  965. {
  966. mDstChanLayout = layoutmask;
  967. mFrameSize *= 4;
  968. mFormat = EnableUhj ? AL_FORMAT_UHJ4CHN8_SOFT
  969. : alGetEnumValue("AL_FORMAT_QUAD8");
  970. }
  971. }
  972. if(layoutmask == AV_CH_LAYOUT_MONO)
  973. {
  974. mDstChanLayout = layoutmask;
  975. mFrameSize *= 1;
  976. mFormat = AL_FORMAT_MONO8;
  977. }
  978. }
  979. else if(mCodecCtx->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC && has_bfmt)
  980. {
  981. auto order = static_cast<int>(std::sqrt(mCodecCtx->ch_layout.nb_channels)) - 1;
  982. auto channels = (order+1) * (order+1);
  983. if(channels == mCodecCtx->ch_layout.nb_channels
  984. || channels+2 == mCodecCtx->ch_layout.nb_channels)
  985. {
  986. ambi_order = std::min(order, max_ambi_order);
  987. mFrameSize *= ALuint(ambi_order+1) * ALuint(ambi_order+1);
  988. mFormat = alGetEnumValue("AL_FORMAT_BFORMAT3D_8");
  989. }
  990. }
  991. if(!mFormat || mFormat == -1)
  992. {
  993. mDstChanLayout = AV_CH_LAYOUT_STEREO;
  994. mFrameSize *= 2;
  995. mFormat = EnableUhj ? AL_FORMAT_UHJ2CHN8_SOFT : AL_FORMAT_STEREO8;
  996. }
  997. }
  998. if(!mFormat || mFormat == -1)
  999. {
  1000. mDstSampleFmt = AV_SAMPLE_FMT_S16;
  1001. mFrameSize = 2;
  1002. if(mCodecCtx->ch_layout.order == AV_CHANNEL_ORDER_NATIVE)
  1003. {
  1004. if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
  1005. {
  1006. if(layoutmask == AV_CH_LAYOUT_7POINT1)
  1007. {
  1008. mDstChanLayout = layoutmask;
  1009. mFrameSize *= 8;
  1010. mFormat = alGetEnumValue("AL_FORMAT_71CHN16");
  1011. }
  1012. if(layoutmask == AV_CH_LAYOUT_5POINT1 || layoutmask == AV_CH_LAYOUT_5POINT1_BACK)
  1013. {
  1014. mDstChanLayout = layoutmask;
  1015. mFrameSize *= 6;
  1016. mFormat = alGetEnumValue("AL_FORMAT_51CHN16");
  1017. }
  1018. if(layoutmask == AV_CH_LAYOUT_QUAD)
  1019. {
  1020. mDstChanLayout = layoutmask;
  1021. mFrameSize *= 4;
  1022. mFormat = EnableUhj ? AL_FORMAT_UHJ4CHN16_SOFT
  1023. : alGetEnumValue("AL_FORMAT_QUAD16");
  1024. }
  1025. }
  1026. if(layoutmask == AV_CH_LAYOUT_MONO)
  1027. {
  1028. mDstChanLayout = layoutmask;
  1029. mFrameSize *= 1;
  1030. mFormat = AL_FORMAT_MONO16;
  1031. }
  1032. }
  1033. else if(mCodecCtx->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC && has_bfmt)
  1034. {
  1035. auto order = static_cast<int>(std::sqrt(mCodecCtx->ch_layout.nb_channels)) - 1;
  1036. auto channels = (order+1) * (order+1);
  1037. if(channels == mCodecCtx->ch_layout.nb_channels
  1038. || channels+2 == mCodecCtx->ch_layout.nb_channels)
  1039. {
  1040. ambi_order = std::min(order, max_ambi_order);
  1041. mFrameSize *= ALuint(ambi_order+1) * ALuint(ambi_order+1);
  1042. mFormat = alGetEnumValue("AL_FORMAT_BFORMAT3D_16");
  1043. }
  1044. }
  1045. if(!mFormat || mFormat == -1)
  1046. {
  1047. mDstChanLayout = AV_CH_LAYOUT_STEREO;
  1048. mFrameSize *= 2;
  1049. mFormat = EnableUhj ? AL_FORMAT_UHJ2CHN16_SOFT : AL_FORMAT_STEREO16;
  1050. }
  1051. }
  1052. mSamples.fill(nullptr);
  1053. mSamplesSpan = {};
  1054. mSamplesMax = 0;
  1055. mSamplesPos = 0;
  1056. mSamplesLen = 0;
  1057. mDecodedFrame.reset(av_frame_alloc());
  1058. if(!mDecodedFrame)
  1059. {
  1060. fmt::println(stderr, "Failed to allocate audio frame");
  1061. return 0;
  1062. }
  1063. if(!mDstChanLayout)
  1064. {
  1065. auto layout = ChannelLayout{};
  1066. av_channel_layout_from_string(&layout, fmt::format("ambisonic {}", ambi_order).c_str());
  1067. const auto err = swr_alloc_set_opts2(al::out_ptr(mSwresCtx), &layout, mDstSampleFmt,
  1068. mCodecCtx->sample_rate, &mCodecCtx->ch_layout, mCodecCtx->sample_fmt,
  1069. mCodecCtx->sample_rate, 0, nullptr);
  1070. if(err != 0)
  1071. {
  1072. std::array<char,AV_ERROR_MAX_STRING_SIZE> errstr{};
  1073. fmt::println(stderr, "Failed to allocate SwrContext: {}",
  1074. av_make_error_string(errstr.data(), AV_ERROR_MAX_STRING_SIZE, err));
  1075. return 0;
  1076. }
  1077. if(has_bfmt_hoa && ambi_order > 1)
  1078. fmt::println("Found AL_SOFT_bformat_hoa (order {})", ambi_order);
  1079. else if(has_bfmt_ex)
  1080. fmt::println("Found AL_SOFT_bformat_ex");
  1081. else
  1082. {
  1083. fmt::println("Found AL_EXT_BFORMAT");
  1084. /* Without AL_SOFT_bformat_ex, OpenAL only supports FuMa channel
  1085. * ordering and normalization, so a custom matrix is needed to
  1086. * scale and reorder the source from AmbiX.
  1087. */
  1088. std::vector<double> mtx(64_uz*64_uz, 0.0);
  1089. mtx[0 + 0*64] = std::sqrt(0.5);
  1090. mtx[3 + 1*64] = 1.0;
  1091. mtx[1 + 2*64] = 1.0;
  1092. mtx[2 + 3*64] = 1.0;
  1093. swr_set_matrix(mSwresCtx.get(), mtx.data(), 64);
  1094. }
  1095. }
  1096. else
  1097. {
  1098. ChannelLayout layout{};
  1099. av_channel_layout_from_mask(&layout, mDstChanLayout);
  1100. int err{swr_alloc_set_opts2(al::out_ptr(mSwresCtx), &layout, mDstSampleFmt,
  1101. mCodecCtx->sample_rate, &mCodecCtx->ch_layout, mCodecCtx->sample_fmt,
  1102. mCodecCtx->sample_rate, 0, nullptr)};
  1103. if(err != 0)
  1104. {
  1105. std::array<char,AV_ERROR_MAX_STRING_SIZE> errstr{};
  1106. fmt::println(stderr, "Failed to allocate SwrContext: {}",
  1107. av_make_error_string(errstr.data(), AV_ERROR_MAX_STRING_SIZE, err));
  1108. return 0;
  1109. }
  1110. }
  1111. if(int err{swr_init(mSwresCtx.get())})
  1112. {
  1113. std::array<char,AV_ERROR_MAX_STRING_SIZE> errstr{};
  1114. fmt::println(stderr, "Failed to initialize audio converter: {}",
  1115. av_make_error_string(errstr.data(), AV_ERROR_MAX_STRING_SIZE, err));
  1116. return 0;
  1117. }
  1118. alGenBuffers(static_cast<ALsizei>(mBuffers.size()), mBuffers.data());
  1119. alGenSources(1, &mSource);
  1120. if(DirectOutMode)
  1121. alSourcei(mSource, AL_DIRECT_CHANNELS_SOFT, DirectOutMode);
  1122. if(EnableWideStereo)
  1123. {
  1124. static constexpr std::array angles{static_cast<float>(al::numbers::pi / 3.0),
  1125. static_cast<float>(-al::numbers::pi / 3.0)};
  1126. alSourcefv(mSource, AL_STEREO_ANGLES, angles.data());
  1127. }
  1128. if(has_bfmt_ex)
  1129. {
  1130. for(ALuint bufid : mBuffers)
  1131. {
  1132. alBufferi(bufid, AL_AMBISONIC_LAYOUT_SOFT, AL_ACN_SOFT);
  1133. alBufferi(bufid, AL_AMBISONIC_SCALING_SOFT, AL_SN3D_SOFT);
  1134. }
  1135. }
  1136. if(ambi_order > 1)
  1137. {
  1138. for(ALuint bufid : mBuffers)
  1139. alBufferi(bufid, AL_UNPACK_AMBISONIC_ORDER_SOFT, ambi_order);
  1140. }
  1141. #ifdef AL_SOFT_UHJ
  1142. if(EnableSuperStereo)
  1143. alSourcei(mSource, AL_STEREO_MODE_SOFT, AL_SUPER_STEREO_SOFT);
  1144. #endif
  1145. if(alGetError() != AL_NO_ERROR)
  1146. return 0;
  1147. bool callback_ok{false};
  1148. if(alBufferCallbackSOFT)
  1149. {
  1150. alBufferCallbackSOFT(mBuffers[0], mFormat, mCodecCtx->sample_rate, bufferCallbackC, this);
  1151. alSourcei(mSource, AL_BUFFER, static_cast<ALint>(mBuffers[0]));
  1152. if(alGetError() != AL_NO_ERROR)
  1153. {
  1154. fmt::println(stderr, "Failed to set buffer callback");
  1155. alSourcei(mSource, AL_BUFFER, 0);
  1156. }
  1157. else
  1158. {
  1159. mBufferData.resize(static_cast<size_t>(duration_cast<seconds>(mCodecCtx->sample_rate *
  1160. AudioBufferTotalTime).count()) * mFrameSize);
  1161. std::fill(mBufferData.begin(), mBufferData.end(), uint8_t{});
  1162. mReadPos.store(0, std::memory_order_relaxed);
  1163. mWritePos.store(mBufferData.size()/mFrameSize/2*mFrameSize, std::memory_order_relaxed);
  1164. ALCint refresh{};
  1165. alcGetIntegerv(alcGetContextsDevice(alcGetCurrentContext()), ALC_REFRESH, 1, &refresh);
  1166. sleep_time = milliseconds{seconds{1}} / refresh;
  1167. callback_ok = true;
  1168. }
  1169. }
  1170. if(!callback_ok)
  1171. buffer_len = static_cast<int>(duration_cast<seconds>(mCodecCtx->sample_rate *
  1172. AudioBufferTime).count() * mFrameSize);
  1173. if(buffer_len > 0)
  1174. samples.resize(static_cast<ALuint>(buffer_len));
  1175. /* Prefill the codec buffer. */
  1176. auto packet_sender = [this]()
  1177. {
  1178. while(true)
  1179. {
  1180. const int ret{mQueue.sendPacket(mCodecCtx.get())};
  1181. if(ret == AVErrorEOF) break;
  1182. }
  1183. };
  1184. auto sender [[maybe_unused]] = std::async(std::launch::async, packet_sender);
  1185. srclock.lock();
  1186. if(alcGetInteger64vSOFT)
  1187. {
  1188. int64_t devtime{};
  1189. alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()), ALC_DEVICE_CLOCK_SOFT,
  1190. 1, &devtime);
  1191. mDeviceStartTime = nanoseconds{devtime} - mCurrentPts;
  1192. }
  1193. mSamplesLen = decodeFrame();
  1194. if(mSamplesLen > 0)
  1195. {
  1196. mSamplesPos = std::min(mSamplesLen, getSync());
  1197. auto skip = nanoseconds{seconds{mSamplesPos}} / mCodecCtx->sample_rate;
  1198. mDeviceStartTime -= skip;
  1199. mCurrentPts += skip;
  1200. }
  1201. while(true)
  1202. {
  1203. if(mMovie.mQuit.load(std::memory_order_relaxed))
  1204. {
  1205. /* If mQuit is set, drain frames until we can't get more audio,
  1206. * indicating we've reached the flush packet and the packet sender
  1207. * will also quit.
  1208. */
  1209. do {
  1210. mSamplesLen = decodeFrame();
  1211. mSamplesPos = mSamplesLen;
  1212. } while(mSamplesLen > 0);
  1213. break;
  1214. }
  1215. ALenum state;
  1216. if(!mBufferData.empty())
  1217. {
  1218. alGetSourcei(mSource, AL_SOURCE_STATE, &state);
  1219. /* If mQuit is not set, don't quit even if there's no more audio,
  1220. * so what's buffered has a chance to play to the real end.
  1221. */
  1222. readAudio(getSync());
  1223. }
  1224. else
  1225. {
  1226. ALint processed, queued;
  1227. /* First remove any processed buffers. */
  1228. alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
  1229. while(processed > 0)
  1230. {
  1231. ALuint bid;
  1232. alSourceUnqueueBuffers(mSource, 1, &bid);
  1233. --processed;
  1234. }
  1235. /* Refill the buffer queue. */
  1236. int sync_skip{getSync()};
  1237. alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
  1238. while(static_cast<ALuint>(queued) < mBuffers.size())
  1239. {
  1240. /* Read the next chunk of data, filling the buffer, and queue
  1241. * it on the source.
  1242. */
  1243. if(!readAudio(samples, static_cast<ALuint>(buffer_len), sync_skip))
  1244. break;
  1245. const ALuint bufid{mBuffers[mBufferIdx]};
  1246. mBufferIdx = static_cast<ALuint>((mBufferIdx+1) % mBuffers.size());
  1247. alBufferData(bufid, mFormat, samples.data(), buffer_len, mCodecCtx->sample_rate);
  1248. alSourceQueueBuffers(mSource, 1, &bufid);
  1249. ++queued;
  1250. }
  1251. /* Check that the source is playing. */
  1252. alGetSourcei(mSource, AL_SOURCE_STATE, &state);
  1253. if(state == AL_STOPPED)
  1254. {
  1255. /* AL_STOPPED means there was an underrun. Clear the buffer
  1256. * queue since this likely means we're late, and rewind the
  1257. * source to get it back into an AL_INITIAL state.
  1258. */
  1259. alSourceRewind(mSource);
  1260. alSourcei(mSource, AL_BUFFER, 0);
  1261. if(alcGetInteger64vSOFT)
  1262. {
  1263. /* Also update the device start time with the current
  1264. * device clock, so the decoder knows we're running behind.
  1265. */
  1266. int64_t devtime{};
  1267. alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()),
  1268. ALC_DEVICE_CLOCK_SOFT, 1, &devtime);
  1269. mDeviceStartTime = nanoseconds{devtime} - mCurrentPts;
  1270. }
  1271. continue;
  1272. }
  1273. }
  1274. /* (re)start the source if needed, and wait for a buffer to finish */
  1275. if(state != AL_PLAYING && state != AL_PAUSED)
  1276. {
  1277. if(!startPlayback())
  1278. break;
  1279. }
  1280. if(ALenum err{alGetError()})
  1281. fmt::println(stderr, "Got AL error: {:#x} ({})", as_unsigned(err), alGetString(err));
  1282. mSrcCond.wait_for(srclock, sleep_time);
  1283. }
  1284. alSourceRewind(mSource);
  1285. alSourcei(mSource, AL_BUFFER, 0);
  1286. srclock.unlock();
  1287. return 0;
  1288. }
  1289. nanoseconds VideoState::getClock()
  1290. {
  1291. /* NOTE: This returns incorrect times while not playing. */
  1292. std::lock_guard<std::mutex> displock{mDispPtsMutex};
  1293. if(mDisplayPtsTime == microseconds::min())
  1294. return nanoseconds::zero();
  1295. auto delta = get_avtime() - mDisplayPtsTime;
  1296. return mDisplayPts + delta;
  1297. }
  1298. /* Called by VideoState::updateVideo to display the next video frame. */
  1299. void VideoState::display(SDL_Renderer *renderer, AVFrame *frame) const
  1300. {
  1301. if(!mImage)
  1302. return;
  1303. auto frame_width = frame->width - static_cast<int>(frame->crop_left + frame->crop_right);
  1304. auto frame_height = frame->height - static_cast<int>(frame->crop_top + frame->crop_bottom);
  1305. const auto src_rect = SDL_FRect{ static_cast<float>(frame->crop_left),
  1306. static_cast<float>(frame->crop_top), static_cast<float>(frame_width),
  1307. static_cast<float>(frame_height) };
  1308. SDL_RenderTexture(renderer, mImage, &src_rect, nullptr);
  1309. SDL_RenderPresent(renderer);
  1310. }
  1311. /* Called regularly on the main thread where the SDL_Renderer was created. It
  1312. * handles updating the textures of decoded frames and displaying the latest
  1313. * frame.
  1314. */
  1315. void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer, bool redraw)
  1316. {
  1317. size_t read_idx{mPictQRead.load(std::memory_order_relaxed)};
  1318. Picture *vp{&mPictQ[read_idx]};
  1319. auto clocktime = mMovie.getMasterClock();
  1320. bool updated{false};
  1321. while(true)
  1322. {
  1323. size_t next_idx{(read_idx+1)%mPictQ.size()};
  1324. if(next_idx == mPictQWrite.load(std::memory_order_acquire))
  1325. break;
  1326. Picture *nextvp{&mPictQ[next_idx]};
  1327. if(clocktime < nextvp->mPts && !mMovie.mQuit.load(std::memory_order_relaxed))
  1328. {
  1329. /* For the first update, ensure the first frame gets shown. */
  1330. if(!mFirstUpdate || updated)
  1331. break;
  1332. }
  1333. vp = nextvp;
  1334. updated = true;
  1335. read_idx = next_idx;
  1336. }
  1337. if(mMovie.mQuit.load(std::memory_order_relaxed))
  1338. {
  1339. if(mEOS)
  1340. mFinalUpdate = true;
  1341. mPictQRead.store(read_idx, std::memory_order_release);
  1342. std::unique_lock<std::mutex>{mPictQMutex}.unlock();
  1343. mPictQCond.notify_one();
  1344. return;
  1345. }
  1346. AVFrame *frame{vp->mFrame.get()};
  1347. if(updated)
  1348. {
  1349. mPictQRead.store(read_idx, std::memory_order_release);
  1350. std::unique_lock<std::mutex>{mPictQMutex}.unlock();
  1351. mPictQCond.notify_one();
  1352. /* allocate or resize the buffer! */
  1353. if(!mImage || mWidth != frame->width || mHeight != frame->height
  1354. || frame->format != mAVFormat)
  1355. {
  1356. if(mImage)
  1357. SDL_DestroyTexture(mImage);
  1358. mImage = nullptr;
  1359. mSwscaleCtx = nullptr;
  1360. auto fmtiter = std::find_if(TextureFormatMap.begin(), TextureFormatMap.end(),
  1361. [frame](const TextureFormatEntry &entry) noexcept
  1362. { return frame->format == entry.avformat; });
  1363. if(fmtiter != TextureFormatMap.end())
  1364. {
  1365. auto props = SDLProps{};
  1366. props.setInt(SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, fmtiter->sdlformat);
  1367. props.setInt(SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STREAMING);
  1368. props.setInt(SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, frame->width);
  1369. props.setInt(SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, frame->height);
  1370. /* Should be a better way to check YCbCr vs RGB. */
  1371. const auto ctype = (frame->format == AV_PIX_FMT_YUV420P
  1372. || frame->format == AV_PIX_FMT_YUYV422
  1373. || frame->format == AV_PIX_FMT_UYVY422 || frame->format == AV_PIX_FMT_NV12
  1374. || frame->format == AV_PIX_FMT_NV21) ? SDL_COLOR_TYPE_YCBCR
  1375. : SDL_COLOR_TYPE_RGB;
  1376. const auto crange = std::invoke([frame]
  1377. {
  1378. switch(frame->color_range)
  1379. {
  1380. case AVCOL_RANGE_UNSPECIFIED: return SDL_COLOR_RANGE_UNKNOWN;
  1381. case AVCOL_RANGE_MPEG: return SDL_COLOR_RANGE_LIMITED;
  1382. case AVCOL_RANGE_JPEG: return SDL_COLOR_RANGE_FULL;
  1383. case AVCOL_RANGE_NB: break;
  1384. }
  1385. return SDL_COLOR_RANGE_UNKNOWN;
  1386. });
  1387. const auto cprims = std::invoke([frame]
  1388. {
  1389. switch(frame->color_primaries)
  1390. {
  1391. case AVCOL_PRI_RESERVED0: break;
  1392. case AVCOL_PRI_BT709: return SDL_COLOR_PRIMARIES_BT709;
  1393. case AVCOL_PRI_UNSPECIFIED: return SDL_COLOR_PRIMARIES_UNSPECIFIED;
  1394. case AVCOL_PRI_RESERVED: break;
  1395. case AVCOL_PRI_BT470M: return SDL_COLOR_PRIMARIES_BT470M;
  1396. case AVCOL_PRI_BT470BG: return SDL_COLOR_PRIMARIES_BT470BG;
  1397. case AVCOL_PRI_SMPTE170M: return SDL_COLOR_PRIMARIES_BT601;
  1398. case AVCOL_PRI_SMPTE240M: return SDL_COLOR_PRIMARIES_SMPTE240;
  1399. case AVCOL_PRI_FILM: return SDL_COLOR_PRIMARIES_GENERIC_FILM;
  1400. case AVCOL_PRI_BT2020: return SDL_COLOR_PRIMARIES_BT2020;
  1401. case AVCOL_PRI_SMPTE428: return SDL_COLOR_PRIMARIES_XYZ;
  1402. case AVCOL_PRI_SMPTE431: return SDL_COLOR_PRIMARIES_SMPTE431;
  1403. case AVCOL_PRI_SMPTE432: return SDL_COLOR_PRIMARIES_SMPTE432;
  1404. case AVCOL_PRI_EBU3213: return SDL_COLOR_PRIMARIES_EBU3213;
  1405. case AVCOL_PRI_NB: break;
  1406. }
  1407. return SDL_COLOR_PRIMARIES_UNKNOWN;
  1408. });
  1409. const auto ctransfer = std::invoke([frame]
  1410. {
  1411. switch(frame->color_trc)
  1412. {
  1413. case AVCOL_TRC_RESERVED0: break;
  1414. case AVCOL_TRC_BT709: return SDL_TRANSFER_CHARACTERISTICS_BT709;
  1415. case AVCOL_TRC_UNSPECIFIED: return SDL_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
  1416. case AVCOL_TRC_RESERVED: break;
  1417. case AVCOL_TRC_GAMMA22: return SDL_TRANSFER_CHARACTERISTICS_GAMMA22;
  1418. case AVCOL_TRC_GAMMA28: return SDL_TRANSFER_CHARACTERISTICS_GAMMA28;
  1419. case AVCOL_TRC_SMPTE170M: return SDL_TRANSFER_CHARACTERISTICS_BT601;
  1420. case AVCOL_TRC_SMPTE240M: return SDL_TRANSFER_CHARACTERISTICS_SMPTE240;
  1421. case AVCOL_TRC_LINEAR: return SDL_TRANSFER_CHARACTERISTICS_LINEAR;
  1422. case AVCOL_TRC_LOG: return SDL_TRANSFER_CHARACTERISTICS_LOG100;
  1423. case AVCOL_TRC_LOG_SQRT: return SDL_TRANSFER_CHARACTERISTICS_LOG100_SQRT10;
  1424. case AVCOL_TRC_IEC61966_2_4: return SDL_TRANSFER_CHARACTERISTICS_IEC61966;
  1425. case AVCOL_TRC_BT1361_ECG: return SDL_TRANSFER_CHARACTERISTICS_BT1361;
  1426. case AVCOL_TRC_IEC61966_2_1: return SDL_TRANSFER_CHARACTERISTICS_SRGB;
  1427. case AVCOL_TRC_BT2020_10: return SDL_TRANSFER_CHARACTERISTICS_BT2020_10BIT;
  1428. case AVCOL_TRC_BT2020_12: return SDL_TRANSFER_CHARACTERISTICS_BT2020_12BIT;
  1429. case AVCOL_TRC_SMPTE2084: return SDL_TRANSFER_CHARACTERISTICS_PQ;
  1430. case AVCOL_TRC_SMPTE428: return SDL_TRANSFER_CHARACTERISTICS_SMPTE428;
  1431. case AVCOL_TRC_ARIB_STD_B67: return SDL_TRANSFER_CHARACTERISTICS_HLG;
  1432. case AVCOL_TRC_NB: break;
  1433. }
  1434. return SDL_TRANSFER_CHARACTERISTICS_UNKNOWN;
  1435. });
  1436. const auto cmatrix = std::invoke([frame]
  1437. {
  1438. switch(frame->colorspace)
  1439. {
  1440. case AVCOL_SPC_RGB: return SDL_MATRIX_COEFFICIENTS_IDENTITY;
  1441. case AVCOL_SPC_BT709: return SDL_MATRIX_COEFFICIENTS_BT709;
  1442. case AVCOL_SPC_UNSPECIFIED: return SDL_MATRIX_COEFFICIENTS_UNSPECIFIED;
  1443. case AVCOL_SPC_RESERVED: break;
  1444. case AVCOL_SPC_FCC: return SDL_MATRIX_COEFFICIENTS_FCC;
  1445. case AVCOL_SPC_BT470BG: return SDL_MATRIX_COEFFICIENTS_BT470BG;
  1446. case AVCOL_SPC_SMPTE170M: return SDL_MATRIX_COEFFICIENTS_BT601;
  1447. case AVCOL_SPC_SMPTE240M: return SDL_MATRIX_COEFFICIENTS_SMPTE240;
  1448. case AVCOL_SPC_YCGCO: return SDL_MATRIX_COEFFICIENTS_YCGCO;
  1449. case AVCOL_SPC_BT2020_NCL: return SDL_MATRIX_COEFFICIENTS_BT2020_NCL;
  1450. case AVCOL_SPC_BT2020_CL: return SDL_MATRIX_COEFFICIENTS_BT2020_CL;
  1451. case AVCOL_SPC_SMPTE2085: return SDL_MATRIX_COEFFICIENTS_SMPTE2085;
  1452. case AVCOL_SPC_CHROMA_DERIVED_NCL: return SDL_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
  1453. case AVCOL_SPC_CHROMA_DERIVED_CL: return SDL_MATRIX_COEFFICIENTS_CHROMA_DERIVED_CL;
  1454. case AVCOL_SPC_ICTCP: return SDL_MATRIX_COEFFICIENTS_ICTCP;
  1455. case AVCOL_SPC_IPT_C2: break; // ???
  1456. case AVCOL_SPC_YCGCO_RE: return SDL_MATRIX_COEFFICIENTS_YCGCO; // ???
  1457. case AVCOL_SPC_YCGCO_RO: return SDL_MATRIX_COEFFICIENTS_YCGCO; // ???
  1458. case AVCOL_SPC_NB: break;
  1459. }
  1460. return SDL_MATRIX_COEFFICIENTS_UNSPECIFIED;
  1461. });
  1462. const auto cchromaloc = std::invoke([frame]
  1463. {
  1464. switch(frame->chroma_location)
  1465. {
  1466. case AVCHROMA_LOC_UNSPECIFIED: return SDL_CHROMA_LOCATION_NONE;
  1467. case AVCHROMA_LOC_LEFT: return SDL_CHROMA_LOCATION_LEFT;
  1468. case AVCHROMA_LOC_CENTER: return SDL_CHROMA_LOCATION_CENTER;
  1469. case AVCHROMA_LOC_TOPLEFT: return SDL_CHROMA_LOCATION_TOPLEFT;
  1470. case AVCHROMA_LOC_TOP: return SDL_CHROMA_LOCATION_TOPLEFT; // ???
  1471. case AVCHROMA_LOC_BOTTOMLEFT: return SDL_CHROMA_LOCATION_LEFT; // ???
  1472. case AVCHROMA_LOC_BOTTOM: return SDL_CHROMA_LOCATION_CENTER; // ???
  1473. case AVCHROMA_LOC_NB: break;
  1474. }
  1475. return SDL_CHROMA_LOCATION_NONE;
  1476. });
  1477. const auto colorspace = DefineSDLColorspace(ctype, crange, cprims, ctransfer,
  1478. cmatrix, cchromaloc);
  1479. props.setInt(SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, colorspace);
  1480. mImage = SDL_CreateTextureWithProperties(renderer, props.getid());
  1481. if(!mImage)
  1482. fmt::println(stderr, "Failed to create texture!");
  1483. mWidth = frame->width;
  1484. mHeight = frame->height;
  1485. mSDLFormat = fmtiter->sdlformat;
  1486. mAVFormat = fmtiter->avformat;
  1487. }
  1488. else
  1489. {
  1490. /* If there's no matching format, convert to RGB24. */
  1491. fmt::println(stderr, "Could not find SDL texture format for pix_fmt {0:#x} ({0})",
  1492. as_unsigned(frame->format));
  1493. auto props = SDLProps{};
  1494. props.setInt(SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, SDL_PIXELFORMAT_RGB24);
  1495. props.setInt(SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STREAMING);
  1496. props.setInt(SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, frame->width);
  1497. props.setInt(SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, frame->height);
  1498. mImage = SDL_CreateTextureWithProperties(renderer, props.getid());
  1499. if(!mImage)
  1500. fmt::println(stderr, "Failed to create texture!");
  1501. mWidth = frame->width;
  1502. mHeight = frame->height;
  1503. mSDLFormat = SDL_PIXELFORMAT_RGB24;
  1504. mAVFormat = frame->format;
  1505. mSwscaleCtx = SwsContextPtr{sws_getContext(
  1506. frame->width, frame->height, static_cast<AVPixelFormat>(frame->format),
  1507. frame->width, frame->height, AV_PIX_FMT_RGB24, 0,
  1508. nullptr, nullptr, nullptr)};
  1509. sws_setColorspaceDetails(mSwscaleCtx.get(), sws_getCoefficients(frame->colorspace),
  1510. (frame->color_range==AVCOL_RANGE_JPEG), sws_getCoefficients(SWS_CS_DEFAULT), 1,
  1511. 0<<16, 1<<16, 1<<16);
  1512. }
  1513. }
  1514. int frame_width{frame->width - static_cast<int>(frame->crop_left + frame->crop_right)};
  1515. int frame_height{frame->height - static_cast<int>(frame->crop_top + frame->crop_bottom)};
  1516. if(mFirstUpdate && frame_width > 0 && frame_height > 0)
  1517. {
  1518. /* For the first update, set the window size to the video size. */
  1519. mFirstUpdate = false;
  1520. if(frame->sample_aspect_ratio.den != 0)
  1521. {
  1522. double aspect_ratio = av_q2d(frame->sample_aspect_ratio);
  1523. if(aspect_ratio >= 1.0)
  1524. frame_width = static_cast<int>(std::lround(frame_width * aspect_ratio));
  1525. else if(aspect_ratio > 0.0)
  1526. frame_height = static_cast<int>(std::lround(frame_height / aspect_ratio));
  1527. }
  1528. if(SDL_SetWindowSize(screen, frame_width, frame_height))
  1529. SDL_SyncWindow(screen);
  1530. SDL_SetRenderLogicalPresentation(renderer, frame_width, frame_height,
  1531. SDL_LOGICAL_PRESENTATION_LETTERBOX);
  1532. }
  1533. if(mImage)
  1534. {
  1535. if(mSDLFormat == SDL_PIXELFORMAT_IYUV || mSDLFormat == SDL_PIXELFORMAT_YV12)
  1536. SDL_UpdateYUVTexture(mImage, nullptr,
  1537. frame->data[0], frame->linesize[0],
  1538. frame->data[1], frame->linesize[1],
  1539. frame->data[2], frame->linesize[2]);
  1540. else if(mSDLFormat == SDL_PIXELFORMAT_NV12 || mSDLFormat == SDL_PIXELFORMAT_NV21)
  1541. SDL_UpdateNVTexture(mImage, nullptr,
  1542. frame->data[0], frame->linesize[0],
  1543. frame->data[1], frame->linesize[1]);
  1544. else if(mSwscaleCtx)
  1545. {
  1546. auto pixels = voidp{};
  1547. auto pitch = int{};
  1548. if(!SDL_LockTexture(mImage, nullptr, &pixels, &pitch))
  1549. fmt::println(stderr, "Failed to lock texture: {}", SDL_GetError());
  1550. else
  1551. {
  1552. /* Formats passing through mSwscaleCtx are converted to
  1553. * 24-bit RGB, which is interleaved/non-planar.
  1554. */
  1555. const auto pict_data = std::array{static_cast<uint8_t*>(pixels)};
  1556. const auto pict_linesize = std::array{pitch};
  1557. sws_scale(mSwscaleCtx.get(), std::data(frame->data),
  1558. std::data(frame->linesize), 0, frame->height, pict_data.data(),
  1559. pict_linesize.data());
  1560. SDL_UnlockTexture(mImage);
  1561. }
  1562. }
  1563. else
  1564. SDL_UpdateTexture(mImage, nullptr, frame->data[0], frame->linesize[0]);
  1565. redraw = true;
  1566. }
  1567. }
  1568. if(redraw)
  1569. {
  1570. /* Show the picture! */
  1571. display(renderer, frame);
  1572. }
  1573. if(updated)
  1574. {
  1575. auto disp_time = get_avtime();
  1576. std::lock_guard<std::mutex> displock{mDispPtsMutex};
  1577. mDisplayPts = vp->mPts;
  1578. mDisplayPtsTime = disp_time;
  1579. }
  1580. if(mEOS.load(std::memory_order_acquire))
  1581. {
  1582. if((read_idx+1)%mPictQ.size() == mPictQWrite.load(std::memory_order_acquire))
  1583. {
  1584. mFinalUpdate = true;
  1585. std::unique_lock<std::mutex>{mPictQMutex}.unlock();
  1586. mPictQCond.notify_one();
  1587. }
  1588. }
  1589. }
  1590. int VideoState::handler()
  1591. {
  1592. std::for_each(mPictQ.begin(), mPictQ.end(),
  1593. [](Picture &pict) -> void
  1594. { pict.mFrame = AVFramePtr{av_frame_alloc()}; });
  1595. /* Prefill the codec buffer. */
  1596. auto sender [[maybe_unused]] = std::async(std::launch::async, [this]()
  1597. {
  1598. while(true)
  1599. {
  1600. const int ret{mQueue.sendPacket(mCodecCtx.get())};
  1601. if(ret == AVErrorEOF) break;
  1602. }
  1603. });
  1604. {
  1605. std::lock_guard<std::mutex> displock{mDispPtsMutex};
  1606. mDisplayPtsTime = get_avtime();
  1607. }
  1608. auto current_pts = nanoseconds::zero();
  1609. while(true)
  1610. {
  1611. size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)};
  1612. Picture *vp{&mPictQ[write_idx]};
  1613. /* Retrieve video frame. */
  1614. auto get_frame = [this](AVFrame *frame) -> AVFrame*
  1615. {
  1616. while(int ret{mQueue.receiveFrame(mCodecCtx.get(), frame)})
  1617. {
  1618. if(ret == AVErrorEOF) return nullptr;
  1619. fmt::println(stderr, "Failed to receive frame: {}", ret);
  1620. }
  1621. return frame;
  1622. };
  1623. auto *decoded_frame = get_frame(vp->mFrame.get());
  1624. if(!decoded_frame) break;
  1625. /* Get the PTS for this frame. */
  1626. if(decoded_frame->best_effort_timestamp != AVNoPtsValue)
  1627. current_pts = duration_cast<nanoseconds>(seconds_d64{av_q2d(mStream->time_base) *
  1628. static_cast<double>(decoded_frame->best_effort_timestamp)});
  1629. vp->mPts = current_pts;
  1630. /* Update the video clock to the next expected PTS. */
  1631. auto frame_delay = av_q2d(mCodecCtx->time_base);
  1632. frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5);
  1633. current_pts += duration_cast<nanoseconds>(seconds_d64{frame_delay});
  1634. /* Put the frame in the queue to be loaded into a texture and displayed
  1635. * by the rendering thread.
  1636. */
  1637. write_idx = (write_idx+1)%mPictQ.size();
  1638. mPictQWrite.store(write_idx, std::memory_order_release);
  1639. if(write_idx == mPictQRead.load(std::memory_order_acquire))
  1640. {
  1641. /* Wait until we have space for a new pic */
  1642. auto lock = std::unique_lock{mPictQMutex};
  1643. mPictQCond.wait(lock, [write_idx,this]() noexcept
  1644. { return write_idx != mPictQRead.load(std::memory_order_acquire); });
  1645. }
  1646. }
  1647. mEOS = true;
  1648. auto lock = std::unique_lock{mPictQMutex};
  1649. mPictQCond.wait(lock, [this]() noexcept { return mFinalUpdate.load(); });
  1650. return 0;
  1651. }
  1652. int MovieState::decode_interrupt_cb(void *ctx)
  1653. {
  1654. return static_cast<MovieState*>(ctx)->mQuit.load(std::memory_order_relaxed);
  1655. }
  1656. bool MovieState::prepare()
  1657. {
  1658. auto intcb = AVIOInterruptCB{decode_interrupt_cb, this};
  1659. if(avio_open2(al::out_ptr(mIOContext), mFilename.c_str(), AVIO_FLAG_READ, &intcb, nullptr) < 0)
  1660. {
  1661. fmt::println(stderr, "Failed to open {}", mFilename);
  1662. return false;
  1663. }
  1664. /* Open movie file. If avformat_open_input fails it will automatically free
  1665. * this context.
  1666. */
  1667. mFormatCtx.reset(avformat_alloc_context());
  1668. mFormatCtx->pb = mIOContext.get();
  1669. mFormatCtx->interrupt_callback = intcb;
  1670. if(avformat_open_input(al::inout_ptr(mFormatCtx), mFilename.c_str(), nullptr, nullptr) < 0)
  1671. {
  1672. fmt::println(stderr, "Failed to open {}", mFilename);
  1673. return false;
  1674. }
  1675. /* Retrieve stream information */
  1676. if(avformat_find_stream_info(mFormatCtx.get(), nullptr) < 0)
  1677. {
  1678. fmt::println(stderr, "{}: failed to find stream info", mFilename);
  1679. return false;
  1680. }
  1681. /* Dump information about file onto standard error */
  1682. av_dump_format(mFormatCtx.get(), 0, mFilename.c_str(), 0);
  1683. mParseThread = std::thread{&MovieState::parse_handler, this};
  1684. std::unique_lock<std::mutex> slock{mStartupMutex};
  1685. while(!mStartupDone) mStartupCond.wait(slock);
  1686. return true;
  1687. }
  1688. void MovieState::setTitle(SDL_Window *window) const
  1689. {
  1690. /* rfind returns npos if the char isn't found, and npos+1==0, which will
  1691. * give the desired result for finding the filename portion.
  1692. */
  1693. const auto fpos = std::max(mFilename.rfind('/')+1, mFilename.rfind('\\')+1);
  1694. const auto title = fmt::format("{} - {}", std::string_view{mFilename}.substr(fpos), AppName);
  1695. SDL_SetWindowTitle(window, title.c_str());
  1696. }
  1697. nanoseconds MovieState::getClock() const
  1698. {
  1699. if(mClockBase == microseconds::min())
  1700. return nanoseconds::zero();
  1701. return get_avtime() - mClockBase;
  1702. }
  1703. nanoseconds MovieState::getMasterClock()
  1704. {
  1705. if(mAVSyncType == SyncMaster::Video && mVideo.mStream)
  1706. return mVideo.getClock();
  1707. if(mAVSyncType == SyncMaster::Audio && mAudio.mStream)
  1708. return mAudio.getClock();
  1709. return getClock();
  1710. }
  1711. nanoseconds MovieState::getDuration() const
  1712. { return std::chrono::duration<int64_t,std::ratio<1,AV_TIME_BASE>>(mFormatCtx->duration); }
  1713. bool MovieState::streamComponentOpen(AVStream *stream)
  1714. {
  1715. /* Get a pointer to the codec context for the stream, and open the
  1716. * associated codec.
  1717. */
  1718. AVCodecCtxPtr avctx{avcodec_alloc_context3(nullptr)};
  1719. if(!avctx) return false;
  1720. if(avcodec_parameters_to_context(avctx.get(), stream->codecpar))
  1721. return false;
  1722. const AVCodec *codec{avcodec_find_decoder(avctx->codec_id)};
  1723. if(!codec || avcodec_open2(avctx.get(), codec, nullptr) < 0)
  1724. {
  1725. fmt::println(stderr, "Unsupported codec: {} ({:#x})", avcodec_get_name(avctx->codec_id),
  1726. al::to_underlying(avctx->codec_id));
  1727. return false;
  1728. }
  1729. /* Initialize and start the media type handler */
  1730. switch(avctx->codec_type)
  1731. {
  1732. case AVMEDIA_TYPE_AUDIO:
  1733. mAudio.mStream = stream;
  1734. mAudio.mCodecCtx = std::move(avctx);
  1735. return true;
  1736. case AVMEDIA_TYPE_VIDEO:
  1737. mVideo.mStream = stream;
  1738. mVideo.mCodecCtx = std::move(avctx);
  1739. return true;
  1740. default:
  1741. break;
  1742. }
  1743. return false;
  1744. }
  1745. int MovieState::parse_handler()
  1746. {
  1747. auto &audio_queue = mAudio.mQueue;
  1748. auto &video_queue = mVideo.mQueue;
  1749. int video_index{-1};
  1750. int audio_index{-1};
  1751. /* Find the first video and audio streams */
  1752. const auto ctxstreams = al::span{mFormatCtx->streams, mFormatCtx->nb_streams};
  1753. for(size_t i{0};i < ctxstreams.size();++i)
  1754. {
  1755. auto codecpar = ctxstreams[i]->codecpar;
  1756. if(codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !DisableVideo && video_index < 0
  1757. && streamComponentOpen(ctxstreams[i]))
  1758. video_index = static_cast<int>(i);
  1759. else if(codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0
  1760. && streamComponentOpen(ctxstreams[i]))
  1761. audio_index = static_cast<int>(i);
  1762. }
  1763. {
  1764. std::unique_lock<std::mutex> slock{mStartupMutex};
  1765. mStartupDone = true;
  1766. }
  1767. mStartupCond.notify_all();
  1768. if(video_index < 0 && audio_index < 0)
  1769. {
  1770. fmt::println(stderr, "{}: could not open codecs", mFilename);
  1771. mQuit = true;
  1772. }
  1773. /* Set the base time 750ms ahead of the current av time. */
  1774. mClockBase = get_avtime() + milliseconds{750};
  1775. if(audio_index >= 0)
  1776. mAudioThread = std::thread{&AudioState::handler, &mAudio};
  1777. if(video_index >= 0)
  1778. mVideoThread = std::thread{&VideoState::handler, &mVideo};
  1779. /* Main packet reading/dispatching loop */
  1780. AVPacketPtr packet{av_packet_alloc()};
  1781. while(!mQuit.load(std::memory_order_relaxed))
  1782. {
  1783. if(av_read_frame(mFormatCtx.get(), packet.get()) < 0)
  1784. break;
  1785. /* Copy the packet into the queue it's meant for. */
  1786. if(packet->stream_index == video_index)
  1787. {
  1788. while(!mQuit.load(std::memory_order_acquire) && !video_queue.put(packet.get()))
  1789. std::this_thread::sleep_for(milliseconds{100});
  1790. }
  1791. else if(packet->stream_index == audio_index)
  1792. {
  1793. while(!mQuit.load(std::memory_order_acquire) && !audio_queue.put(packet.get()))
  1794. std::this_thread::sleep_for(milliseconds{100});
  1795. }
  1796. av_packet_unref(packet.get());
  1797. }
  1798. /* Finish the queues so the receivers know nothing more is coming. */
  1799. video_queue.setFinished();
  1800. audio_queue.setFinished();
  1801. /* all done - wait for it */
  1802. if(mVideoThread.joinable())
  1803. mVideoThread.join();
  1804. if(mAudioThread.joinable())
  1805. mAudioThread.join();
  1806. mVideo.mEOS = true;
  1807. std::unique_lock<std::mutex> lock{mVideo.mPictQMutex};
  1808. while(!mVideo.mFinalUpdate)
  1809. mVideo.mPictQCond.wait(lock);
  1810. lock.unlock();
  1811. SDL_Event evt{};
  1812. evt.user.type = FF_MOVIE_DONE_EVENT;
  1813. SDL_PushEvent(&evt);
  1814. return 0;
  1815. }
  1816. void MovieState::stop()
  1817. {
  1818. mQuit = true;
  1819. mAudio.mQueue.flush();
  1820. mVideo.mQueue.flush();
  1821. }
  1822. // Helper method to print the time with human-readable formatting.
  1823. auto PrettyTime(seconds t) -> std::string
  1824. {
  1825. using minutes = std::chrono::minutes;
  1826. using hours = std::chrono::hours;
  1827. if(t.count() < 0)
  1828. return "0s";
  1829. // Only handle up to hour formatting
  1830. if(t >= hours{1})
  1831. return fmt::format("{}h{:02}m{:02}s", duration_cast<hours>(t).count(),
  1832. duration_cast<minutes>(t).count()%60, t.count()%60);
  1833. return fmt::format("{}m{:02}s", duration_cast<minutes>(t).count(), t.count()%60);
  1834. }
  1835. int main(al::span<std::string_view> args)
  1836. {
  1837. SDL_SetMainReady();
  1838. if(args.size() < 2)
  1839. {
  1840. fmt::println(stderr, "Usage: {} [-device <device name>] [-direct] <files...>", args[0]);
  1841. return 1;
  1842. }
  1843. /* Initialize networking protocols */
  1844. avformat_network_init();
  1845. if(!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
  1846. {
  1847. fmt::println(stderr, "Could not initialize SDL - {}", SDL_GetError());
  1848. return 1;
  1849. }
  1850. /* Make a window to put our video */
  1851. auto *screen = SDL_CreateWindow(AppName.c_str(), 640, 480, SDL_WINDOW_RESIZABLE);
  1852. if(!screen)
  1853. {
  1854. fmt::println(stderr, "SDL: could not set video mode - exiting");
  1855. return 1;
  1856. }
  1857. SDL_SetWindowSurfaceVSync(screen, 1);
  1858. /* Make a renderer to handle the texture image surface and rendering. */
  1859. auto *renderer = SDL_CreateRenderer(screen, nullptr);
  1860. if(!renderer)
  1861. {
  1862. fmt::println(stderr, "SDL: could not create renderer - exiting");
  1863. return 1;
  1864. }
  1865. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  1866. SDL_RenderFillRect(renderer, nullptr);
  1867. SDL_RenderPresent(renderer);
  1868. /* Open an audio device */
  1869. args = args.subspan(1);
  1870. if(InitAL(args) != 0)
  1871. return 1;
  1872. {
  1873. ALCdevice *device{alcGetContextsDevice(alcGetCurrentContext())};
  1874. if(alcIsExtensionPresent(device,"ALC_SOFT_device_clock"))
  1875. {
  1876. fmt::println("Found ALC_SOFT_device_clock");
  1877. alcGetInteger64vSOFT = reinterpret_cast<LPALCGETINTEGER64VSOFT>(
  1878. alcGetProcAddress(device, "alcGetInteger64vSOFT"));
  1879. }
  1880. }
  1881. if(alIsExtensionPresent("AL_SOFT_source_latency"))
  1882. {
  1883. fmt::println("Found AL_SOFT_source_latency");
  1884. alGetSourcei64vSOFT = reinterpret_cast<LPALGETSOURCEI64VSOFT>(
  1885. alGetProcAddress("alGetSourcei64vSOFT"));
  1886. }
  1887. if(alIsExtensionPresent("AL_SOFT_events"))
  1888. {
  1889. fmt::println("Found AL_SOFT_events");
  1890. alEventControlSOFT = reinterpret_cast<LPALEVENTCONTROLSOFT>(
  1891. alGetProcAddress("alEventControlSOFT"));
  1892. alEventCallbackSOFT = reinterpret_cast<LPALEVENTCALLBACKSOFT>(
  1893. alGetProcAddress("alEventCallbackSOFT"));
  1894. }
  1895. if(alIsExtensionPresent("AL_SOFT_callback_buffer"))
  1896. {
  1897. fmt::println("Found AL_SOFT_callback_buffer");
  1898. alBufferCallbackSOFT = reinterpret_cast<LPALBUFFERCALLBACKSOFT>(
  1899. alGetProcAddress("alBufferCallbackSOFT"));
  1900. }
  1901. size_t fileidx{0};
  1902. for(;fileidx < args.size();++fileidx)
  1903. {
  1904. if(args[fileidx] == "-direct")
  1905. {
  1906. if(alIsExtensionPresent("AL_SOFT_direct_channels_remix"))
  1907. {
  1908. fmt::println("Found AL_SOFT_direct_channels_remix");
  1909. DirectOutMode = AL_REMIX_UNMATCHED_SOFT;
  1910. }
  1911. else if(alIsExtensionPresent("AL_SOFT_direct_channels"))
  1912. {
  1913. fmt::println("Found AL_SOFT_direct_channels");
  1914. DirectOutMode = AL_DROP_UNMATCHED_SOFT;
  1915. }
  1916. else
  1917. fmt::println(stderr, "AL_SOFT_direct_channels not supported for direct output");
  1918. }
  1919. else if(args[fileidx] == "-wide")
  1920. {
  1921. if(!alIsExtensionPresent("AL_EXT_STEREO_ANGLES"))
  1922. fmt::println(stderr, "AL_EXT_STEREO_ANGLES not supported for wide stereo");
  1923. else
  1924. {
  1925. fmt::println("Found AL_EXT_STEREO_ANGLES");
  1926. EnableWideStereo = true;
  1927. }
  1928. }
  1929. else if(args[fileidx] == "-uhj")
  1930. {
  1931. if(!alIsExtensionPresent("AL_SOFT_UHJ"))
  1932. fmt::println(stderr, "AL_SOFT_UHJ not supported for UHJ decoding");
  1933. else
  1934. {
  1935. fmt::println("Found AL_SOFT_UHJ");
  1936. EnableUhj = true;
  1937. }
  1938. }
  1939. else if(args[fileidx] == "-superstereo")
  1940. {
  1941. if(!alIsExtensionPresent("AL_SOFT_UHJ"))
  1942. fmt::println(stderr, "AL_SOFT_UHJ not supported for Super Stereo decoding");
  1943. else
  1944. {
  1945. fmt::println("Found AL_SOFT_UHJ (Super Stereo)");
  1946. EnableSuperStereo = true;
  1947. }
  1948. }
  1949. else if(args[fileidx] == "-novideo")
  1950. DisableVideo = true;
  1951. else
  1952. break;
  1953. }
  1954. auto movState = std::unique_ptr<MovieState>{};
  1955. while(fileidx < args.size() && !movState)
  1956. {
  1957. movState = std::make_unique<MovieState>(args[fileidx++]);
  1958. if(!movState->prepare()) movState = nullptr;
  1959. }
  1960. if(!movState)
  1961. {
  1962. fmt::println(stderr, "Could not start a video");
  1963. return 1;
  1964. }
  1965. movState->setTitle(screen);
  1966. /* Default to going to the next movie at the end of one. */
  1967. enum class EomAction {
  1968. Next, Quit
  1969. } eom_action{EomAction::Next};
  1970. seconds last_time{seconds::min()};
  1971. while(true)
  1972. {
  1973. auto event = SDL_Event{};
  1974. auto have_event = SDL_WaitEventTimeout(&event, 10);
  1975. const auto cur_time = duration_cast<seconds>(movState->getMasterClock());
  1976. if(cur_time != last_time)
  1977. {
  1978. const auto end_time = duration_cast<seconds>(movState->getDuration());
  1979. fmt::print(" \r {} / {}", PrettyTime(cur_time), PrettyTime(end_time));
  1980. fflush(stdout);
  1981. last_time = cur_time;
  1982. }
  1983. auto force_redraw = false;
  1984. while(have_event)
  1985. {
  1986. switch(event.type)
  1987. {
  1988. case SDL_EVENT_KEY_DOWN:
  1989. switch(event.key.key)
  1990. {
  1991. case SDLK_ESCAPE:
  1992. movState->stop();
  1993. eom_action = EomAction::Quit;
  1994. break;
  1995. case SDLK_N:
  1996. movState->stop();
  1997. eom_action = EomAction::Next;
  1998. break;
  1999. default:
  2000. break;
  2001. }
  2002. break;
  2003. case SDL_EVENT_WINDOW_SHOWN:
  2004. case SDL_EVENT_WINDOW_EXPOSED:
  2005. case SDL_EVENT_WINDOW_RESIZED:
  2006. case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
  2007. case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
  2008. case SDL_EVENT_RENDER_TARGETS_RESET:
  2009. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  2010. SDL_RenderFillRect(renderer, nullptr);
  2011. force_redraw = true;
  2012. break;
  2013. case SDL_EVENT_QUIT:
  2014. movState->stop();
  2015. eom_action = EomAction::Quit;
  2016. break;
  2017. case FF_MOVIE_DONE_EVENT:
  2018. fmt::println("");
  2019. last_time = seconds::min();
  2020. if(eom_action != EomAction::Quit)
  2021. {
  2022. movState = nullptr;
  2023. while(fileidx < args.size() && !movState)
  2024. {
  2025. movState = std::make_unique<MovieState>(args[fileidx++]);
  2026. if(!movState->prepare()) movState = nullptr;
  2027. }
  2028. if(movState)
  2029. {
  2030. movState->setTitle(screen);
  2031. break;
  2032. }
  2033. }
  2034. /* Nothing more to play. Shut everything down and quit. */
  2035. movState = nullptr;
  2036. CloseAL();
  2037. SDL_DestroyRenderer(renderer);
  2038. renderer = nullptr;
  2039. SDL_DestroyWindow(screen);
  2040. screen = nullptr;
  2041. SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
  2042. exit(0);
  2043. default:
  2044. break;
  2045. }
  2046. have_event = SDL_PollEvent(&event);
  2047. }
  2048. movState->mVideo.updateVideo(screen, renderer, force_redraw);
  2049. }
  2050. fmt::println(stderr, "SDL_WaitEvent error - {}", SDL_GetError());
  2051. return 1;
  2052. }
  2053. } // namespace
  2054. int main(int argc, char *argv[])
  2055. {
  2056. assert(argc >= 0);
  2057. auto args = std::vector<std::string_view>(static_cast<unsigned int>(argc));
  2058. std::copy_n(argv, args.size(), args.begin());
  2059. return main(al::span{args});
  2060. }