CodecsComponent.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  1. #include "CodecsComponent.h"
  2. #include <QDebug>
  3. #include <QString>
  4. #include <Qt>
  5. #include <QDir>
  6. #include <QDomAttr>
  7. #include <QDomDocument>
  8. #include <QDomNode>
  9. #include <QCoreApplication>
  10. #include <QProcess>
  11. #include <QUuid>
  12. #include <QUrl>
  13. #include <QUrlQuery>
  14. #include <QResource>
  15. #include <QSaveFile>
  16. #include <QStandardPaths>
  17. #include <QOperatingSystemVersion>
  18. #include <QCryptographicHash>
  19. #include <QTemporaryDir>
  20. #ifdef HAVE_MINIZIP
  21. #include <minizip/unzip.h>
  22. #include <minizip/ioapi.h>
  23. #endif
  24. #include "system/SystemComponent.h"
  25. #include "settings/SettingsComponent.h"
  26. #include "utils/Utils.h"
  27. #include "shared/Paths.h"
  28. #include "PlayerComponent.h"
  29. #define countof(x) (sizeof(x) / sizeof((x)[0]))
  30. // For QVariant. Mysteriously makes Qt happy.
  31. Q_DECLARE_METATYPE(CodecDriver);
  32. #ifdef HAVE_CODEC_MANIFEST
  33. #define WITH_CODECS 1
  34. #include "CodecManifest.h"
  35. #else
  36. #define WITH_CODECS 0
  37. #define CODEC_VERSION "dummy"
  38. #define SHLIB_PREFIX ""
  39. #define SHLIB_EXTENSION "dummy"
  40. // Codec.name is the name of the codec implementation, Codec.codecName the name of the codec
  41. struct Codec {const char* name; const char* codecName; const char* profiles; int external;};
  42. static const Codec Decoders[] = {
  43. {"dummy", "dummy", nullptr, 1},
  44. };
  45. static const Codec Encoders[] = {
  46. {"dummy", "dummy", nullptr, 1},
  47. };
  48. #endif
  49. #define STRINGIFY_(x) #x
  50. #define STRINGIFY(x) STRINGIFY_(x)
  51. #ifdef EAE_VERSION
  52. #define HAVE_EAE 1
  53. #else
  54. #define EAE_VERSION unavailable
  55. #define HAVE_EAE 0
  56. #endif
  57. // We might want to use Codec.quality to decide this one day.
  58. // But for now, it's better if we can quickly change these.
  59. static QSet<QString> g_systemVideoDecoderWhitelist = {
  60. // RPI
  61. "h264_mmal",
  62. "mpeg2_mmal",
  63. "mpeg4_mmal",
  64. "vc1_mmal",
  65. };
  66. static QSet<QString> g_systemAudioDecoderWhitelist = {
  67. // OSX
  68. "eac3_at",
  69. // Windows
  70. "eac3_mf",
  71. };
  72. static QSet<QString> g_systemAudioEncoderWhitelist = {
  73. };
  74. static QSize g_mediaFoundationH264MaxResolution;
  75. static QString g_codecVersion;
  76. static QList<CodecDriver> g_cachedCodecList;
  77. static QString g_deviceID;
  78. static QString g_eaeWatchFolder;
  79. static QProcess* g_eaeProcess;
  80. ///////////////////////////////////////////////////////////////////////////////////////////////////
  81. static QString getBuildType()
  82. {
  83. #ifdef Q_OS_MAC
  84. return "darwin-x86_64";
  85. #elif defined(TARGET_RPI)
  86. return "openelec-armv7";
  87. #else
  88. return SystemComponent::Get().getPlatformTypeString() + "-" +
  89. SystemComponent::Get().getPlatformArchString();
  90. #endif
  91. }
  92. ///////////////////////////////////////////////////////////////////////////////////////////////////
  93. static QString getEAEBuildType()
  94. {
  95. #if defined(Q_OS_MAC)
  96. return "darwin-x86_64";
  97. #elif defined(Q_OS_WIN)
  98. return sizeof(void *) > 4 ? "windows-x86_64" : "windows-i386";
  99. #elif defined(TARGET_RPI)
  100. return "linux-raspi2-arm7";
  101. #elif defined(Q_OS_LINUX)
  102. return sizeof(void *) > 4 ? "linux-ubuntu-x86_64" : "linux-ubuntu-i686";
  103. #else
  104. return "unknown";
  105. #endif
  106. }
  107. ///////////////////////////////////////////////////////////////////////////////////////////////////
  108. QString Codecs::plexNameToFF(QString plex)
  109. {
  110. if (plex == "dca")
  111. return "dts";
  112. return plex;
  113. }
  114. ///////////////////////////////////////////////////////////////////////////////////////////////////
  115. QString Codecs::plexNameFromFF(QString ffname)
  116. {
  117. if (ffname == "dts")
  118. return "dca";
  119. return ffname;
  120. }
  121. ///////////////////////////////////////////////////////////////////////////////////////////////////
  122. static QString codecsRootPath()
  123. {
  124. return Paths::dataDir("Codecs") + QDir::separator();
  125. }
  126. ///////////////////////////////////////////////////////////////////////////////////////////////////
  127. static QString codecsPath()
  128. {
  129. return codecsRootPath() + g_codecVersion + "-" + getBuildType() + QDir::separator();
  130. }
  131. ///////////////////////////////////////////////////////////////////////////////////////////////////
  132. static QString eaePrefixPath()
  133. {
  134. // (Keep in sync with PMS paths.)
  135. return codecsRootPath() + "EasyAudioEncoder-" + STRINGIFY(EAE_VERSION) + "-" + getBuildType();
  136. }
  137. ///////////////////////////////////////////////////////////////////////////////////////////////////
  138. static QString eaeBinaryPath()
  139. {
  140. QString exeSuffix = "";
  141. #ifdef Q_OS_WIN
  142. exeSuffix = ".exe";
  143. #endif
  144. return eaePrefixPath() + "/EasyAudioEncoder/EasyAudioEncoder" + exeSuffix;
  145. }
  146. ///////////////////////////////////////////////////////////////////////////////////////////////////
  147. static bool eaeIsPresent()
  148. {
  149. return QFile(eaeBinaryPath()).exists();
  150. }
  151. ///////////////////////////////////////////////////////////////////////////////////////////////////
  152. static int indexOfCodecInList(const QList<CodecDriver>& list, const CodecDriver& codec)
  153. {
  154. for (int n = 0; n < list.size(); n++)
  155. {
  156. if (Codecs::sameCodec(list[n], codec))
  157. return n;
  158. }
  159. return -1;
  160. }
  161. ///////////////////////////////////////////////////////////////////////////////////////////////////
  162. void Codecs::updateCachedCodecList()
  163. {
  164. g_cachedCodecList.clear();
  165. for (CodecType type : {CodecType::Decoder, CodecType::Encoder})
  166. {
  167. const Codec* list = (type == CodecType::Decoder) ? Decoders : Encoders;
  168. size_t count = (type == CodecType::Decoder) ? countof(Decoders) : countof(Encoders);
  169. for (size_t i = 0; i < count; i++)
  170. {
  171. CodecDriver codec = {};
  172. codec.type = type;
  173. codec.format = Codecs::plexNameToFF(list[i].codecName);
  174. codec.driver = list[i].name;
  175. codec.external = list[i].external;
  176. if (!codec.isSystemCodec())
  177. g_cachedCodecList.append(codec);
  178. }
  179. }
  180. // Set present flag for the installed codecs. Also, there could be codecs not
  181. // on the CodecManifest.h list (system codecs, or when compiled without
  182. // codec loading).
  183. QList<CodecDriver> installed = PlayerComponent::Get().installedCodecDrivers();
  184. // Surely O(n^2) won't be causing trouble, right?
  185. for (const CodecDriver& installedCodec : installed)
  186. {
  187. int index = indexOfCodecInList(g_cachedCodecList, installedCodec);
  188. if (index >= 0)
  189. g_cachedCodecList[index].present = true;
  190. else
  191. g_cachedCodecList.append(installedCodec);
  192. }
  193. }
  194. ///////////////////////////////////////////////////////////////////////////////////////////////////
  195. const QList<CodecDriver>& Codecs::getCachedCodecList()
  196. {
  197. return g_cachedCodecList;
  198. }
  199. ///////////////////////////////////////////////////////////////////////////////////////////////////
  200. QList<CodecDriver> Codecs::findCodecsByFormat(const QList<CodecDriver>& list, CodecType type, const QString& format)
  201. {
  202. QList<CodecDriver> result;
  203. for (const CodecDriver& codec : list)
  204. {
  205. if (codec.type == type && codec.format == format)
  206. result.append(codec);
  207. }
  208. return result;
  209. }
  210. ///////////////////////////////////////////////////////////////////////////////////////////////////
  211. QString CodecDriver::getMangledName() const
  212. {
  213. return driver + (type == CodecType::Decoder ? "_decoder" : "_encoder");
  214. }
  215. ///////////////////////////////////////////////////////////////////////////////////////////////////
  216. QString CodecDriver::getFileName() const
  217. {
  218. return SHLIB_PREFIX + getMangledName() + "." + SHLIB_EXTENSION;
  219. }
  220. ///////////////////////////////////////////////////////////////////////////////////////////////////
  221. QString CodecDriver::getPath() const
  222. {
  223. return QDir(codecsPath()).absoluteFilePath(getFileName());
  224. }
  225. ///////////////////////////////////////////////////////////////////////////////////////////////////
  226. bool CodecDriver::isSystemCodec() const
  227. {
  228. // MS Windows
  229. if (driver.endsWith("_mf"))
  230. return true;
  231. // OSX
  232. if (driver.endsWith("_at"))
  233. return true;
  234. // Linux on RPI
  235. if (driver.endsWith("_mmal"))
  236. return true;
  237. // Not really a system codec, but treated as such for convenience
  238. if (driver.endsWith("_eae"))
  239. return true;
  240. if (driver.endsWith("_cuvid"))
  241. return true;
  242. return false;
  243. }
  244. ///////////////////////////////////////////////////////////////////////////////////////////////////
  245. QString CodecDriver::getSystemCodecType() const
  246. {
  247. if (!isSystemCodec())
  248. return "";
  249. int splitAt = driver.indexOf("_");
  250. if (splitAt < 0)
  251. return "";
  252. return driver.mid(splitAt + 1);
  253. }
  254. ///////////////////////////////////////////////////////////////////////////////////////////////////
  255. bool CodecDriver::isWhitelistedSystemAudioCodec() const
  256. {
  257. if (type == CodecType::Decoder)
  258. return g_systemAudioDecoderWhitelist.contains(driver);
  259. else
  260. return g_systemAudioEncoderWhitelist.contains(driver);
  261. }
  262. ///////////////////////////////////////////////////////////////////////////////////////////////////
  263. bool CodecDriver::isWhitelistedSystemVideoCodec() const
  264. {
  265. if (type == CodecType::Decoder)
  266. return g_systemVideoDecoderWhitelist.contains(driver);
  267. return false;
  268. }
  269. ///////////////////////////////////////////////////////////////////////////////////////////////////
  270. static bool useSystemAudioDecoders()
  271. {
  272. return true;
  273. }
  274. ///////////////////////////////////////////////////////////////////////////////////////////////////
  275. static bool useSystemVideoDecoders()
  276. {
  277. return SettingsComponent::Get().value(SETTINGS_SECTION_MAIN, "useSystemVideoCodecs").toBool();
  278. }
  279. /////////////////////////////////////////////////////////////////////////////////////////
  280. // Load the device ID, do some minimal verification, return "" on error.
  281. static QString loadDeviceID(QString filename)
  282. {
  283. QFile path(filename);
  284. if (!path.open(QFile::ReadOnly))
  285. return "";
  286. auto res = QString::fromLatin1(path.readAll());
  287. if (res.size() < 32 || res.size() > 512)
  288. res = ""; // mark as invalid
  289. return res;
  290. }
  291. /////////////////////////////////////////////////////////////////////////////////////////
  292. static QString findOldDeviceID()
  293. {
  294. return "";
  295. }
  296. ///////////////////////////////////////////////////////////////////////////////////////////////////
  297. // Returns "" on error.
  298. static QString loadDeviceID()
  299. {
  300. QString deviceIDFilename = QDir(codecsRootPath()).absoluteFilePath(".device-id");
  301. QString id = loadDeviceID(deviceIDFilename);
  302. if (id.isEmpty())
  303. {
  304. id = findOldDeviceID();
  305. if (id.isEmpty())
  306. {
  307. id = QUuid::createUuid().toString();
  308. // The UUID should be e.g. "8f6ad954-0cb9-4dbb-a5e5-e0b085f07cf8"
  309. if (id.startsWith("{"))
  310. id = id.mid(1);
  311. if (id.endsWith("}"))
  312. id = id.mid(0, id.size() - 1);
  313. }
  314. Utils::safelyWriteFile(deviceIDFilename, id.toLatin1());
  315. // We load it again to make sure writing it succeeded. If it doesn't, we'll
  316. // error out at a later point.
  317. id = loadDeviceID(deviceIDFilename);
  318. }
  319. return id;
  320. }
  321. ///////////////////////////////////////////////////////////////////////////////////////////////////
  322. static QString getFFmpegVersion()
  323. {
  324. auto mpv = mpv::qt::Handle::FromRawHandle(mpv_create());
  325. if (!mpv || mpv_initialize(mpv) < 0)
  326. return "";
  327. return mpv::qt::get_property(mpv, "ffmpeg-version").toString();
  328. }
  329. ///////////////////////////////////////////////////////////////////////////////////////////////////
  330. static void setEnv(QString var, QString val)
  331. {
  332. #ifdef Q_OS_WIN
  333. SetEnvironmentVariableW(var.toStdWString().c_str(), val.toStdWString().c_str());
  334. #else
  335. qputenv(var.toUtf8().data(), val.toUtf8().data());
  336. #endif
  337. }
  338. ///////////////////////////////////////////////////////////////////////////////////////////////////
  339. void Codecs::preinitCodecs()
  340. {
  341. // Extract the CI codecs version we set with --extra-version when compiling FFmpeg.
  342. QString ffmpegVersion = getFFmpegVersion();
  343. int sep = ffmpegVersion.indexOf(',');
  344. if (sep >= 0)
  345. g_codecVersion = ffmpegVersion.mid(sep + 1);
  346. else
  347. g_codecVersion = CODEC_VERSION;
  348. QString path = codecsPath();
  349. QDir("").mkpath(path);
  350. // Follows the convention used by av_get_token().
  351. QString escapedPath = path.replace("\\", "\\\\").replace(":", "\\:").replace("'", "\\'");
  352. // This must be run before any threads are started etc. (for safety).
  353. setEnv("FFMPEG_EXTERNAL_LIBS", escapedPath);
  354. QTemporaryDir d(QDir::tempPath() + "/pmp-eae-XXXXXX");
  355. d.setAutoRemove(false);
  356. g_eaeWatchFolder = d.path();
  357. setEnv("EAE_ROOT", g_eaeWatchFolder);
  358. g_deviceID = loadDeviceID();
  359. }
  360. #if 0
  361. ///////////////////////////////////////////////////////////////////////////////////////////////////
  362. static bool probeDecoder(QString decoder, QString resourceName)
  363. {
  364. QResource resource(resourceName);
  365. qDebug() << "Testing decoding of" << resource.fileName();
  366. if (!resource.isValid())
  367. return false;
  368. auto mpv = mpv::qt::Handle::FromRawHandle(mpv_create());
  369. if (!mpv || mpv_initialize(mpv) < 0)
  370. return false;
  371. // Disable any output.
  372. mpv::qt::set_property(mpv, "vo", "null");
  373. // Force the decoder. The ",-" means that if the first entry fails, the next codec in the global
  374. // codec list will not be tried, and decoding fails.
  375. mpv::qt::set_property(mpv, "vd", "lavc:" + decoder + ",-");
  376. // Attempt decoding, and return success.
  377. auto data = QByteArray::fromRawData((const char *)resource.data(), resource.size());
  378. if (resource.isCompressed())
  379. data = qUncompress(data);
  380. auto hex = data.toHex();
  381. mpv::qt::command(mpv, QVariantList{"loadfile", "hex://" + QString::fromLatin1(hex)});
  382. bool result = false;
  383. while (1) {
  384. mpv_event *event = mpv_wait_event(mpv, 0);
  385. if (event->event_id == MPV_EVENT_SHUTDOWN)
  386. break;
  387. if (event->event_id == MPV_EVENT_END_FILE)
  388. {
  389. mpv_event_end_file *endFile = (mpv_event_end_file *)event->data;
  390. result = endFile->reason == MPV_END_FILE_REASON_EOF;
  391. break;
  392. }
  393. }
  394. qDebug() << "Result:" << result;
  395. return result;
  396. }
  397. #endif
  398. ///////////////////////////////////////////////////////////////////////////////////////////////////
  399. static void probeCodecs()
  400. {
  401. #if 0
  402. if (useSystemVideoDecoders())
  403. {
  404. if (probeDecoder("h264_mf", ":/testmedia/high_4096x2304.h264"))
  405. g_mediaFoundationH264MaxResolution = QSize(4096, 2304);
  406. else if (probeDecoder("h264_mf", ":/testmedia/high_4096x2160.h264"))
  407. g_mediaFoundationH264MaxResolution = QSize(4096, 2160);
  408. else if (probeDecoder("h264_mf", ":/testmedia/high_4096x1080.h264"))
  409. g_mediaFoundationH264MaxResolution = QSize(4096, 1080);
  410. else
  411. g_systemVideoDecoderWhitelist.remove("h264_mf");
  412. qDebug() << "h264_mf max. resolution:" << g_mediaFoundationH264MaxResolution;
  413. }
  414. #endif
  415. #ifdef Q_OS_MAC
  416. auto current = QOperatingSystemVersion::current();
  417. // Unsupported, but avoid picking up broken Perian decoders.
  418. if (current <= QOperatingSystemVersion::OSXYosemite)
  419. g_systemAudioDecoderWhitelist.remove("ac3_at");
  420. // Unknown Apple crashes
  421. if (current <= QOperatingSystemVersion::OSXElCapitan)
  422. g_systemAudioDecoderWhitelist.remove("aac_at");
  423. #endif
  424. }
  425. ///////////////////////////////////////////////////////////////////////////////////////////////////
  426. static void updateCodecs()
  427. {
  428. QStringList candidates = {
  429. codecsRootPath(),
  430. Paths::dataDir() + "/codecs/",
  431. };
  432. QSet<QString> codecFiles;
  433. bool needEAE = false;
  434. for (auto dir : candidates)
  435. {
  436. QDir qdir(dir);
  437. if (!qdir.exists())
  438. continue;
  439. for (auto entry : qdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
  440. {
  441. QDir entryDir = qdir;
  442. if (!entryDir.cd(entry))
  443. continue;
  444. for (auto codecdirEntry : entryDir.entryList(QDir::Files))
  445. codecFiles.insert(codecdirEntry);
  446. // NOTE: PMS also uses this prefix
  447. if (entry.startsWith("EasyAudioEncoder-") && !eaeIsPresent())
  448. needEAE = true;
  449. }
  450. }
  451. QList<CodecDriver> install;
  452. for (CodecDriver& codec : g_cachedCodecList)
  453. {
  454. if ((codecFiles.contains(codec.getFileName()) && codec.external && !codec.present) ||
  455. (codec.getSystemCodecType() == "eae" && needEAE))
  456. install.append(codec);
  457. }
  458. if (!install.empty())
  459. {
  460. QStringList codecs;
  461. for (auto codec : install)
  462. codecs.append(codec.getMangledName());
  463. qInfo() << "Updating some codecs: " + codecs.join(", ");
  464. auto fetcher = new CodecsFetcher();
  465. QObject::connect(fetcher, &CodecsFetcher::done, [](CodecsFetcher* sender)
  466. {
  467. qInfo() << "Codec update finished.";
  468. sender->deleteLater();
  469. });
  470. fetcher->startCodecs = false;
  471. fetcher->installCodecs(install);
  472. }
  473. }
  474. ///////////////////////////////////////////////////////////////////////////////////////////////////
  475. static void deleteOldCodecs()
  476. {
  477. QStringList neededPaths = {
  478. codecsPath(),
  479. };
  480. for (auto entry : QDir(codecsRootPath()).entryList(QDir::Dirs | QDir::NoDotAndDotDot))
  481. {
  482. QDir entryPath = codecsRootPath();
  483. if (!entryPath.cd(entry))
  484. continue;
  485. bool needed = false;
  486. for (auto neededPath : neededPaths)
  487. {
  488. if (entryPath.absolutePath() == QDir(neededPath).absolutePath())
  489. {
  490. needed = true;
  491. break;
  492. }
  493. }
  494. if (needed)
  495. continue;
  496. // Same version, but different platform -> just keep it.
  497. if (entry.startsWith(g_codecVersion + "-"))
  498. continue;
  499. // EAE is "special"
  500. if (entry.startsWith(QString("EasyAudioEncoder-") + STRINGIFY(EAE_VERSION) + "-"))
  501. continue;
  502. qDebug() << "Deleting old directory: " << entryPath.absolutePath();
  503. entryPath.removeRecursively();
  504. }
  505. }
  506. ///////////////////////////////////////////////////////////////////////////////////////////////////
  507. void Codecs::initCodecs()
  508. {
  509. if (g_deviceID.isEmpty())
  510. throw FatalException("Could not read device-id.");
  511. if (g_eaeWatchFolder.isEmpty())
  512. throw FatalException("Could not create EAE working directory.");
  513. Codecs::updateCachedCodecList();
  514. updateCodecs();
  515. deleteOldCodecs();
  516. probeCodecs();
  517. }
  518. ///////////////////////////////////////////////////////////////////////////////////////////////////
  519. bool CodecsFetcher::codecNeedsDownload(const CodecDriver& codec)
  520. {
  521. if (codec.present)
  522. return false;
  523. if (!codec.external)
  524. {
  525. qCritical() << "Codec" << codec.driver << "does not exist and is not downloadable.";
  526. return false;
  527. }
  528. for (int n = 0; n < m_Codecs.size(); n++)
  529. {
  530. if (Codecs::sameCodec(codec, m_Codecs[n]))
  531. return false;
  532. }
  533. QFile codecFile(codec.getPath());
  534. if (codecFile.exists())
  535. {
  536. qCritical() << "Codec" << codec.driver << "exists on disk as" << codec.getPath()
  537. << "but is not known as installed - broken codec?";
  538. if (!codecFile.remove())
  539. return false;
  540. qCritical() << "Retrying download.";
  541. }
  542. return true;
  543. }
  544. ///////////////////////////////////////////////////////////////////////////////////////////////////
  545. void CodecsFetcher::installCodecs(const QList<CodecDriver>& codecs)
  546. {
  547. foreach (CodecDriver codec, codecs)
  548. {
  549. if (codecNeedsDownload(codec))
  550. m_Codecs.enqueue(codec);
  551. if (codec.getSystemCodecType() == "eae")
  552. {
  553. m_eaeNeeded = true;
  554. if (!eaeIsPresent())
  555. m_fetchEAE = true;
  556. }
  557. }
  558. startNext();
  559. }
  560. ///////////////////////////////////////////////////////////////////////////////////////////////////
  561. static Downloader::HeaderList getPlexHeaders()
  562. {
  563. Downloader::HeaderList headers;
  564. return headers;
  565. }
  566. static QUrl buildCodecQuery(QString version, QString name, QString build)
  567. {
  568. return QUrl("");
  569. }
  570. ///////////////////////////////////////////////////////////////////////////////////////////////////
  571. void CodecsFetcher::startNext()
  572. {
  573. if (m_fetchEAE)
  574. {
  575. m_fetchEAE = false;
  576. QUrl url = buildCodecQuery(STRINGIFY(EAE_VERSION), "easyaudioencoder", getEAEBuildType());
  577. Downloader *downloader = new Downloader(QVariant("eae"), url, getPlexHeaders(), this);
  578. connect(downloader, &Downloader::done, this, &CodecsFetcher::codecInfoDownloadDone);
  579. return;
  580. }
  581. if (m_Codecs.isEmpty())
  582. {
  583. // Do final initializations.
  584. if (m_eaeNeeded && startCodecs)
  585. startEAE();
  586. emit done(this);
  587. return;
  588. }
  589. CodecDriver codec = m_Codecs.dequeue();
  590. QUrl url = buildCodecQuery(g_codecVersion, codec.getMangledName(), getBuildType());
  591. Downloader *downloader = new Downloader(QVariant::fromValue(codec), url, getPlexHeaders(), this);
  592. connect(downloader, &Downloader::done, this, &CodecsFetcher::codecInfoDownloadDone);
  593. }
  594. ///////////////////////////////////////////////////////////////////////////////////////////////////
  595. bool CodecsFetcher::processCodecInfoReply(const QVariant& context, const QByteArray& data)
  596. {
  597. qInfo() << "Got reply:" << QString::fromUtf8(data);
  598. QDomDocument dom;
  599. if (!dom.setContent(data))
  600. {
  601. qCritical() << "XML parsing error.";
  602. return false;
  603. }
  604. QDomNodeList list = dom.elementsByTagName("MediaContainer");
  605. if (list.count() != 1)
  606. {
  607. qCritical() << "MediaContainer XML element not found.";
  608. return false;
  609. }
  610. list = dom.elementsByTagName("Codec");
  611. if (list.count() != 1)
  612. {
  613. qCritical() << "Codec XML element not found.";
  614. return false;
  615. }
  616. QDomNamedNodeMap attrs = list.at(0).attributes();
  617. QString url = attrs.namedItem("url").toAttr().value();
  618. if (!url.size())
  619. {
  620. qCritical() << "No URL found.";
  621. return false;
  622. }
  623. QString hash = attrs.namedItem("fileSha").toAttr().value();
  624. m_currentHash = QByteArray::fromHex(hash.toUtf8());
  625. // it's hardcoded to SHA-1
  626. if (!m_currentHash.size()) {
  627. qCritical() << "Hash value in unexpected format or missing:" << hash;
  628. return false;
  629. }
  630. Downloader *downloader = new Downloader(context, url, getPlexHeaders(), this);
  631. connect(downloader, &Downloader::done, this, &CodecsFetcher::codecDownloadDone);
  632. return true;
  633. }
  634. ///////////////////////////////////////////////////////////////////////////////////////////////////
  635. void CodecsFetcher::codecInfoDownloadDone(QVariant userData, bool success, const QByteArray& data)
  636. {
  637. if (!success || !processCodecInfoReply(userData, data))
  638. {
  639. qCritical() << "Codec download failed.";
  640. startNext();
  641. }
  642. }
  643. #ifdef HAVE_MINIZIP
  644. static voidpf unz_open_file(voidpf opaque, const char* filename, int mode)
  645. {
  646. #ifdef Q_OS_WIN32
  647. return _wfopen(QString::fromUtf8(filename).toStdWString().c_str(), L"rb");
  648. #else
  649. return fopen(filename, "rb");
  650. #endif
  651. }
  652. static uLong unz_read_file(voidpf opaque, voidpf stream, void* buf, uLong size)
  653. {
  654. return fread(buf, 1, size, (FILE *)stream);
  655. }
  656. static uLong unz_write_file(voidpf opaque, voidpf stream, const void* buf, uLong size)
  657. {
  658. return 0;
  659. }
  660. static int unz_close_file(voidpf opaque, voidpf stream)
  661. {
  662. return fclose((FILE *)stream);
  663. }
  664. static int unz_error_file(voidpf opaque, voidpf stream)
  665. {
  666. return ferror((FILE *)stream);
  667. }
  668. static long unz_tell_file(voidpf opaque, voidpf stream)
  669. {
  670. return ftell((FILE *)stream);
  671. }
  672. long unz_seek_file(voidpf opaque, voidpf stream, uLong offset, int origin)
  673. {
  674. int whence = -1;
  675. switch (origin)
  676. {
  677. case ZLIB_FILEFUNC_SEEK_CUR:
  678. whence = SEEK_CUR;
  679. break;
  680. case ZLIB_FILEFUNC_SEEK_END:
  681. whence = SEEK_END;
  682. break;
  683. case ZLIB_FILEFUNC_SEEK_SET:
  684. whence = SEEK_SET;
  685. break;
  686. }
  687. return fseek((FILE *)stream, offset, whence);
  688. }
  689. ///////////////////////////////////////////////////////////////////////////////////////////////////
  690. static bool extractZip(QString zip, QString dest)
  691. {
  692. bool success = false;
  693. zlib_filefunc_def unzfilefuncs = {};
  694. unzfilefuncs.zopen_file = unz_open_file;
  695. unzfilefuncs.zread_file = unz_read_file;
  696. unzfilefuncs.zwrite_file = unz_write_file;
  697. unzfilefuncs.ztell_file = unz_tell_file;
  698. unzfilefuncs.zseek_file = unz_seek_file;
  699. unzfilefuncs.zclose_file = unz_close_file;
  700. unzfilefuncs.zerror_file = unz_error_file;
  701. unzFile file = unzOpen2(zip.toUtf8().data(), &unzfilefuncs);
  702. if (!file)
  703. {
  704. qCritical() << "could not open .zip file.";
  705. goto fail;
  706. }
  707. unz_global_info info;
  708. int unzerr;
  709. if ((unzerr = unzGetGlobalInfo(file, &info)) != UNZ_OK)
  710. {
  711. qCritical() << "unzGlobalInfo() failed with" << unzerr;
  712. goto fail;
  713. }
  714. if ((unzerr = unzGoToFirstFile(file)) != UNZ_OK)
  715. {
  716. qCritical() << "unzGoToFirstFile() failed with" << unzerr;
  717. goto fail;
  718. }
  719. for (ZPOS64_T n = 0; n < info.number_entry; n++)
  720. {
  721. if (n > 0 && (unzerr = unzGoToNextFile(file)) != UNZ_OK)
  722. {
  723. qCritical() << "unzGoToNextFile() failed with" << unzerr;
  724. goto fail;
  725. }
  726. char filename[256];
  727. unz_file_info finfo;
  728. if ((unzerr = unzGetCurrentFileInfo(file, &finfo, filename, sizeof(filename), 0, 0, 0, 0)) != UNZ_OK)
  729. {
  730. qCritical() << "unzGetCurrentFileInfo() failed with" << unzerr;
  731. goto fail;
  732. }
  733. if ((unzerr = unzOpenCurrentFile(file)) != UNZ_OK)
  734. {
  735. qCritical() << "unzOpenCurrentFile() failed with" << unzerr;
  736. goto fail;
  737. }
  738. char *pathpart = strrchr(filename, '/');
  739. if (pathpart)
  740. {
  741. // This part sucks especially: temporarily cut off the string.
  742. *pathpart = '\0';
  743. QDir dir(dest + "/" + filename);
  744. if (!dir.mkpath("."))
  745. {
  746. qCritical() << "could not create zip sub directory";
  747. goto fail;
  748. }
  749. *pathpart = '/';
  750. }
  751. // Directory (probably)
  752. if (QString(filename).endsWith("/"))
  753. continue;
  754. QString writepath = dest + "/" + filename;
  755. QSaveFile out(writepath);
  756. if (!out.open(QIODevice::WriteOnly))
  757. {
  758. qCritical() << "could not open output file" << filename;
  759. goto fail;
  760. }
  761. while (true)
  762. {
  763. char buf[4096];
  764. int read = unzReadCurrentFile(file, buf, sizeof(buf));
  765. if (read == 0)
  766. break;
  767. if (read < 0)
  768. {
  769. qCritical() << "error decompressing zip entry" << filename;
  770. goto fail;
  771. }
  772. if (out.write(buf, read) != read)
  773. {
  774. qCritical() << "error writing output file" << filename;
  775. goto fail;
  776. }
  777. }
  778. if (!out.commit())
  779. {
  780. qCritical() << "error closing output file" << filename;
  781. goto fail;
  782. }
  783. #ifndef _WIN32
  784. // Set the executable bit.
  785. // We could try setting the full permissions as stored in the file, but why bother.
  786. if (finfo.external_fa & 0x400000)
  787. {
  788. if (!QFile::setPermissions(writepath, QFileDevice::Permissions(0x5145)))
  789. {
  790. qCritical() << "could not set output executable bit on extracted file";
  791. goto fail;
  792. }
  793. }
  794. #endif
  795. }
  796. success = true;
  797. fail:
  798. unzClose(file);
  799. return success;
  800. }
  801. #else /* ifdef HAVE_MINIZIP */
  802. ///////////////////////////////////////////////////////////////////////////////////////////////////
  803. static bool extractZip(QString zip, QString dest)
  804. {
  805. return false;
  806. }
  807. #endif
  808. ///////////////////////////////////////////////////////////////////////////////////////////////////
  809. void CodecsFetcher::processCodecDownloadDone(const QVariant& context, const QByteArray& data)
  810. {
  811. QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha1);
  812. if (hash != m_currentHash)
  813. {
  814. qCritical() << "Checksum mismatch: got" << hash.toHex() << "expected" << m_currentHash.toHex();
  815. return;
  816. }
  817. if (context == QVariant("eae"))
  818. {
  819. QString dest = eaePrefixPath() + ".zip";
  820. qInfo() << "Storing EAE as" << dest;
  821. if (!Utils::safelyWriteFile(dest, data))
  822. {
  823. qCritical() << "Writing codec file failed.";
  824. return;
  825. }
  826. QDir dir(dest);
  827. dir.removeRecursively();
  828. if (!extractZip(dest, eaePrefixPath()))
  829. {
  830. qCritical() << "Could not extract zip.";
  831. dir.removeRecursively();
  832. return;
  833. }
  834. QFile::remove(dest);
  835. }
  836. else
  837. {
  838. CodecDriver codec = context.value<CodecDriver>();
  839. qInfo() << "Storing codec as" << codec.getPath();
  840. if (!Utils::safelyWriteFile(codec.getPath(), data))
  841. {
  842. qCritical() << "Writing codec file failed.";
  843. return;
  844. }
  845. // This causes libmpv and eventually libavcodec to rescan and load new codecs.
  846. Codecs::updateCachedCodecList();
  847. for (const CodecDriver& item : Codecs::getCachedCodecList())
  848. {
  849. if (Codecs::sameCodec(item, codec) && !item.present)
  850. {
  851. qCritical() << "Codec could not be loaded after installing it.";
  852. return;
  853. }
  854. }
  855. }
  856. qInfo() << "Codec download and installation succeeded.";
  857. }
  858. ///////////////////////////////////////////////////////////////////////////////////////////////////
  859. void CodecsFetcher::codecDownloadDone(QVariant userData, bool success, const QByteArray& data)
  860. {
  861. qInfo() << "Codec request finished.";
  862. if (success)
  863. {
  864. processCodecDownloadDone(userData, data);
  865. }
  866. else
  867. {
  868. qCritical() << "Codec download HTTP request failed.";
  869. }
  870. startNext();
  871. }
  872. ///////////////////////////////////////////////////////////////////////////////////////////////////
  873. void CodecsFetcher::startEAE()
  874. {
  875. if (!g_eaeProcess)
  876. {
  877. g_eaeProcess = new QProcess();
  878. g_eaeProcess->setProcessChannelMode(QProcess::ForwardedChannels);
  879. connect(g_eaeProcess, &QProcess::stateChanged,
  880. [](QProcess::ProcessState s)
  881. {
  882. qInfo() << "EAE process state:" << s;
  883. }
  884. );
  885. connect(g_eaeProcess, &QProcess::errorOccurred,
  886. [](QProcess::ProcessError e)
  887. {
  888. qInfo() << "EAE process error:" << e;
  889. }
  890. );
  891. connect(g_eaeProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
  892. [](int exitCode, QProcess::ExitStatus exitStatus)
  893. {
  894. qInfo() << "EAE process finished:" << exitCode << exitStatus;
  895. }
  896. );
  897. }
  898. if (g_eaeProcess->state() == QProcess::NotRunning)
  899. {
  900. if (g_eaeProcess->program().size())
  901. {
  902. int exitCode = g_eaeProcess->exitStatus() == QProcess::NormalExit ? g_eaeProcess->exitCode() : -1;
  903. qCritical() << "EAE died with exit code" << exitCode;
  904. }
  905. qInfo() << "Starting EAE.";
  906. g_eaeProcess->setProgram(eaeBinaryPath());
  907. g_eaeProcess->setWorkingDirectory(g_eaeWatchFolder);
  908. QDir dir(g_eaeWatchFolder);
  909. dir.removeRecursively();
  910. dir.mkpath(".");
  911. static const QStringList watchfolder_names =
  912. {
  913. "Convert to WAV (to 2ch or less)",
  914. "Convert to WAV (to 8ch or less)",
  915. "Convert to Dolby Digital (Low Quality - 384 kbps)",
  916. "Convert to Dolby Digital (High Quality - 640 kbps)",
  917. "Convert to Dolby Digital Plus (High Quality - 384 kbps)",
  918. "Convert to Dolby Digital Plus (Max Quality - 1024 kbps)",
  919. };
  920. for (auto folder : watchfolder_names)
  921. {
  922. if (!dir.mkpath(folder))
  923. {
  924. qCritical() << "Could not create watch folder";
  925. }
  926. }
  927. g_eaeProcess->start();
  928. }
  929. }
  930. ///////////////////////////////////////////////////////////////////////////////////////////////////
  931. Downloader::Downloader(QVariant userData, const QUrl& url, const HeaderList& headers, QObject* parent)
  932. : QObject(parent), m_userData(userData), m_lastProgress(-1)
  933. {
  934. qInfo() << "HTTP request:" << url.toDisplayString();
  935. m_currentStartTime.start();
  936. connect(&m_WebCtrl, &QNetworkAccessManager::finished, this, &Downloader::networkFinished);
  937. QNetworkRequest request(url);
  938. for (int n = 0; n < headers.size(); n++)
  939. request.setRawHeader(headers[n].first.toUtf8(), headers[n].second.toUtf8());
  940. QNetworkReply *reply = m_WebCtrl.get(request);
  941. if (reply)
  942. {
  943. connect(reply, &QNetworkReply::downloadProgress, this, &Downloader::downloadProgress);
  944. }
  945. }
  946. ///////////////////////////////////////////////////////////////////////////////////////////////////
  947. void Downloader::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
  948. {
  949. if (bytesTotal > 0)
  950. {
  951. int progress = (int)(bytesReceived * 100 / bytesTotal);
  952. if (m_lastProgress < 0 || progress > m_lastProgress + 10)
  953. {
  954. m_lastProgress = progress;
  955. qInfo() << "HTTP request at" << progress << "% (" << bytesReceived << "/" << bytesTotal << ")";
  956. }
  957. }
  958. }
  959. ///////////////////////////////////////////////////////////////////////////////////////////////////
  960. void Downloader::networkFinished(QNetworkReply* pReply)
  961. {
  962. qInfo() << "HTTP finished after" << (m_currentStartTime.elapsed() + 500) / 1000
  963. << "seconds for a request of" << pReply->size() << "bytes.";
  964. if (pReply->error() == QNetworkReply::NoError)
  965. {
  966. emit done(m_userData, true, pReply->readAll());
  967. }
  968. else
  969. {
  970. qCritical() << "HTTP download error:" << pReply->errorString();
  971. emit done(m_userData, false, QByteArray());
  972. }
  973. pReply->deleteLater();
  974. m_WebCtrl.clearAccessCache(); // make sure the TCP connection is closed
  975. }
  976. ///////////////////////////////////////////////////////////////////////////////////////////////////
  977. static CodecDriver selectBestDecoder(const StreamInfo& stream)
  978. {
  979. QList<CodecDriver> codecs = Codecs::findCodecsByFormat(Codecs::getCachedCodecList(), CodecType::Decoder, stream.codec);
  980. CodecDriver best = {};
  981. int bestScore = -1;
  982. for (auto codec : codecs)
  983. {
  984. int score = -1;
  985. if (codec.isSystemCodec())
  986. {
  987. // we always want to avoid using non-whitelisted system codecs
  988. // on the other hand, always prefer whitelisted system codecs
  989. if ((codec.isWhitelistedSystemAudioCodec() && useSystemAudioDecoders()) ||
  990. (codec.isWhitelistedSystemVideoCodec() && useSystemVideoDecoders()))
  991. score = 10;
  992. if (codec.format == "h264")
  993. {
  994. // Avoid using system video decoders for h264 profiles usually not supported.
  995. if (stream.profile != "" && stream.profile != "main" && stream.profile != "baseline" && stream.profile != "high")
  996. score = 1;
  997. }
  998. if (codec.driver == "h264_mf")
  999. {
  1000. if (!stream.videoResolution.isEmpty())
  1001. {
  1002. QSize res = stream.videoResolution;
  1003. if (res.width() > g_mediaFoundationH264MaxResolution.width() ||
  1004. res.height() > g_mediaFoundationH264MaxResolution.height())
  1005. score = 1;
  1006. }
  1007. }
  1008. if (codec.driver == "aac_mf")
  1009. {
  1010. // Arbitrary but documented and enforced 6 channel limit by MS.
  1011. if (stream.audioChannels > 6)
  1012. score = 1;
  1013. // Another arbitrary limit.
  1014. if (stream.audioSampleRate > 0 && (stream.audioSampleRate < 8000 || stream.audioSampleRate > 48000))
  1015. score = 1;
  1016. }
  1017. if (codec.getSystemCodecType() == "eae")
  1018. score = HAVE_EAE ? 2 : -1;
  1019. }
  1020. else
  1021. {
  1022. // prefer codecs which do not have to be downloaded over others
  1023. if (codec.present)
  1024. score = 15;
  1025. else
  1026. score = 5;
  1027. }
  1028. if (score > bestScore && score >= 0)
  1029. {
  1030. best = codec;
  1031. bestScore = score;
  1032. }
  1033. }
  1034. return best;
  1035. }
  1036. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1037. QList<CodecDriver> Codecs::determineRequiredCodecs(const PlaybackInfo& info)
  1038. {
  1039. QList<CodecDriver> result;
  1040. bool needAC3Encoder = false;
  1041. qInfo() << "Using system audio decoders:" << useSystemAudioDecoders();
  1042. qInfo() << "Using system video decoders:" << useSystemVideoDecoders();
  1043. #if !defined(HAVE_CODEC_MANIFEST)
  1044. qInfo() << "Not using on-demand codecs.";
  1045. #endif
  1046. for (auto stream : info.streams)
  1047. {
  1048. if (!stream.isVideo && !stream.isAudio)
  1049. continue;
  1050. if (!stream.codec.size())
  1051. {
  1052. qCritical() << "unidentified codec";
  1053. continue;
  1054. }
  1055. // We could do this if we'd find a nice way to enable passthrough by default:
  1056. #if 0
  1057. // Can passthrough be used? If so, don't request a codec.
  1058. if (info.audioPassthroughCodecs.contains(stream.codec))
  1059. continue;
  1060. #endif
  1061. // (Would be nice to check audioChannels here to not request the encoder
  1062. // when playing stereo - but unfortunately, the ac3 encoder is loaded first,
  1063. // and only removed when detecting stereo input)
  1064. if (info.enableAC3Transcoding)
  1065. needAC3Encoder = true;
  1066. CodecDriver best = selectBestDecoder(stream);
  1067. if (best.valid())
  1068. {
  1069. result.append(best);
  1070. }
  1071. else
  1072. {
  1073. qCritical() << "no decoder for" << stream.codec;
  1074. }
  1075. }
  1076. if (needAC3Encoder)
  1077. {
  1078. QList<CodecDriver> codecs = Codecs::findCodecsByFormat(Codecs::getCachedCodecList(), CodecType::Encoder, "ac3");
  1079. CodecDriver encoder = {};
  1080. for (auto codec : codecs)
  1081. {
  1082. if (codec.present && (!codec.isSystemCodec() || codec.isWhitelistedSystemAudioCodec()))
  1083. {
  1084. encoder = codec;
  1085. break;
  1086. }
  1087. if (codec.external)
  1088. encoder = codec; // fallback
  1089. }
  1090. if (encoder.valid())
  1091. {
  1092. result.append(encoder);
  1093. }
  1094. else
  1095. {
  1096. qCritical() << "no AC3 encoder available";
  1097. }
  1098. }
  1099. return result;
  1100. }
  1101. void Codecs::Uninit()
  1102. {
  1103. if (g_eaeProcess)
  1104. {
  1105. delete g_eaeProcess;
  1106. g_eaeProcess = nullptr;
  1107. }
  1108. if (!g_eaeWatchFolder.isEmpty())
  1109. {
  1110. QDir dir(g_eaeWatchFolder);
  1111. dir.removeRecursively();
  1112. }
  1113. }