media_clip_reader.cpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "media/clip/media_clip_reader.h"
  8. #include "media/clip/media_clip_ffmpeg.h"
  9. #include "media/clip/media_clip_check_streaming.h"
  10. #include "ui/chat/attach/attach_prepare.h"
  11. #include "ui/painter.h"
  12. #include "core/file_location.h"
  13. #include "base/random.h"
  14. #include "base/invoke_queued.h"
  15. #include "logs.h"
  16. #include <QtCore/QBuffer>
  17. #include <QtCore/QAbstractEventDispatcher>
  18. #include <QtCore/QCoreApplication>
  19. #include <QtCore/QThread>
  20. #include <QtCore/QFileInfo>
  21. extern "C" {
  22. #include <libavcodec/avcodec.h>
  23. #include <libavformat/avformat.h>
  24. #include <libavutil/opt.h>
  25. #include <libswscale/swscale.h>
  26. } // extern "C"
  27. namespace Media {
  28. namespace Clip {
  29. namespace {
  30. constexpr auto kClipThreadsCount = 8;
  31. constexpr auto kAverageGifSize = 320 * 240;
  32. constexpr auto kWaitBeforeGifPause = crl::time(200);
  33. QImage PrepareFrame(
  34. const FrameRequest &request,
  35. const QImage &original,
  36. bool hasAlpha,
  37. QImage &cache) {
  38. const auto needResize = (original.size() != request.frame);
  39. const auto needOuterFill = request.outer.isValid()
  40. && (request.outer != request.frame);
  41. const auto needRounding = (request.radius != ImageRoundRadius::None);
  42. const auto colorizing = (request.colored.alpha() != 0);
  43. if (!needResize
  44. && !needOuterFill
  45. && !hasAlpha
  46. && !needRounding
  47. && !colorizing) {
  48. return original;
  49. }
  50. const auto factor = request.factor;
  51. const auto size = request.outer.isValid() ? request.outer : request.frame;
  52. const auto needNewCache = (cache.size() != size);
  53. if (needNewCache) {
  54. cache = QImage(size, QImage::Format_ARGB32_Premultiplied);
  55. cache.setDevicePixelRatio(factor);
  56. }
  57. if (hasAlpha && request.keepAlpha) {
  58. cache.fill(Qt::transparent);
  59. }
  60. {
  61. auto p = QPainter(&cache);
  62. const auto framew = request.frame.width();
  63. const auto outerw = size.width();
  64. const auto frameh = request.frame.height();
  65. const auto outerh = size.height();
  66. if (needNewCache && (!hasAlpha || !request.keepAlpha)) {
  67. if (framew < outerw) {
  68. p.fillRect(0, 0, (outerw - framew) / (2 * factor), cache.height() / factor, st::imageBg);
  69. p.fillRect((outerw - framew) / (2 * factor) + (framew / factor), 0, (cache.width() / factor) - ((outerw - framew) / (2 * factor) + (framew / factor)), cache.height() / factor, st::imageBg);
  70. }
  71. if (frameh < outerh) {
  72. p.fillRect(qMax(0, (outerw - framew) / (2 * factor)), 0, qMin(cache.width(), framew) / factor, (outerh - frameh) / (2 * factor), st::imageBg);
  73. p.fillRect(qMax(0, (outerw - framew) / (2 * factor)), (outerh - frameh) / (2 * factor) + (frameh / factor), qMin(cache.width(), framew) / factor, (cache.height() / factor) - ((outerh - frameh) / (2 * factor) + (frameh / factor)), st::imageBg);
  74. }
  75. }
  76. if (hasAlpha && !request.keepAlpha) {
  77. p.fillRect(qMax(0, (outerw - framew) / (2 * factor)), qMax(0, (outerh - frameh) / (2 * factor)), qMin(cache.width(), framew) / factor, qMin(cache.height(), frameh) / factor, st::imageBgTransparent);
  78. }
  79. const auto position = QPoint((outerw - framew) / (2 * factor), (outerh - frameh) / (2 * factor));
  80. if (needResize) {
  81. PainterHighQualityEnabler hq(p);
  82. const auto dst = QRect(position, QSize(framew / factor, frameh / factor));
  83. const auto src = QRect(0, 0, original.width(), original.height());
  84. p.drawImage(dst, original, src, Qt::ColorOnly);
  85. } else {
  86. p.drawImage(position, original);
  87. }
  88. }
  89. if (needRounding) {
  90. cache = Images::Round(
  91. std::move(cache),
  92. request.radius,
  93. request.corners);
  94. }
  95. if (colorizing) {
  96. cache = Images::Colored(std::move(cache), request.colored);
  97. }
  98. return cache;
  99. }
  100. } // namespace
  101. enum class ProcessResult {
  102. Error,
  103. Started,
  104. Finished,
  105. Paused,
  106. Repaint,
  107. CopyFrame,
  108. Wait,
  109. };
  110. class Manager final : public QObject {
  111. public:
  112. explicit Manager(not_null<QThread*> thread);
  113. ~Manager();
  114. int loadLevel() const {
  115. return _loadLevel;
  116. }
  117. void append(Reader *reader, const Core::FileLocation &location, const QByteArray &data);
  118. void start(Reader *reader);
  119. void update(Reader *reader);
  120. void stop(Reader *reader);
  121. bool carries(Reader *reader) const;
  122. private:
  123. void process();
  124. void finish();
  125. void callback(Reader *reader, Notification notification);
  126. void clear();
  127. QAtomicInt _loadLevel;
  128. using ReaderPointers = QMap<Reader*, QAtomicInt>;
  129. ReaderPointers _readerPointers;
  130. mutable QMutex _readerPointersMutex;
  131. ReaderPointers::const_iterator constUnsafeFindReaderPointer(ReaderPrivate *reader) const;
  132. ReaderPointers::iterator unsafeFindReaderPointer(ReaderPrivate *reader);
  133. bool handleProcessResult(ReaderPrivate *reader, ProcessResult result, crl::time ms);
  134. enum ResultHandleState {
  135. ResultHandleRemove,
  136. ResultHandleStop,
  137. ResultHandleContinue,
  138. };
  139. ResultHandleState handleResult(ReaderPrivate *reader, ProcessResult result, crl::time ms);
  140. using Readers = QMap<ReaderPrivate*, crl::time>;
  141. Readers _readers;
  142. QTimer _timer;
  143. QThread *_processingInThread = nullptr;
  144. bool _needReProcess = false;
  145. };
  146. namespace {
  147. struct Worker {
  148. Worker() : manager(&thread) {
  149. thread.start();
  150. }
  151. ~Worker() {
  152. thread.quit();
  153. thread.wait();
  154. }
  155. QThread thread;
  156. Manager manager;
  157. };
  158. std::vector<std::unique_ptr<Worker>> Workers;
  159. } // namespace
  160. Reader::Reader(
  161. const Core::FileLocation &location,
  162. const QByteArray &data,
  163. Callback &&callback)
  164. : _callback(std::move(callback)) {
  165. init(location, data);
  166. }
  167. Reader::Reader(const QString &filepath, Callback &&callback)
  168. : _callback(std::move(callback)) {
  169. init(Core::FileLocation(filepath), QByteArray());
  170. }
  171. Reader::Reader(const QByteArray &data, Callback &&callback)
  172. : _callback(std::move(callback)) {
  173. init(Core::FileLocation(QString()), data);
  174. }
  175. void Reader::init(const Core::FileLocation &location, const QByteArray &data) {
  176. if (Workers.size() < kClipThreadsCount) {
  177. _threadIndex = Workers.size();
  178. Workers.push_back(std::make_unique<Worker>());
  179. } else {
  180. _threadIndex = base::RandomIndex(Workers.size());
  181. auto loadLevel = 0x7FFFFFFF;
  182. for (int i = 0, l = int(Workers.size()); i < l; ++i) {
  183. const auto level = Workers[i]->manager.loadLevel();
  184. if (level < loadLevel) {
  185. _threadIndex = i;
  186. loadLevel = level;
  187. }
  188. }
  189. }
  190. Workers[_threadIndex]->manager.append(this, location, data);
  191. }
  192. Reader::Frame *Reader::frameToShow(int32 *index) const { // 0 means not ready
  193. int step = _step.loadAcquire(), i;
  194. if (step == kWaitingForDimensionsStep) {
  195. if (index) *index = 0;
  196. return nullptr;
  197. } else if (step == kWaitingForRequestStep) {
  198. i = 0;
  199. } else if (step == kWaitingForFirstFrameStep) {
  200. i = 0;
  201. } else {
  202. i = (step / 2) % 3;
  203. }
  204. if (index) *index = i;
  205. return _frames + i;
  206. }
  207. Reader::Frame *Reader::frameToWrite(int32 *index) const { // 0 means not ready
  208. int32 step = _step.loadAcquire(), i;
  209. if (step == kWaitingForDimensionsStep) {
  210. i = 0;
  211. } else if (step == kWaitingForRequestStep) {
  212. if (index) *index = 0;
  213. return nullptr;
  214. } else if (step == kWaitingForFirstFrameStep) {
  215. i = 0;
  216. } else {
  217. i = ((step + 2) / 2) % 3;
  218. }
  219. if (index) *index = i;
  220. return _frames + i;
  221. }
  222. Reader::Frame *Reader::frameToWriteNext(bool checkNotWriting, int32 *index) const {
  223. int32 step = _step.loadAcquire(), i;
  224. if (step == kWaitingForDimensionsStep
  225. || step == kWaitingForRequestStep
  226. || (checkNotWriting && (step % 2))) {
  227. if (index) *index = 0;
  228. return nullptr;
  229. }
  230. i = ((step + 4) / 2) % 3;
  231. if (index) *index = i;
  232. return _frames + i;
  233. }
  234. bool Reader::moveToNextShow() const {
  235. const auto step = _step.loadAcquire();
  236. if (step == kWaitingForDimensionsStep) {
  237. } else if (step == kWaitingForRequestStep) {
  238. _step.storeRelease(kWaitingForFirstFrameStep);
  239. return true;
  240. } else if (step == kWaitingForFirstFrameStep) {
  241. } else if (!(step % 2)) {
  242. _step.storeRelease(step + 1);
  243. return true;
  244. }
  245. return false;
  246. }
  247. void Reader::moveToNextWrite() const {
  248. int32 step = _step.loadAcquire();
  249. if (step == kWaitingForDimensionsStep) {
  250. _step.storeRelease(kWaitingForRequestStep);
  251. } else if (step == kWaitingForRequestStep) {
  252. } else if (step == kWaitingForFirstFrameStep) {
  253. _step.storeRelease(0);
  254. // Force paint the first frame so moveToNextShow() is called.
  255. _frames[0].displayed.storeRelease(0);
  256. } else if (step % 2) {
  257. _step.storeRelease((step + 1) % 6);
  258. }
  259. }
  260. void Reader::SafeCallback(
  261. Reader *reader,
  262. int threadIndex,
  263. Notification notification) {
  264. // Check if reader is not deleted already
  265. if (Workers.size() > threadIndex
  266. && Workers[threadIndex]->manager.carries(reader)
  267. && reader->_callback) {
  268. reader->_callback(Notification(notification));
  269. }
  270. }
  271. void Reader::start(FrameRequest request) {
  272. if (Workers.size() <= _threadIndex) {
  273. error();
  274. }
  275. if (_state == State::Error
  276. || (_step.loadAcquire() != kWaitingForRequestStep)) {
  277. return;
  278. }
  279. const auto factor = style::DevicePixelRatio();
  280. request.factor = factor;
  281. request.frame *= factor;
  282. if (request.outer.isValid()) {
  283. request.outer *= factor;
  284. }
  285. _frames[0].request = _frames[1].request = _frames[2].request = request;
  286. moveToNextShow();
  287. Workers[_threadIndex]->manager.start(this);
  288. }
  289. Reader::FrameInfo Reader::frameInfo(FrameRequest request, crl::time now) {
  290. Expects(!(request.outer.isValid()
  291. ? request.outer
  292. : request.frame).isEmpty());
  293. const auto frame = frameToShow();
  294. Assert(frame != nullptr);
  295. const auto shouldBePaused = !now;
  296. if (!shouldBePaused) {
  297. frame->displayed.storeRelease(1);
  298. if (_autoPausedGif.loadAcquire()) {
  299. _autoPausedGif.storeRelease(0);
  300. if (Workers.size() <= _threadIndex) {
  301. error();
  302. } else if (_state != State::Error) {
  303. Workers[_threadIndex]->manager.update(this);
  304. }
  305. }
  306. } else {
  307. frame->displayed.storeRelease(-1);
  308. }
  309. const auto factor = style::DevicePixelRatio();
  310. request.factor = factor;
  311. request.frame *= factor;
  312. if (request.outer.isValid()) {
  313. request.outer *= factor;
  314. }
  315. const auto size = request.outer.isValid()
  316. ? request.outer
  317. : request.frame;
  318. Assert(frame->request.radius == request.radius
  319. && frame->request.corners == request.corners
  320. && frame->request.keepAlpha == request.keepAlpha);
  321. if (frame->prepared.size() != size
  322. || frame->preparedColored != request.colored) {
  323. frame->request.frame = request.frame;
  324. frame->request.outer = request.outer;
  325. frame->request.colored = request.colored;
  326. QImage cacheForResize;
  327. frame->original.setDevicePixelRatio(factor);
  328. frame->prepared = QImage();
  329. frame->prepared = PrepareFrame(
  330. frame->request,
  331. frame->original,
  332. true,
  333. cacheForResize);
  334. frame->preparedColored = request.colored;
  335. auto other = frameToWriteNext(true);
  336. if (other) other->request = frame->request;
  337. if (Workers.size() <= _threadIndex) {
  338. error();
  339. } else if (_state != State::Error) {
  340. Workers[_threadIndex]->manager.update(this);
  341. }
  342. }
  343. return { frame->prepared, frame->index };
  344. }
  345. bool Reader::ready() const {
  346. if (_width && _height) {
  347. return true;
  348. }
  349. const auto frame = frameToShow();
  350. if (frame) {
  351. _width = frame->original.width();
  352. _height = frame->original.height();
  353. return true;
  354. }
  355. return false;
  356. }
  357. crl::time Reader::getPositionMs() const {
  358. if (const auto frame = frameToShow()) {
  359. return frame->positionMs;
  360. }
  361. return 0;
  362. }
  363. crl::time Reader::getDurationMs() const {
  364. return ready() ? _durationMs : 0;
  365. }
  366. void Reader::pauseResumeVideo() {
  367. if (Workers.size() <= _threadIndex) {
  368. error();
  369. }
  370. if (_state == State::Error) return;
  371. _videoPauseRequest.storeRelease(1 - _videoPauseRequest.loadAcquire());
  372. Workers[_threadIndex]->manager.start(this);
  373. }
  374. bool Reader::videoPaused() const {
  375. return _videoPauseRequest.loadAcquire() != 0;
  376. }
  377. int32 Reader::width() const {
  378. return _width;
  379. }
  380. int32 Reader::height() const {
  381. return _height;
  382. }
  383. State Reader::state() const {
  384. return _state;
  385. }
  386. void Reader::stop() {
  387. if (Workers.size() <= _threadIndex) {
  388. error();
  389. }
  390. if (_state != State::Error) {
  391. Workers[_threadIndex]->manager.stop(this);
  392. _width = _height = 0;
  393. }
  394. }
  395. void Reader::error() {
  396. _state = State::Error;
  397. _private = nullptr;
  398. }
  399. void Reader::finished() {
  400. _state = State::Finished;
  401. _private = nullptr;
  402. }
  403. Reader::~Reader() {
  404. stop();
  405. }
  406. class ReaderPrivate {
  407. public:
  408. ReaderPrivate(Reader *reader, const Core::FileLocation &location, const QByteArray &data)
  409. : _interface(reader)
  410. , _data(data) {
  411. if (_data.isEmpty()) {
  412. _location = std::make_unique<Core::FileLocation>(location);
  413. if (!_location->accessEnable()) {
  414. error();
  415. return;
  416. }
  417. }
  418. _accessed = true;
  419. }
  420. ProcessResult start(crl::time ms) {
  421. if (!_implementation && !init()) {
  422. return error();
  423. }
  424. if (frame()->original.isNull()) {
  425. auto readResult = _implementation->readFramesTill(-1, ms);
  426. if (readResult == internal::ReaderImplementation::ReadResult::EndOfFile && _seekPositionMs > 0) {
  427. // If seek was done to the end: try to read the first frame,
  428. // get the frame size and return a black frame with that size.
  429. auto firstFramePositionMs = crl::time(0);
  430. auto reader = std::make_unique<internal::FFMpegReaderImplementation>(_location.get(), &_data);
  431. if (reader->start(internal::ReaderImplementation::Mode::Silent, firstFramePositionMs)) {
  432. auto firstFrameReadResult = reader->readFramesTill(-1, ms);
  433. if (firstFrameReadResult == internal::ReaderImplementation::ReadResult::Success) {
  434. if (reader->renderFrame(frame()->original, frame()->alpha, frame()->index, QSize())) {
  435. frame()->original.fill(QColor(0, 0, 0));
  436. frame()->positionMs = _seekPositionMs;
  437. _width = frame()->original.width();
  438. _height = frame()->original.height();
  439. _durationMs = _implementation->durationMs();
  440. return ProcessResult::Started;
  441. }
  442. }
  443. }
  444. return error();
  445. } else if (readResult != internal::ReaderImplementation::ReadResult::Success) { // Read the first frame.
  446. return error();
  447. }
  448. if (!_implementation->renderFrame(frame()->original, frame()->alpha, frame()->index, QSize())) {
  449. return error();
  450. }
  451. frame()->positionMs = _implementation->frameRealTime();
  452. _width = frame()->original.width();
  453. _height = frame()->original.height();
  454. _durationMs = _implementation->durationMs();
  455. return ProcessResult::Started;
  456. }
  457. return ProcessResult::Wait;
  458. }
  459. ProcessResult process(crl::time ms) { // -1 - do nothing, 0 - update, 1 - reinit
  460. if (_state == State::Error) {
  461. return ProcessResult::Error;
  462. } else if (_state == State::Finished) {
  463. return ProcessResult::Finished;
  464. }
  465. if (!_request.valid()) {
  466. return start(ms);
  467. }
  468. if (!_started) {
  469. _started = true;
  470. }
  471. if (!_autoPausedGif && !_videoPausedAtMs && ms >= _nextFrameWhen) {
  472. return ProcessResult::Repaint;
  473. }
  474. return ProcessResult::Wait;
  475. }
  476. ProcessResult finishProcess(crl::time ms) {
  477. auto frameMs = _seekPositionMs + ms - _animationStarted;
  478. auto readResult = _implementation->readFramesTill(frameMs, ms);
  479. if (readResult == internal::ReaderImplementation::ReadResult::EndOfFile) {
  480. stop();
  481. _state = State::Finished;
  482. return ProcessResult::Finished;
  483. } else if (readResult == internal::ReaderImplementation::ReadResult::Error) {
  484. return error();
  485. }
  486. _nextFramePositionMs = _implementation->frameRealTime();
  487. _nextFrameWhen = _animationStarted + _implementation->framePresentationTime();
  488. if (_nextFrameWhen > _seekPositionMs) {
  489. _nextFrameWhen -= _seekPositionMs;
  490. } else {
  491. _nextFrameWhen = 1;
  492. }
  493. if (!renderFrame()) {
  494. return error();
  495. }
  496. return ProcessResult::CopyFrame;
  497. }
  498. bool renderFrame() {
  499. Expects(_request.valid());
  500. if (!_implementation->renderFrame(frame()->original, frame()->alpha, frame()->index, _request.frame)) {
  501. return false;
  502. }
  503. frame()->original.setDevicePixelRatio(_request.factor);
  504. frame()->prepared = QImage();
  505. frame()->prepared = PrepareFrame(
  506. _request,
  507. frame()->original,
  508. frame()->alpha,
  509. frame()->cache);
  510. frame()->preparedColored = _request.colored;
  511. frame()->when = _nextFrameWhen;
  512. frame()->positionMs = _nextFramePositionMs;
  513. return true;
  514. }
  515. bool init() {
  516. if (_data.isEmpty() && QFileInfo(_location->name()).size() <= internal::kMaxInMemory) {
  517. QFile f(_location->name());
  518. if (f.open(QIODevice::ReadOnly)) {
  519. _data = f.readAll();
  520. if (f.error() != QFile::NoError) {
  521. _data = QByteArray();
  522. }
  523. }
  524. }
  525. _implementation = std::make_unique<internal::FFMpegReaderImplementation>(_location.get(), &_data);
  526. return _implementation->start(internal::ReaderImplementation::Mode::Silent, _seekPositionMs);
  527. }
  528. void startedAt(crl::time ms) {
  529. _animationStarted = _nextFrameWhen = ms;
  530. }
  531. void pauseVideo(crl::time ms) {
  532. if (_videoPausedAtMs) return; // Paused already.
  533. _videoPausedAtMs = ms;
  534. }
  535. void resumeVideo(crl::time ms) {
  536. if (!_videoPausedAtMs) return; // Not paused.
  537. auto delta = ms - _videoPausedAtMs;
  538. _animationStarted += delta;
  539. _nextFrameWhen += delta;
  540. _videoPausedAtMs = 0;
  541. }
  542. ProcessResult error() {
  543. stop();
  544. _state = State::Error;
  545. return ProcessResult::Error;
  546. }
  547. void stop() {
  548. _implementation = nullptr;
  549. if (_location) {
  550. if (_accessed) {
  551. _location->accessDisable();
  552. }
  553. _location = nullptr;
  554. }
  555. _accessed = false;
  556. }
  557. ~ReaderPrivate() {
  558. stop();
  559. _data.clear();
  560. }
  561. private:
  562. Reader *_interface;
  563. State _state = State::Reading;
  564. crl::time _seekPositionMs = 0;
  565. QByteArray _data;
  566. std::unique_ptr<Core::FileLocation> _location;
  567. bool _accessed = false;
  568. QBuffer _buffer;
  569. std::unique_ptr<internal::ReaderImplementation> _implementation;
  570. FrameRequest _request;
  571. struct Frame {
  572. QImage prepared;
  573. QColor preparedColored = QColor(0, 0, 0, 0);
  574. QImage original;
  575. QImage cache;
  576. int index = 0;
  577. bool alpha = true;
  578. crl::time when = 0;
  579. // Counted from the end, so that positionMs <= durationMs despite keep up delays.
  580. crl::time positionMs = 0;
  581. };
  582. Frame _frames[3];
  583. int _frame = 0;
  584. not_null<Frame*> frame() {
  585. return _frames + _frame;
  586. }
  587. int _width = 0;
  588. int _height = 0;
  589. crl::time _durationMs = 0;
  590. crl::time _animationStarted = 0;
  591. crl::time _nextFrameWhen = 0;
  592. crl::time _nextFramePositionMs = 0;
  593. bool _autoPausedGif = false;
  594. bool _started = false;
  595. crl::time _videoPausedAtMs = 0;
  596. friend class Manager;
  597. };
  598. Manager::Manager(not_null<QThread*> thread) {
  599. moveToThread(thread);
  600. connect(thread, &QThread::started, this, [=] { process(); });
  601. connect(thread, &QThread::finished, this, [=] { finish(); });
  602. _timer.setSingleShot(true);
  603. _timer.moveToThread(thread);
  604. connect(&_timer, &QTimer::timeout, this, [=] { process(); });
  605. }
  606. void Manager::append(Reader *reader, const Core::FileLocation &location, const QByteArray &data) {
  607. reader->_private = new ReaderPrivate(reader, location, data);
  608. _loadLevel.fetchAndAddRelaxed(kAverageGifSize);
  609. update(reader);
  610. }
  611. void Manager::start(Reader *reader) {
  612. update(reader);
  613. }
  614. void Manager::update(Reader *reader) {
  615. QMutexLocker lock(&_readerPointersMutex);
  616. auto i = _readerPointers.find(reader);
  617. if (i == _readerPointers.cend()) {
  618. _readerPointers.insert(reader, QAtomicInt(1));
  619. } else {
  620. i->storeRelease(1);
  621. }
  622. InvokeQueued(this, [=] { process(); });
  623. }
  624. void Manager::stop(Reader *reader) {
  625. if (!carries(reader)) return;
  626. QMutexLocker lock(&_readerPointersMutex);
  627. _readerPointers.remove(reader);
  628. InvokeQueued(this, [=] { process(); });
  629. }
  630. bool Manager::carries(Reader *reader) const {
  631. QMutexLocker lock(&_readerPointersMutex);
  632. return _readerPointers.contains(reader);
  633. }
  634. auto Manager::unsafeFindReaderPointer(ReaderPrivate *reader)
  635. -> ReaderPointers::iterator {
  636. const auto it = _readerPointers.find(reader->_interface);
  637. // could be a new reader which was realloced in the same address
  638. return (it == _readerPointers.cend() || it.key()->_private == reader)
  639. ? it
  640. : _readerPointers.end();
  641. }
  642. auto Manager::constUnsafeFindReaderPointer(ReaderPrivate *reader) const
  643. -> ReaderPointers::const_iterator {
  644. const auto it = _readerPointers.constFind(reader->_interface);
  645. // could be a new reader which was realloced in the same address
  646. return (it == _readerPointers.cend() || it.key()->_private == reader)
  647. ? it
  648. : _readerPointers.cend();
  649. }
  650. void Manager::callback(Reader *reader, Notification notification) {
  651. crl::on_main([=, threadIndex = reader->threadIndex()] {
  652. Reader::SafeCallback(reader, threadIndex, notification);
  653. });
  654. }
  655. bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, crl::time ms) {
  656. QMutexLocker lock(&_readerPointersMutex);
  657. auto it = unsafeFindReaderPointer(reader);
  658. if (result == ProcessResult::Error) {
  659. if (it != _readerPointers.cend()) {
  660. it.key()->error();
  661. callback(it.key(), Notification::Reinit);
  662. _readerPointers.erase(it);
  663. }
  664. return false;
  665. } else if (result == ProcessResult::Finished) {
  666. if (it != _readerPointers.cend()) {
  667. it.key()->finished();
  668. callback(it.key(), Notification::Reinit);
  669. }
  670. return false;
  671. }
  672. if (it == _readerPointers.cend()) {
  673. return false;
  674. }
  675. if (result == ProcessResult::Started) {
  676. _loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - kAverageGifSize);
  677. it.key()->_durationMs = reader->_durationMs;
  678. }
  679. // See if we need to pause GIF because it is not displayed right now.
  680. if (!reader->_autoPausedGif && result == ProcessResult::Repaint) {
  681. int32 ishowing, iprevious;
  682. auto showing = it.key()->frameToShow(&ishowing), previous = it.key()->frameToWriteNext(false, &iprevious);
  683. Assert(previous != nullptr && showing != nullptr && ishowing >= 0 && iprevious >= 0);
  684. if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown
  685. if (reader->_frames[ishowing].when + kWaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) {
  686. reader->_autoPausedGif = true;
  687. it.key()->_autoPausedGif.storeRelease(1);
  688. result = ProcessResult::Paused;
  689. }
  690. }
  691. }
  692. if (result == ProcessResult::Started || result == ProcessResult::CopyFrame) {
  693. Assert(reader->_frame >= 0);
  694. auto frame = it.key()->_frames + reader->_frame;
  695. frame->clear();
  696. frame->prepared = reader->frame()->prepared;
  697. frame->preparedColored = reader->frame()->preparedColored;
  698. frame->original = reader->frame()->original;
  699. frame->index = reader->frame()->index;
  700. frame->displayed.storeRelease(0);
  701. frame->positionMs = reader->frame()->positionMs;
  702. if (result == ProcessResult::Started) {
  703. reader->startedAt(ms);
  704. it.key()->moveToNextWrite();
  705. callback(it.key(), Notification::Reinit);
  706. }
  707. } else if (result == ProcessResult::Paused) {
  708. it.key()->moveToNextWrite();
  709. callback(it.key(), Notification::Reinit);
  710. } else if (result == ProcessResult::Repaint) {
  711. it.key()->moveToNextWrite();
  712. callback(it.key(), Notification::Repaint);
  713. }
  714. return true;
  715. }
  716. Manager::ResultHandleState Manager::handleResult(ReaderPrivate *reader, ProcessResult result, crl::time ms) {
  717. if (!handleProcessResult(reader, result, ms)) {
  718. _loadLevel.fetchAndAddRelaxed(-1 * (reader->_width > 0 ? reader->_width * reader->_height : kAverageGifSize));
  719. delete reader;
  720. return ResultHandleRemove;
  721. }
  722. _processingInThread->eventDispatcher()->processEvents(QEventLoop::AllEvents);
  723. if (_processingInThread->isInterruptionRequested()) {
  724. return ResultHandleStop;
  725. }
  726. if (result == ProcessResult::Repaint) {
  727. {
  728. QMutexLocker lock(&_readerPointersMutex);
  729. auto it = constUnsafeFindReaderPointer(reader);
  730. if (it != _readerPointers.cend()) {
  731. int32 index = 0;
  732. Reader::Frame *frame = it.key()->frameToWrite(&index);
  733. if (frame) {
  734. frame->clear();
  735. } else {
  736. Assert(!reader->_request.valid());
  737. }
  738. reader->_frame = index;
  739. }
  740. }
  741. return handleResult(reader, reader->finishProcess(ms), ms);
  742. }
  743. return ResultHandleContinue;
  744. }
  745. void Manager::process() {
  746. if (_processingInThread) {
  747. _needReProcess = true;
  748. return;
  749. }
  750. _timer.stop();
  751. _processingInThread = thread();
  752. bool checkAllReaders = false;
  753. auto ms = crl::now(), minms = ms + 86400 * crl::time(1000);
  754. {
  755. QMutexLocker lock(&_readerPointersMutex);
  756. for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) {
  757. if (it->loadAcquire() && it.key()->_private != nullptr) {
  758. auto i = _readers.find(it.key()->_private);
  759. if (i == _readers.cend()) {
  760. _readers.insert(it.key()->_private, 0);
  761. } else {
  762. i.value() = ms;
  763. if (i.key()->_autoPausedGif && !it.key()->_autoPausedGif.loadAcquire()) {
  764. i.key()->_autoPausedGif = false;
  765. }
  766. if (it.key()->_videoPauseRequest.loadAcquire()) {
  767. i.key()->pauseVideo(ms);
  768. } else {
  769. i.key()->resumeVideo(ms);
  770. }
  771. }
  772. auto frame = it.key()->frameToWrite();
  773. if (frame) it.key()->_private->_request = frame->request;
  774. it->storeRelease(0);
  775. }
  776. }
  777. checkAllReaders = (_readers.size() > _readerPointers.size());
  778. }
  779. for (auto i = _readers.begin(), e = _readers.end(); i != e;) {
  780. ReaderPrivate *reader = i.key();
  781. if (i.value() <= ms) {
  782. ResultHandleState state = handleResult(reader, reader->process(ms), ms);
  783. if (state == ResultHandleRemove) {
  784. i = _readers.erase(i);
  785. continue;
  786. } else if (state == ResultHandleStop) {
  787. _processingInThread = nullptr;
  788. return;
  789. }
  790. ms = crl::now();
  791. if (reader->_videoPausedAtMs) {
  792. i.value() = ms + 86400 * 1000ULL;
  793. } else if (reader->_nextFrameWhen && reader->_started) {
  794. i.value() = reader->_nextFrameWhen;
  795. } else {
  796. i.value() = (ms + 86400 * 1000ULL);
  797. }
  798. } else if (checkAllReaders) {
  799. QMutexLocker lock(&_readerPointersMutex);
  800. auto it = constUnsafeFindReaderPointer(reader);
  801. if (it == _readerPointers.cend()) {
  802. _loadLevel.fetchAndAddRelaxed(-1 * (reader->_width > 0 ? reader->_width * reader->_height : kAverageGifSize));
  803. delete reader;
  804. i = _readers.erase(i);
  805. continue;
  806. }
  807. }
  808. if (!reader->_autoPausedGif && i.value() < minms) {
  809. minms = i.value();
  810. }
  811. ++i;
  812. }
  813. ms = crl::now();
  814. if (_needReProcess || minms <= ms) {
  815. _needReProcess = false;
  816. _timer.start(1);
  817. } else {
  818. _timer.start(minms - ms);
  819. }
  820. _processingInThread = nullptr;
  821. }
  822. void Manager::finish() {
  823. _timer.stop();
  824. clear();
  825. }
  826. void Manager::clear() {
  827. {
  828. QMutexLocker lock(&_readerPointersMutex);
  829. for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) {
  830. it.key()->_private = nullptr;
  831. }
  832. _readerPointers.clear();
  833. }
  834. for (Readers::iterator i = _readers.begin(), e = _readers.end(); i != e; ++i) {
  835. delete i.key();
  836. }
  837. _readers.clear();
  838. }
  839. Manager::~Manager() {
  840. clear();
  841. }
  842. Ui::PreparedFileInformation PrepareForSending(
  843. const QString &fname,
  844. const QByteArray &data) {
  845. auto result = Ui::PreparedFileInformation::Video();
  846. auto localLocation = Core::FileLocation(fname);
  847. auto localData = QByteArray(data);
  848. auto seekPositionMs = crl::time(0);
  849. auto reader = std::make_unique<internal::FFMpegReaderImplementation>(&localLocation, &localData);
  850. if (reader->start(internal::ReaderImplementation::Mode::Inspecting, seekPositionMs)) {
  851. const auto durationMs = reader->durationMs();
  852. if (durationMs > 0) {
  853. result.isGifv = reader->isGifv();
  854. result.isWebmSticker = reader->isWebmSticker();
  855. // Use first video frame as a thumbnail.
  856. // All other apps and server do that way.
  857. //if (!result.isGifv) {
  858. // auto middleMs = durationMs / 2;
  859. // if (!reader->inspectAt(middleMs)) {
  860. // return result;
  861. // }
  862. //}
  863. auto index = 0;
  864. auto hasAlpha = false;
  865. auto readResult = reader->readFramesTill(-1, crl::now());
  866. auto readFrame = (readResult == internal::ReaderImplementation::ReadResult::Success);
  867. if (readFrame && reader->renderFrame(result.thumbnail, hasAlpha, index, QSize())) {
  868. if (hasAlpha && !result.isWebmSticker) {
  869. result.thumbnail = Images::Opaque(std::move(result.thumbnail));
  870. }
  871. result.duration = durationMs;
  872. }
  873. result.supportsStreaming = CheckStreamingSupport(
  874. localLocation,
  875. localData);
  876. }
  877. }
  878. return { .media = result };
  879. }
  880. void Finish() {
  881. Workers.clear();
  882. }
  883. Reader *const ReaderPointer::BadPointer = reinterpret_cast<Reader*>(1);
  884. ReaderPointer::~ReaderPointer() {
  885. if (valid()) {
  886. delete _pointer;
  887. }
  888. _pointer = nullptr;
  889. }
  890. } // namespace Clip
  891. } // namespace Media