2 * Copyright (C) 2010-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "AEStreamInfo.h"
11 #include "utils/log.h"
16 #define DTS_PREAMBLE_14BE 0x1FFFE800
17 #define DTS_PREAMBLE_14LE 0xFF1F00E8
18 #define DTS_PREAMBLE_16BE 0x7FFE8001
19 #define DTS_PREAMBLE_16LE 0xFE7F0180
20 #define DTS_PREAMBLE_HD 0x64582025
21 #define DTS_PREAMBLE_XCH 0x5a5a5a5a
22 #define DTS_PREAMBLE_XXCH 0x47004a03
23 #define DTS_PREAMBLE_X96K 0x1d95f262
24 #define DTS_PREAMBLE_XBR 0x655e315e
25 #define DTS_PREAMBLE_LBR 0x0a801921
26 #define DTS_PREAMBLE_XLL 0x41a29547
27 #define DTS_SFREQ_COUNT 16
28 #define MAX_EAC3_BLOCKS 6
29 #define UNKNOWN_DTS_EXTENSION 255
31 static const uint16_t AC3Bitrates
[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160,
32 192, 224, 256, 320, 384, 448, 512, 576, 640};
33 static const uint16_t AC3FSCod
[] = {48000, 44100, 32000, 0};
34 static const uint8_t AC3BlkCod
[] = {1, 2, 3, 6};
35 static const uint8_t AC3Channels
[] = {2, 1, 2, 3, 3, 4, 4, 5};
36 static const uint8_t DTSChannels
[] = {1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8};
37 static const uint8_t THDChanMap
[] = {2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1};
39 static const uint32_t DTSSampleRates
[DTS_SFREQ_COUNT
] = {0, 8000, 16000, 32000, 64000, 128000,
40 11025, 22050, 44100, 88200, 176400, 12000,
41 24000, 48000, 96000, 192000};
43 CAEStreamParser::CAEStreamParser() : m_syncFunc(&CAEStreamParser::DetectType
)
45 av_crc_init(m_crcTrueHD
, 0, 16, 0x2D, sizeof(m_crcTrueHD
));
48 double CAEStreamInfo::GetDuration() const
56 case STREAM_TYPE_EAC3
:
57 duration
= 6144.0 / m_sampleRate
/ 4;
59 case STREAM_TYPE_TRUEHD
:
61 if (m_sampleRate
== 48000 || m_sampleRate
== 96000 || m_sampleRate
== 192000)
65 duration
= 3840.0 / rate
;
67 case STREAM_TYPE_DTS_512
:
68 case STREAM_TYPE_DTSHD_CORE
:
69 case STREAM_TYPE_DTSHD
:
70 case STREAM_TYPE_DTSHD_MA
:
71 duration
= 512.0 / m_sampleRate
;
73 case STREAM_TYPE_DTS_1024
:
74 duration
= 1024.0 / m_sampleRate
;
76 case STREAM_TYPE_DTS_2048
:
77 duration
= 2048.0 / m_sampleRate
;
80 CLog::Log(LOGERROR
, "CAEStreamInfo::GetDuration - invalid stream type");
83 return duration
* 1000;
86 bool CAEStreamInfo::operator==(const CAEStreamInfo
& info
) const
88 if (m_type
!= info
.m_type
)
90 if (m_dataIsLE
!= info
.m_dataIsLE
)
92 if (m_repeat
!= info
.m_repeat
)
97 void CAEStreamParser::Reset()
105 int CAEStreamParser::AddData(uint8_t* data
,
108 unsigned int* bufferSize
)
119 unsigned int canSkip
= std::min(size
, m_skipBytes
);
120 unsigned int room
= sizeof(m_buffer
) - m_bufferSize
;
121 unsigned int copy
= std::min(room
, canSkip
);
123 memcpy(m_buffer
+ m_bufferSize
, data
, copy
);
124 m_bufferSize
+= copy
;
134 GetPacket(buffer
, bufferSize
);
139 unsigned int consumed
= 0;
140 unsigned int offset
= 0;
141 unsigned int room
= sizeof(m_buffer
) - m_bufferSize
;
151 unsigned int copy
= std::min(room
, size
);
152 memcpy(m_buffer
+ m_bufferSize
, data
, copy
);
153 m_bufferSize
+= copy
;
159 if (m_needBytes
> m_bufferSize
)
163 offset
= (this->*m_syncFunc
)(m_buffer
, m_bufferSize
);
170 m_syncFunc
= &CAEStreamParser::DetectType
;
171 m_info
.m_type
= CAEStreamInfo::STREAM_TYPE_NULL
;
174 // if the buffer is full, or the offset < the buffer size
175 if (m_bufferSize
== sizeof(m_buffer
) || offset
< m_bufferSize
)
177 m_bufferSize
-= offset
;
179 memmove(m_buffer
, m_buffer
+ offset
, m_bufferSize
);
184 // if we got here, we acquired sync on the buffer
189 m_bufferSize
-= offset
;
190 memmove(m_buffer
, m_buffer
+ offset
, m_bufferSize
);
193 // bytes to skip until the next packet
194 m_skipBytes
= std::max(0, (int)m_fsize
- (int)m_bufferSize
);
203 GetPacket(buffer
, bufferSize
);
211 void CAEStreamParser::GetPacket(uint8_t** buffer
, unsigned int* bufferSize
)
213 // if the caller wants the packet
216 // if it is dtsHD and we only want the core, just fetch that
217 unsigned int size
= m_fsize
;
218 if (m_info
.m_type
== CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
)
221 // make sure the buffer is allocated and big enough
222 if (!*buffer
|| !bufferSize
|| *bufferSize
< size
)
225 *buffer
= new uint8_t[size
];
228 // copy the data into the buffer and update the size
229 memcpy(*buffer
, m_buffer
, size
);
234 // remove the parsed data from the buffer
235 m_bufferSize
-= m_fsize
;
236 memmove(m_buffer
, m_buffer
+ m_fsize
, m_bufferSize
);
243 // This function looks for sync words across the types in parallel, and only does an exhaustive
244 // test if it finds a syncword. Once sync has been established, the relevant sync function sets
245 // m_syncFunc to itself. This function will only be called again if total sync is lost, which
246 // allows is to switch stream types on the fly much like a real receiver does.
247 unsigned int CAEStreamParser::DetectType(uint8_t* data
, unsigned int size
)
249 unsigned int skipped
= 0;
250 unsigned int possible
= 0;
254 // if it could be DTS
255 unsigned int header
= data
[0] << 24 | data
[1] << 16 | data
[2] << 8 | data
[3];
256 if (header
== DTS_PREAMBLE_14LE
|| header
== DTS_PREAMBLE_14BE
|| header
== DTS_PREAMBLE_16LE
||
257 header
== DTS_PREAMBLE_16BE
)
259 unsigned int skip
= SyncDTS(data
, size
);
260 if (m_hasSync
|| m_needBytes
)
261 return skipped
+ skip
;
266 // if it could be AC3
267 if (data
[0] == 0x0b && data
[1] == 0x77)
269 unsigned int skip
= SyncAC3(data
, size
);
270 if (m_hasSync
|| m_needBytes
)
271 return skipped
+ skip
;
276 // if it could be TrueHD
277 if (data
[4] == 0xf8 && data
[5] == 0x72 && data
[6] == 0x6f && data
[7] == 0xba)
279 unsigned int skip
= SyncTrueHD(data
, size
);
281 return skipped
+ skip
;
286 // move along one byte
292 return possible
? possible
: skipped
;
295 bool CAEStreamParser::TrySyncAC3(uint8_t* data
,
298 bool wantEAC3dependent
)
303 // look for an ac3 sync word
304 if (data
[0] != 0x0b || data
[1] != 0x77)
307 uint8_t bsid
= data
[5] >> 3;
308 uint8_t acmod
= data
[6] >> 5;
312 if ((acmod
& 0x1) && (acmod
!= 0x1))
319 lfeon
= (data
[7] & 0x64) ? 1 : 0;
321 lfeon
= ((data
[6] >> pos
) & 0x1) ? 1 : 0;
323 if (bsid
> 0x11 || acmod
> 7)
330 if (wantEAC3dependent
)
333 uint8_t fscod
= data
[4] >> 6;
334 uint8_t frmsizecod
= data
[4] & 0x3F;
335 if (fscod
== 3 || frmsizecod
> 37)
338 // get the details we need to check crc1 and framesize
339 unsigned int bitRate
= AC3Bitrates
[frmsizecod
>> 1];
340 unsigned int framesize
= 0;
344 framesize
= bitRate
* 2;
347 framesize
= (320 * bitRate
/ 147 + (frmsizecod
& 1 ? 1 : 0));
350 framesize
= bitRate
* 4;
354 m_fsize
= framesize
<< 1;
355 m_info
.m_sampleRate
= AC3FSCod
[fscod
];
357 // dont do extensive testing if we have not lost sync
358 if (m_info
.m_type
== CAEStreamInfo::STREAM_TYPE_AC3
&& !resyncing
)
361 // this may be the main stream of EAC3
362 unsigned int fsizeMain
= m_fsize
;
363 unsigned int reqBytes
= fsizeMain
+ 8;
366 // not enough data to check for E-AC3 dependent frame, request more
367 m_needBytes
= reqBytes
;
369 // no need to resync => return true
372 m_info
.m_frameSize
= fsizeMain
;
373 if (TrySyncAC3(data
+ fsizeMain
, size
- fsizeMain
, resyncing
, true))
375 // concatenate the main and dependent frames
376 m_fsize
+= fsizeMain
;
380 unsigned int crc_size
;
381 // if we have enough data, validate the entire packet, else try to validate crc2 (5/8 of the packet)
382 if (framesize
<= size
)
383 crc_size
= framesize
- 1;
385 crc_size
= (framesize
>> 1) + (framesize
>> 3) - 1;
387 if (crc_size
<= size
)
388 if (av_crc(av_crc_get_table(AV_CRC_16_ANSI
), 0, &data
[2], crc_size
* 2))
391 // if we get here, we can sync
393 m_info
.m_channels
= AC3Channels
[acmod
] + lfeon
;
394 m_syncFunc
= &CAEStreamParser::SyncAC3
;
395 m_info
.m_type
= CAEStreamInfo::STREAM_TYPE_AC3
;
396 m_info
.m_frameSize
+= m_fsize
;
399 CLog::Log(LOGINFO
, "CAEStreamParser::TrySyncAC3 - AC3 stream detected ({} channels, {}Hz)",
400 m_info
.m_channels
, m_info
.m_sampleRate
);
406 uint8_t strmtyp
= data
[2] >> 6;
410 if (strmtyp
!= 1 && wantEAC3dependent
)
413 unsigned int framesize
= (((data
[2] & 0x7) << 8) | data
[3]) + 1;
414 uint8_t fscod
= (data
[4] >> 6) & 0x3;
415 uint8_t cod
= (data
[4] >> 4) & 0x3;
416 uint8_t acmod
= (data
[4] >> 1) & 0x7;
417 uint8_t lfeon
= data
[4] & 0x1;
426 m_info
.m_sampleRate
= AC3FSCod
[cod
] >> 1;
430 blocks
= AC3BlkCod
[cod
];
431 m_info
.m_sampleRate
= AC3FSCod
[fscod
];
434 m_fsize
= framesize
<< 1;
435 m_info
.m_repeat
= MAX_EAC3_BLOCKS
/ blocks
;
437 // EAC3 can have a dependent stream too
438 if (!wantEAC3dependent
)
440 unsigned int fsizeMain
= m_fsize
;
441 unsigned int reqBytes
= fsizeMain
+ 8;
444 // not enough data to check for E-AC3 dependent frame, request more
445 m_needBytes
= reqBytes
;
447 // no need to resync => return true
450 m_info
.m_frameSize
= fsizeMain
;
451 if (TrySyncAC3(data
+ fsizeMain
, size
- fsizeMain
, resyncing
, true))
453 // concatenate the main and dependent frames
454 m_fsize
+= fsizeMain
;
459 if (m_info
.m_type
== CAEStreamInfo::STREAM_TYPE_EAC3
&& m_hasSync
&& !resyncing
)
462 // if we get here, we can sync
464 m_info
.m_channels
= AC3Channels
[acmod
] + lfeon
;
465 m_syncFunc
= &CAEStreamParser::SyncAC3
;
466 m_info
.m_type
= CAEStreamInfo::STREAM_TYPE_EAC3
;
467 m_info
.m_frameSize
+= m_fsize
;
469 CLog::Log(LOGINFO
, "CAEStreamParser::TrySyncAC3 - E-AC3 stream detected ({} channels, {}Hz)",
470 m_info
.m_channels
, m_info
.m_sampleRate
);
475 unsigned int CAEStreamParser::SyncAC3(uint8_t* data
, unsigned int size
)
477 unsigned int skip
= 0;
479 for (; size
- skip
> 7; ++skip
, ++data
)
481 bool resyncing
= (skip
!= 0);
482 if (TrySyncAC3(data
, size
- skip
, resyncing
, false))
486 // if we get here, the entire packet is invalid and we have lost sync
487 CLog::Log(LOGINFO
, "CAEStreamParser::SyncAC3 - AC3 sync lost");
492 unsigned int CAEStreamParser::SyncDTS(uint8_t* data
, unsigned int size
)
496 if (m_needBytes
< 13)
501 unsigned int skip
= 0;
502 for (; size
- skip
> 13; ++skip
, ++data
)
504 unsigned int header
= data
[0] << 24 | data
[1] << 16 | data
[2] << 8 | data
[3];
505 unsigned int hd_sync
= 0;
506 unsigned int dtsBlocks
;
509 unsigned int target_rate
;
510 unsigned int extension
= 0;
511 unsigned int ext_type
= UNKNOWN_DTS_EXTENSION
;
518 case DTS_PREAMBLE_14BE
:
519 if (data
[4] != 0x07 || (data
[5] & 0xf0) != 0xf0)
521 dtsBlocks
= (((data
[5] & 0x7) << 4) | ((data
[6] & 0x3C) >> 2)) + 1;
522 m_fsize
= (((((data
[6] & 0x3) << 8) | data
[7]) << 4) | ((data
[8] & 0x3C) >> 2)) + 1;
523 amode
= ((data
[8] & 0x3) << 4) | ((data
[9] & 0xF0) >> 4);
524 target_rate
= ((data
[10] & 0x3e) >> 1);
525 extension
= ((data
[11] & 0x1));
526 ext_type
= ((data
[11] & 0xe) >> 1);
527 sfreq
= data
[9] & 0xF;
528 lfe
= (data
[12] & 0x18) >> 3;
529 m_info
.m_dataIsLE
= false;
534 case DTS_PREAMBLE_14LE
:
535 if (data
[5] != 0x07 || (data
[4] & 0xf0) != 0xf0)
537 dtsBlocks
= (((data
[4] & 0x7) << 4) | ((data
[7] & 0x3C) >> 2)) + 1;
538 m_fsize
= (((((data
[7] & 0x3) << 8) | data
[6]) << 4) | ((data
[9] & 0x3C) >> 2)) + 1;
539 amode
= ((data
[9] & 0x3) << 4) | ((data
[8] & 0xF0) >> 4);
540 target_rate
= ((data
[11] & 0x3e) >> 1);
541 extension
= ((data
[10] & 0x1));
542 ext_type
= ((data
[10] & 0xe) >> 1);
543 sfreq
= data
[8] & 0xF;
544 lfe
= (data
[13] & 0x18) >> 3;
545 m_info
.m_dataIsLE
= true;
550 case DTS_PREAMBLE_16BE
:
551 dtsBlocks
= (((data
[4] & 0x1) << 7) | ((data
[5] & 0xFC) >> 2)) + 1;
552 m_fsize
= (((((data
[5] & 0x3) << 8) | data
[6]) << 4) | ((data
[7] & 0xF0) >> 4)) + 1;
553 amode
= ((data
[7] & 0x0F) << 2) | ((data
[8] & 0xC0) >> 6);
554 sfreq
= (data
[8] & 0x3C) >> 2;
555 target_rate
= ((data
[8] & 0x03) << 3) | ((data
[9] & 0xe0) >> 5);
556 extension
= (data
[10] & 0x10) >> 4;
557 ext_type
= (data
[10] & 0xe0) >> 5;
558 lfe
= (data
[10] >> 1) & 0x3;
559 m_info
.m_dataIsLE
= false;
564 case DTS_PREAMBLE_16LE
:
565 dtsBlocks
= (((data
[5] & 0x1) << 7) | ((data
[4] & 0xFC) >> 2)) + 1;
566 m_fsize
= (((((data
[4] & 0x3) << 8) | data
[7]) << 4) | ((data
[6] & 0xF0) >> 4)) + 1;
567 amode
= ((data
[6] & 0x0F) << 2) | ((data
[9] & 0xC0) >> 6);
568 sfreq
= (data
[9] & 0x3C) >> 2;
569 target_rate
= ((data
[9] & 0x03) << 3) | ((data
[8] & 0xe0) >> 5);
570 extension
= (data
[11] & 0x10) >> 4;
571 ext_type
= (data
[11] & 0xe0) >> 5;
572 lfe
= (data
[11] >> 1) & 0x3;
573 m_info
.m_dataIsLE
= true;
581 if (sfreq
== 0 || sfreq
>= DTS_SFREQ_COUNT
)
584 // make sure the framesize is sane
585 if (m_fsize
< 96 || m_fsize
> 16384)
588 CAEStreamInfo::DataType dataType
{CAEStreamInfo::STREAM_TYPE_NULL
};
589 switch (dtsBlocks
<< 5)
592 dataType
= CAEStreamInfo::STREAM_TYPE_DTS_512
;
595 dataType
= CAEStreamInfo::STREAM_TYPE_DTS_1024
;
598 dataType
= CAEStreamInfo::STREAM_TYPE_DTS_2048
;
602 if (dataType
== CAEStreamInfo::STREAM_TYPE_NULL
)
605 // adjust the fsize for 14 bit streams
607 m_fsize
= m_fsize
/ 14 * 16;
609 // we need enough data to check for DTS-HD
610 if (size
- skip
< m_fsize
+ 10)
612 // we can assume DTS sync at this point
613 m_syncFunc
= &CAEStreamParser::SyncDTS
;
614 m_needBytes
= m_fsize
+ 10;
621 hd_sync
= (data
[m_fsize
] << 24) | (data
[m_fsize
+ 1] << 16) | (data
[m_fsize
+ 2] << 8) |
623 if (hd_sync
== DTS_PREAMBLE_HD
)
626 bool blownup
= (data
[m_fsize
+ 5] & 0x20) != 0;
628 hd_size
= (((data
[m_fsize
+ 6] & 0x01) << 19) | (data
[m_fsize
+ 7] << 11) |
629 (data
[m_fsize
+ 8] << 3) | ((data
[m_fsize
+ 9] & 0xe0) >> 5)) +
632 hd_size
= (((data
[m_fsize
+ 6] & 0x1f) << 11) | (data
[m_fsize
+ 7] << 3) |
633 ((data
[m_fsize
+ 8] & 0xe0) >> 5)) +
638 header_size
= (((data
[m_fsize
+ 5] & 0x1f) << 7) | ((data
[m_fsize
+ 6] & 0xfe) >> 1)) + 1;
640 header_size
= (((data
[m_fsize
+ 5] & 0x1f) << 3) | ((data
[m_fsize
+ 6] & 0xe0) >> 5)) + 1;
642 hd_sync
= data
[m_fsize
+ header_size
] << 24 | data
[m_fsize
+ header_size
+ 1] << 16 |
643 data
[m_fsize
+ header_size
+ 2] << 8 | data
[m_fsize
+ header_size
+ 3];
645 // set the type according to core or not
647 dataType
= CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
;
648 else if (hd_sync
== DTS_PREAMBLE_XLL
)
649 dataType
= CAEStreamInfo::STREAM_TYPE_DTSHD_MA
;
650 else if (hd_sync
== DTS_PREAMBLE_XCH
|| hd_sync
== DTS_PREAMBLE_XXCH
||
651 hd_sync
== DTS_PREAMBLE_X96K
|| hd_sync
== DTS_PREAMBLE_XBR
||
652 hd_sync
== DTS_PREAMBLE_LBR
)
653 dataType
= CAEStreamInfo::STREAM_TYPE_DTSHD
;
655 dataType
= m_info
.m_type
;
657 m_coreSize
= m_fsize
;
661 unsigned int sampleRate
= DTSSampleRates
[sfreq
];
662 if (!m_hasSync
|| skip
|| dataType
!= m_info
.m_type
|| sampleRate
!= m_info
.m_sampleRate
||
663 dtsBlocks
!= m_dtsBlocks
)
666 m_info
.m_type
= dataType
;
667 m_info
.m_sampleRate
= sampleRate
;
668 m_dtsBlocks
= dtsBlocks
;
669 m_info
.m_channels
= DTSChannels
[amode
] + (lfe
? 1 : 0);
670 m_syncFunc
= &CAEStreamParser::SyncDTS
;
671 m_info
.m_frameSize
= m_fsize
;
674 if (dataType
== CAEStreamInfo::STREAM_TYPE_DTSHD_MA
)
676 m_info
.m_channels
+= 2; // FIXME: this needs to be read out, not sure how to do that yet
677 m_info
.m_dtsPeriod
= (192000 * (8 >> 1)) * (m_dtsBlocks
<< 5) / m_info
.m_sampleRate
;
679 else if (dataType
== CAEStreamInfo::STREAM_TYPE_DTSHD
)
681 m_info
.m_dtsPeriod
= (192000 * (2 >> 1)) * (m_dtsBlocks
<< 5) / m_info
.m_sampleRate
;
686 (m_info
.m_sampleRate
* (2 >> 1)) * (m_dtsBlocks
<< 5) / m_info
.m_sampleRate
;
692 case CAEStreamInfo::STREAM_TYPE_DTSHD
:
695 case CAEStreamInfo::STREAM_TYPE_DTSHD_MA
:
698 case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
:
699 type
= "dtsHD (core)";
720 type
+= " ext unknown";
726 "CAEStreamParser::SyncDTS - {} stream detected ({} channels, {}Hz, {}bit {}, "
727 "period: {}, syncword: 0x{:x}, target rate: 0x{:x}, framesize {}))",
728 type
, m_info
.m_channels
, m_info
.m_sampleRate
, bits
, m_info
.m_dataIsLE
? "LE" : "BE",
729 m_info
.m_dtsPeriod
, hd_sync
, target_rate
, m_fsize
);
736 CLog::Log(LOGINFO
, "CAEStreamParser::SyncDTS - DTS sync lost");
741 inline unsigned int CAEStreamParser::GetTrueHDChannels(const uint16_t chanmap
)
744 for (int i
= 0; i
< 13; ++i
)
745 channels
+= THDChanMap
[i
] * ((chanmap
>> i
) & 1);
749 unsigned int CAEStreamParser::SyncTrueHD(uint8_t* data
, unsigned int size
)
751 unsigned int left
= size
;
752 unsigned int skip
= 0;
755 for (; left
; ++skip
, ++data
, --left
)
757 // if we dont have sync and there is less the 8 bytes, then break out
758 if (!m_hasSync
&& left
< 8)
761 // if its a major audio unit
762 uint16_t length
= ((data
[0] & 0x0F) << 8 | data
[1]) << 1;
763 uint32_t syncword
= ((((data
[4] << 8 | data
[5]) << 8) | data
[6]) << 8) | data
[7];
764 if (syncword
== 0xf8726fba)
766 // we need 32 bytes to sync on a master audio unit
770 // get the rate and ensure its valid
771 int rate
= (data
[8] & 0xf0) >> 4;
775 unsigned int major_sync_size
= 28;
778 // extension(s) present, look up count
779 int extension_count
= data
[30] >> 4;
780 major_sync_size
+= 2 + extension_count
* 2;
783 if (left
< 4 + major_sync_size
)
786 // verify the crc of the audio unit
787 uint16_t crc
= av_crc(m_crcTrueHD
, 0, data
+ 4, major_sync_size
- 4);
788 crc
^= (data
[4 + major_sync_size
- 3] << 8) | data
[4 + major_sync_size
- 4];
789 if (((data
[4 + major_sync_size
- 1] << 8) | data
[4 + major_sync_size
- 2]) != crc
)
792 // get the sample rate and substreams, we have a valid master audio unit
793 m_info
.m_sampleRate
= (rate
& 0x8 ? 44100 : 48000) << (rate
& 0x7);
794 m_substreams
= (data
[20] & 0xF0) >> 4;
796 // get the number of encoded channels
797 uint16_t channel_map
= ((data
[10] & 0x1F) << 8) | data
[11];
799 channel_map
= (data
[9] << 1) | (data
[10] >> 7);
800 m_info
.m_channels
= CAEStreamParser::GetTrueHDChannels(channel_map
);
804 "CAEStreamParser::SyncTrueHD - TrueHD stream detected ({} channels, {}Hz)",
805 m_info
.m_channels
, m_info
.m_sampleRate
);
809 m_info
.m_type
= CAEStreamInfo::STREAM_TYPE_TRUEHD
;
810 m_syncFunc
= &CAEStreamParser::SyncTrueHD
;
811 m_info
.m_frameSize
= length
;
817 // we cant sink to a subframe until we have the information from a master audio unit
821 // if there is not enough data left to verify the packet, just return the skip amount
822 if (left
< (unsigned int)m_substreams
* 4)
828 for (int i
= -1; i
< m_substreams
; ++i
)
832 if (i
== -1 || data
[p
- 2] & 0x80)
839 // if the parity nibble does not match
840 if ((((check
>> 4) ^ check
) & 0xF) != 0xF)
844 CLog::Log(LOGINFO
, "CAEStreamParser::SyncTrueHD - Sync Lost");