You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
18KB

  1. // DTS Coherent Acoustics decoder for foobar2000
  2. // Originally based on dtsdec, Copyright (C) 2004 Gildas Bazin <gbazin@videolan.org>
  3. // (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
  4. // (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
  5. // Now based on dcadec, Copyright (C) 2015 foo86
  6. // foobar2000 component copyright (C) 2004-2006 Janne Hyvärinen
  7. // (C) 2006-2018 Christopher Snowhill
  8. //
  9. // Changes:
  10. // 0.6.9 (2020-03-06): Faster but inexact seeking of raw DTS and .DTSWAV files
  11. // 0.6.8 (2019-02-20): Fixed plain DTS file seeking
  12. // 0.6.7 (2019-01-11): Fixed decode postprocessor handling multiple packets in a single decode call
  13. // 0.6.6 (2019-01-10): Fixed decode postprocessor handling pre-stream silence
  14. // 0.6.5 (2019-01-10): Hopefully fixed Windows XP support
  15. // 0.6.4 (2019-01-10): Fixed decode postprocessor to handle invalid packets as invalid stream instead of throwing an exception
  16. // 0.6.3 (2019-01-09): Added extra format information discovery
  17. // 0.6.2 (2019-01-09): Fixed the decode postprocessor
  18. // 0.6.1 (2019-01-07): Fixed the packet decoder
  19. // 0.6.0 (2019-01-07): Switched over to using FFmpeg
  20. // 0.5.5 (2019-01-05): Fixed packet decoder analyze support detection, and implemented support for DTS-HD in MP4 container
  21. // 0.5.4 (2018-01-14): Updated to version 1.4 SDK
  22. // 0.5.3 (2017-02-04): Added link to about string
  23. // 0.5.2 (2016-02-21): Updated the credits, and fixed a UTF-8 encoding issue
  24. // 0.5.1 (2016-02-21): Added support for DTS header specifying a sample delay
  25. // 0.5.0 (2016-02-19): Added .dtshd and .dtsma file name extensions
  26. // 0.4.9 (2016-02-19): Fix several glaring faults in my conversion of the updated dca stream parser
  27. // 0.4.8 (2016-02-18): Fix frame size calculation when dealing with 14 bit streams, especially with odd frame lengths
  28. // 0.4.7 (2016-02-17): Fix a buffer overrun issue with the decode postprocessor when dealing with incorrect data
  29. // 0.4.6 (2016-02-14): Massive update to dcadec-0.2, now with no-C99 backport
  30. // 0.4.5 (2015-05-23): Fixed a potential crash with the decode postprocessor
  31. // 0.4.4 (2015-05-23): Fixed decode postprocessor handling packets split across audio chunks by retaining several state variables
  32. // 0.4.3 (2015-04-16): Made DTS codec profile info more in line with official branding
  33. // 0.4.2 (2015-04-14): Removed usage of the popcnt opcode, which requires arbitrary new processors, and fixed profile string generation
  34. // 0.4.1 (2015-04-13): Added 14 bit to 16 bit packing to packet decoder
  35. // 0.4.0 (2015-04-13): Replaced libdca with libdcadec
  36. // 0.3.3 (2014-02-16): Implemented support for packet decoding from MP4 files
  37. // 0.3.2 (2013-11-03): Fixed channel mode reporting in the event that dts_flags has an invalid channel number field
  38. // 0.3.1 (2013-01-31): Amended decode postprocessor to emit silence in the same format as the DTS signal
  39. // 0.3.0 (2010-09-03): Added support for 48KHz source streams to the decode postprocessor
  40. // 0.2.9 (2010-05-23): Implemented decode_postprocessor interface, removed DSP
  41. // 0.2.8 (2010-01-11): Updated to 1.0 SDK
  42. // 0.2.7 (2009-12-13): Found and fixed another false positive with the DSP
  43. // 0.2.6 (2009-12-13): Really fixed DTS decoder DSP this time
  44. // 0.2.5 (2009-12-05): Fixed heap corruption on bad DTS files, DSP doesn't output until two consecutive frames are found
  45. // 0.2.4 (2009-05-02): Fixed a bug in DTS DSP and packet decoder for when dca_syncinfo fails
  46. // 0.2.3 (2009-03-30): Fixed tag writing
  47. // 0.2.2 (2008-10-26): Restricted silence generation to DTS WAV files
  48. // 0.2.1 (2008-09-28): Seeking accuracy improvements, SDK's Decoder Validator was broken and didn't notice the bugs
  49. // 0.2.0 (2008-09-13): Added preliminary DSP decoder for use with DTS audio CDs and WAVs without changing extension
  50. // 0.1.9 (2008-09-02): Small change: output silence instead of nothing when decoding a block fails
  51. // 0.1.8 (2008-09-02): Tagging configuration is back (in Advanced preferences), updated libdca to version 0.0.5, seeking accuracy improved
  52. // 0.1.7 (2006-07-22): Added support for internal cuesheets
  53. // 0.1.6 (2006-07-12): Playback from cuesheets always started from the beginning of the file, fixed
  54. // 0.1.5 (2006-07-09): foobar2000 v0.9.x conversion
  55. // 0.1.4 (2005-07-24): Accepts header with reversed word order
  56. // 0.1.3 (2005-03-28): Smarter channel order fixing. Now uses 9 channel output only for files that output to center rear speaker.
  57. // Added channel order hack also to packet decoder, added configuration
  58. // 0.1.2 (2005-03-28): Fixed crashing with invalid files
  59. // 0.1.1 (2005-03-26): Hack to fix output channel order for odd channel modes
  60. // 0.1 (2005-03-20): Fixed incorrect handling for files that had no LFE channel, more accurate seeking
  61. // 0.0.9 (2005-01-01): Fixed hanging at the end of DTS files
  62. // 0.0.8 (2004-12-27): Improved DTS-in-wav detection
  63. // 0.0.7 (2004-10-23): Added DTS header seeking to support more DTS-in-wav files
  64. // 0.0.6 (2004-10-20): Removed most of the changes for 0.0.5 and replaced with hacks for now
  65. // 0.0.5 (2004-10-17): Fixes to raw DTS handling
  66. // 0.0.4 (2004-10-15): Simplified packet decoder, added codec reporting, fixed typo in version number
  67. // 0.0.3 (2004-10-15): Added Matroska packet decoder support
  68. #define FD_VERSION "0.6.9"
  69. //#define DTS_DEBUG // print status info to console
  70. #include "../SDK/foobar2000.h"
  71. #include "../helpers/helpers.h"
  72. using namespace pfc;
  73. #include "ffmpeg_shared.h"
  74. enum {
  75. BUFFER_SIZE = 24576,
  76. HEADER_SIZE = 14,
  77. FRAME_SAMPLES = 256,
  78. };
  79. //cfg_int cfg_drc ( "drc", 0 ); // Dynamic range compression defaults to off
  80. //cfg_int cfg_tag ( "tag", 1 ); // Write APEv2 tags by default
  81. static const GUID guid_dts_branch = { 0x879389e3, 0x8c4, 0x4db0, { 0x8c, 0xb7, 0xec, 0x51, 0x3d, 0xb5, 0xd9, 0x14 } };
  82. static const GUID guid_enable_tag = { 0x39e19ab2, 0xfb84, 0x4657, { 0xbf, 0x8c, 0x7a, 0x55, 0x7a, 0x35, 0xce, 0x72 } };
  83. //static const GUID guid_enable_drc = { 0xe254b211, 0xc3f4, 0x40b6, { 0x91, 0xc, 0xa8, 0x3e, 0xe, 0x7f, 0x61, 0x2f } };
  84. static advconfig_branch_factory dts_tagging_branch("DTS", guid_dts_branch, advconfig_branch::guid_branch_tagging, 0);
  85. static advconfig_checkbox_factory g_cfg_tag("Enable APEv2 tag writing", guid_enable_tag, guid_dts_branch, 0, true);
  86. //static advconfig_checkbox_factory g_cfg_drc("DTS - Use dynamic range compression", guid_enable_drc, advconfig_branch::guid_branch_decoding, 0, false);
  87. // -------------------------------------
  88. static void parse_tagtype_internal(const char *p_tagtype, bool &p_have_id3v1, bool &p_have_id3v2, bool &p_have_apev2)
  89. {
  90. const char *tagtype = p_tagtype;
  91. while(*tagtype)
  92. {
  93. unsigned delta = 0;
  94. while(tagtype[delta] != 0 && tagtype[delta] != '|') delta++;
  95. if (delta > 0)
  96. {
  97. if (!stricmp_utf8_ex(tagtype, delta, "apev1", ~0) || !stricmp_utf8_ex(tagtype, delta, "apev2", ~0))
  98. p_have_apev2 = true;
  99. else if (!stricmp_utf8_ex(tagtype, delta, "id3v1", ~0))
  100. p_have_id3v1 = true;
  101. else if (!stricmp_utf8_ex(tagtype, delta, "id3v2", ~0))
  102. p_have_id3v2 = true;
  103. }
  104. tagtype += delta;
  105. while(*tagtype == '|') tagtype++;
  106. }
  107. }
  108. class input_dts : public input_stubs {
  109. private:
  110. service_ptr_t<file> r;
  111. ffmpeg_codec_data * data;
  112. t_filesize header_pos;
  113. bool eof, iswav;
  114. /*
  115. uint8_t buf[BUFFER_SIZE];
  116. uint8_t *bufptr, *bufpos;
  117. */
  118. t_filesize tag_offset;
  119. int dts_flags, nch, srate, bps, frame_size;
  120. double real_bitrate;
  121. unsigned int skip_samples;
  122. unsigned int skip_decoding_packets;
  123. unsigned int channel_mask;
  124. unsigned int silence_bytes;
  125. unsigned int delay_samples;
  126. unsigned int dynamic_interval;
  127. unsigned int dynamic_last_decoded;
  128. unsigned int dynamic_decoded_this_interval;
  129. unsigned int dynamic_blocks_per_interval;
  130. unsigned int dynamic_bitrate_total;
  131. unsigned int dynamic_current_bitrate;
  132. unsigned int dynamic_bitrate_count;
  133. pfc::array_t<unsigned int> dynamic_bitrates;
  134. __int64 skip_wav_header(file::ptr & r, abort_callback &p_abort)
  135. {
  136. t_filesize pos = r->get_position(p_abort);
  137. t_filesize filesize = r->get_size(p_abort);
  138. for (;;) {
  139. char temp[4];
  140. DWORD tmp;
  141. r->read(temp, 4, p_abort);
  142. if (memcmp(temp, "RIFF", 4)) break;
  143. r->read(temp, 4, p_abort);
  144. r->read(temp, 4, p_abort);
  145. if (memcmp(temp, "WAVE", 4)) break;
  146. for (;;) {
  147. if (r->read(temp, 4, p_abort) != 4) break;
  148. if (!memcmp(temp, "fmt ", 4)) break; //success
  149. if (!memcmp(temp, "data", 4)) break; //already got data chunk but no fmt
  150. if (r->read(&tmp, 4, p_abort) != 4) break;
  151. if (tmp & 1) tmp++;
  152. if (tmp == 0 || r->get_position(p_abort) + tmp > filesize - 8) break;
  153. r->seek(tmp + r->get_position(p_abort), p_abort);
  154. }
  155. if (memcmp(temp, "fmt ", 4)) break;
  156. __int64 position = r->get_position(p_abort) - 4;
  157. if (r->read(&tmp, 4, p_abort) != 4) break;
  158. if (tmp < 14 || tmp > 64 * 1024) break;
  159. r->seek(tmp + r->get_position(p_abort), p_abort);
  160. char code[4];
  161. do {
  162. position += 8 + tmp + (tmp & 1); //word-align all blocksizes
  163. r->seek(position, p_abort);
  164. if (r->read(code, 4, p_abort) != 4) break;
  165. if (r->read(temp, 4, p_abort) != 4) break;
  166. } while (memcmp(code, "data", 4));
  167. if (memcmp(code, "data", 4)) break;
  168. position += 8;
  169. r->seek(position, p_abort);
  170. return position - pos;
  171. }
  172. r->seek(pos, p_abort);
  173. return 0;
  174. }
  175. public:
  176. input_dts()
  177. {
  178. data = 0;
  179. }
  180. ~input_dts()
  181. {
  182. abort_callback_dummy temp;
  183. if (data) free_ffmpeg(data, temp);
  184. }
  185. bool decode_can_seek() { return r->can_seek(); }
  186. bool decode_get_dynamic_info(file_info &p_out, double &p_timestamp_delta) {
  187. if (dynamic_decoded_this_interval >= dynamic_interval) {
  188. dynamic_decoded_this_interval %= dynamic_interval;
  189. unsigned int bps = dynamic_bitrate_total / dynamic_bitrate_count;
  190. p_out.info_set_int("bitrate", (bps + 500) / 1000);
  191. p_timestamp_delta = -((double)dynamic_last_decoded / (double)srate);
  192. return true;
  193. }
  194. return false;
  195. }
  196. bool decode_get_dynamic_info_track(file_info &p_out, double &p_timestamp_delta) { return false; }
  197. void decode_on_idle(abort_callback &p_abort) { r->on_idle(p_abort); }
  198. static bool g_is_our_content_type(const char *p_content_type)
  199. {
  200. return (!strcmp(p_content_type, "audio/x-dts")) || (!strcmp(p_content_type, "audio/dts"));
  201. }
  202. static bool g_is_our_path(const char *p_path, const char *p_extension)
  203. {
  204. return (stricmp_utf8(p_extension, "dts") == 0) || (stricmp_utf8(p_extension, "dtswav") == 0) ||
  205. (stricmp_utf8(p_extension, "dtshd") == 0) || (stricmp_utf8(p_extension, "dtsma") == 0);
  206. }
  207. t_filestats get_file_stats(abort_callback &p_abort) { return r->get_stats(p_abort); }
  208. void open(service_ptr_t<file> p_filehint, const char *p_path, t_input_open_reason p_reason, abort_callback &p_abort)
  209. {
  210. if (p_reason==input_open_info_write && g_cfg_tag.get_static_instance().get_state()==false) throw exception_io_unsupported_format();
  211. r = p_filehint;
  212. input_open_file_helper(r, p_path, p_reason, p_abort);
  213. tag_offset = 0;
  214. try {
  215. file_info_impl t;
  216. tag_processor::read_trailing_ex(r, t, tag_offset, p_abort);
  217. } catch(exception_io_data) { /*file had no trailing tags */ }
  218. if (tag_offset == 0) tag_offset = r->get_size(p_abort);
  219. header_pos = 0;
  220. tag_processor::skip_id3v2(r, header_pos, p_abort);
  221. __int64 t = skip_wav_header(r, p_abort);
  222. if (t > 0) iswav = true; else iswav = false;
  223. header_pos += t;
  224. this->r = r;
  225. data = init_ffmpeg_offset(r, header_pos, tag_offset - header_pos, p_abort);
  226. if (!data) {
  227. throw exception_io_data("Failed to initialize DTS decoder");
  228. }
  229. nch = srate = 0;
  230. skip_samples = 0;
  231. silence_bytes = 0;
  232. #ifdef DTS_DEBUG
  233. skipped_bytes = 0;
  234. decoded_bytes = 0;
  235. #endif
  236. eof = false;
  237. channel_mask = 0;
  238. delay_samples = data->skipSamples;
  239. frame_size = data->frameSize ? data->frameSize : 512;
  240. nch = data->channels;
  241. srate = data->sampleRate;
  242. bps = data->bitsPerSample;
  243. if (!srate || !nch) {
  244. free_ffmpeg(data, p_abort);
  245. data = 0;
  246. throw exception_io_data();
  247. }
  248. this->channel_mask = audio_chunk::g_guess_channel_config(nch);
  249. }
  250. void get_info(file_info &p_info, abort_callback &p_abort)
  251. {
  252. t_filesize current_pos = r->get_position(p_abort);
  253. t_filesize next_pos;
  254. __int64 offset;
  255. //t_filesize tag_offset = r->get_size(p_abort);
  256. try {
  257. //tag_processor::read_id3v2(r, p_info, p_abort);
  258. tag_processor::read_id3v2_trailing(r, p_info, p_abort);
  259. } catch(exception_io_data) { /*file had no tags */ }
  260. r->seek(current_pos, p_abort);
  261. info_set_dts_info(p_info, data);
  262. }
  263. void decode_initialize(unsigned p_flags, abort_callback &p_abort)
  264. {
  265. reset_ffmpeg(data, p_abort);
  266. dynamic_interval = srate / 4;
  267. dynamic_last_decoded = 0;
  268. dynamic_decoded_this_interval = 0;
  269. dynamic_blocks_per_interval = 0;
  270. }
  271. bool decode_run(audio_chunk &chunk, abort_callback &p_abort)
  272. {
  273. if (data->endOfAudio || data->endOfStream) return false;
  274. bool ret;
  275. do
  276. {
  277. ret = decode_ffmpeg(data, chunk, p_abort);
  278. if (ret) {
  279. dynamic_last_decoded = chunk.get_sample_count();
  280. dynamic_decoded_this_interval += dynamic_last_decoded;
  281. if (!dynamic_blocks_per_interval) {
  282. dynamic_blocks_per_interval = (dynamic_interval + (dynamic_last_decoded - 1)) / dynamic_last_decoded;
  283. dynamic_bitrates.set_count(dynamic_blocks_per_interval);
  284. dynamic_bitrates.fill_null();
  285. dynamic_current_bitrate = 0;
  286. dynamic_bitrate_total = 0;
  287. dynamic_bitrate_count = 0;
  288. }
  289. dynamic_bitrate_total -= dynamic_bitrates[dynamic_current_bitrate];
  290. dynamic_bitrates[dynamic_current_bitrate] = data->bitrate;
  291. dynamic_bitrate_total += data->bitrate;
  292. dynamic_current_bitrate = (dynamic_current_bitrate + 1) % dynamic_blocks_per_interval;
  293. if (dynamic_bitrate_count < dynamic_blocks_per_interval)
  294. ++dynamic_bitrate_count;
  295. if (data->samplesToDiscard > 0) {
  296. int last_decoded = chunk.get_sample_count();
  297. if (data->samplesToDiscard >= last_decoded) {
  298. data->samplesToDiscard -= last_decoded;
  299. continue;
  300. }
  301. else {
  302. last_decoded -= data->samplesToDiscard;
  303. memmove(chunk.get_data(), chunk.get_data() + data->samplesToDiscard * data->channels, last_decoded * data->channels * sizeof(audio_sample));
  304. chunk.set_sample_count(last_decoded);
  305. data->samplesToDiscard = 0;
  306. }
  307. }
  308. }
  309. } while (ret && data->samplesToDiscard > 0);
  310. return ret;
  311. }
  312. void decode_seek(double newpos, abort_callback &p_abort)
  313. {
  314. r->ensure_seekable(); //throw exceptions if someone called decode_seek() despite of our input having reported itself as nonseekable.
  315. seek_ffmpeg(data, newpos, p_abort);
  316. }
  317. void retag(const file_info &p_info, abort_callback &p_abort)
  318. {
  319. if (g_cfg_tag.get_static_instance().get_state() == false) throw exception_tagging_unsupported(); // exit out when tags are not wanted
  320. r->ensure_seekable();
  321. const char *tagtype = p_info.info_get("tagtype");
  322. if (tagtype == 0) tagtype = "";
  323. bool id3v1=false, id3v2=false, apev2=false;
  324. parse_tagtype_internal(tagtype, id3v1, id3v2, apev2);
  325. if (!id3v2 && !apev2) apev2 = true;
  326. tag_processor::write_multi(r, p_info, p_abort, id3v1, id3v2, apev2);
  327. tag_offset = 0;
  328. try {
  329. file_info_impl t;
  330. tag_processor::read_trailing_ex(r, t, tag_offset, p_abort);
  331. }
  332. catch (exception_io_data) { /*file had no trailing tags */ }
  333. if (tag_offset == 0) tag_offset = r->get_size(p_abort);
  334. header_pos = 0;
  335. tag_processor::skip_id3v2(r, header_pos, p_abort);
  336. __int64 t = skip_wav_header(r, p_abort);
  337. if (t > 0) iswav = true; else iswav = false;
  338. header_pos += t;
  339. if (data) {
  340. data->start = header_pos;
  341. // assume data->size doesn't need adjusting, stream should still be the same
  342. data->offset = data->logical_offset + data->start;
  343. }
  344. }
  345. void remove_tags(abort_callback & p_abort)
  346. {
  347. if (g_cfg_tag.get_static_instance().get_state() == false) throw exception_tagging_unsupported();
  348. tag_processor::remove_id3v2(r, p_abort);
  349. tag_processor::remove_trailing(r, p_abort);
  350. tag_offset = 0;
  351. header_pos = 0;
  352. __int64 t = skip_wav_header(r, p_abort);
  353. if (t > 0) iswav = true; else iswav = false;
  354. header_pos += t;
  355. if (data) {
  356. data->start = header_pos;
  357. // assume data->size doesn't need adjusting, stream should still be the same
  358. data->offset = data->logical_offset + data->start;
  359. }
  360. }
  361. static GUID g_get_guid()
  362. {
  363. static const GUID guid = { 0xe20f55a1, 0xb219, 0x486e,{ 0xba, 0xd3, 0x8b, 0xaa, 0xec, 0xf4, 0x2e, 0x56 } };
  364. return guid;
  365. }
  366. static const char * g_get_name()
  367. {
  368. return "DTS decoder";
  369. }
  370. };
  371. static input_cuesheet_factory_t<input_dts> g_input_dts_factory;
  372. #include "../patrons.h"
  373. class version_dts : public componentversion
  374. {
  375. public:
  376. virtual void get_file_name(pfc::string_base & out) { out = core_api::get_my_file_name(); }
  377. virtual void get_component_name(pfc::string_base & out) { out = "DTS decoder"; }
  378. virtual void get_component_version(pfc::string_base & out) { out = FD_VERSION; }
  379. virtual void get_about_message(pfc::string_base & out)
  380. {
  381. out = "DTS decoding powered by FFmpeg.\n";
  382. out += "\n";
  383. out += "Using FFmpeg version: ";
  384. out += av_version_info();
  385. out += "\n";
  386. out += "\n";
  387. out += u8"foobar2000 component by Janne Hyvärinen and Christopher Snowhill.\n";
  388. out += "Licensed under GNU GPL.\n\n";
  389. out += "https://www.patreon.com/kode54\n\n";
  390. out += MY_PATRONS;
  391. }
  392. };
  393. static service_factory_single_t<version_dts> g_componentversion_dts_factory;
  394. DECLARE_FILE_TYPE("DTS files", "*.DTS;*.DTSWAV;*.DTSHD;*.DTSMA");
  395. VALIDATE_COMPONENT_FILENAME("foo_input_dts.dll");