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.

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