mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Search for TrueHD syncframes
In MatroskaExtractor TrueHD audio samples are joined into larger chunks. For some streams the resulting chunked samples seem never to start with a syncframe. This could result in playback of TrueHD streams getting stuck after seeking because we could never read a syncframe at the start of a sample to determine the sample size. Instead of expecting to find a syncframe at the start of a sample, search for it within the sample, to fix this issue. Note: this means that we may search a few thousand bytes to find the sample size, but the cost is only incurred for the first audio sample read. Issue: #3845 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=191775779
This commit is contained in:
parent
1b84544264
commit
280cc545dd
@ -36,6 +36,9 @@
|
||||
advancing ([#3841](https://github.com/google/ExoPlayer/issues/3841)).
|
||||
* Add an option to skip silent audio in `PlaybackParameters`
|
||||
((#2635)[https://github.com/google/ExoPlayer/issues/2635]).
|
||||
* Fix an issue where playback of TrueHD streams would get stuck after seeking
|
||||
due to not finding a syncframe
|
||||
((#3845)[https://github.com/google/ExoPlayer/issues/3845]).
|
||||
* Caching:
|
||||
* Add release method to Cache interface.
|
||||
* Prevent multiple instances of SimpleCache in the same folder.
|
||||
|
@ -99,7 +99,7 @@ public final class Ac3Util {
|
||||
/**
|
||||
* The number of bytes that must be parsed from a TrueHD syncframe to calculate the sample count.
|
||||
*/
|
||||
public static final int TRUEHD_SYNCFRAME_PREFIX_LENGTH = 12;
|
||||
public static final int TRUEHD_SYNCFRAME_PREFIX_LENGTH = 10;
|
||||
|
||||
/**
|
||||
* The number of new samples per (E-)AC-3 audio block.
|
||||
@ -463,6 +463,26 @@ public final class Ac3Util {
|
||||
: BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD[(buffer.get(buffer.position() + 4) & 0x30) >> 4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset relative to the buffer's position of the start of a TrueHD syncframe, or
|
||||
* {@link C#INDEX_UNSET} if no syncframe was found. The buffer's position is not modified.
|
||||
*
|
||||
* @param buffer The {@link ByteBuffer} within which to find a syncframe.
|
||||
* @return The offset relative to the buffer's position of the start of a TrueHD syncframe, or
|
||||
* {@link C#INDEX_UNSET} if no syncframe was found.
|
||||
*/
|
||||
public static int findTrueHdSyncframeOffset(ByteBuffer buffer) {
|
||||
int startIndex = buffer.position();
|
||||
int endIndex = buffer.limit() - TRUEHD_SYNCFRAME_PREFIX_LENGTH;
|
||||
for (int i = startIndex; i <= endIndex; i++) {
|
||||
// The syncword ends 0xBA for TrueHD or 0xBB for MLP.
|
||||
if ((buffer.getInt(i + 4) & 0xFEFFFFFF) == 0xBA6F72F8) {
|
||||
return i - startIndex;
|
||||
}
|
||||
}
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of audio samples represented by the given TrueHD syncframe, or 0 if the
|
||||
* buffer is not the start of a syncframe.
|
||||
@ -481,25 +501,22 @@ public final class Ac3Util {
|
||||
|| (syncframe[7] & 0xFE) != 0xBA) {
|
||||
return 0;
|
||||
}
|
||||
return 40 << (syncframe[8] & 7);
|
||||
boolean isMlp = (syncframe[7] & 0xFF) == 0xBB;
|
||||
return 40 << ((syncframe[isMlp ? 9 : 8] >> 4) & 0x07);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the number of audio samples represented by the given TrueHD syncframe, or 0 if the buffer
|
||||
* is not the start of a syncframe. The buffer's position is not modified.
|
||||
* Reads the number of audio samples represented by a TrueHD syncframe. The buffer's position is
|
||||
* not modified.
|
||||
*
|
||||
* @param buffer The {@link ByteBuffer} from which to read the syncframe. Must have at least
|
||||
* {@link #TRUEHD_SYNCFRAME_PREFIX_LENGTH} bytes remaining.
|
||||
* @return The number of audio samples represented by the syncframe, or 0 if the buffer is not the
|
||||
* start of a syncframe.
|
||||
* @param buffer The {@link ByteBuffer} from which to read the syncframe.
|
||||
* @param offset The offset of the start of the syncframe relative to the buffer's position.
|
||||
* @return The number of audio samples represented by the syncframe.
|
||||
*/
|
||||
public static int parseTrueHdSyncframeAudioSampleCount(ByteBuffer buffer) {
|
||||
public static int parseTrueHdSyncframeAudioSampleCount(ByteBuffer buffer, int offset) {
|
||||
// TODO: Link to specification if available.
|
||||
// The syncword ends 0xBA for TrueHD or 0xBB for MLP.
|
||||
if ((buffer.getInt(buffer.position() + 4) & 0xFEFFFFFF) != 0xBA6F72F8) {
|
||||
return 0;
|
||||
}
|
||||
return 40 << (buffer.get(buffer.position() + 8) & 0x07);
|
||||
boolean isMlp = (buffer.get(buffer.position() + offset + 7) & 0xFF) == 0xBB;
|
||||
return 40 << ((buffer.get(buffer.position() + offset + (isMlp ? 9 : 8)) >> 4) & 0x07);
|
||||
}
|
||||
|
||||
private static int getAc3SyncframeSize(int fscod, int frmsizecod) {
|
||||
|
@ -1076,8 +1076,11 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
} else if (encoding == C.ENCODING_E_AC3) {
|
||||
return Ac3Util.parseEAc3SyncframeAudioSampleCount(buffer);
|
||||
} else if (encoding == C.ENCODING_DOLBY_TRUEHD) {
|
||||
return Ac3Util.parseTrueHdSyncframeAudioSampleCount(buffer)
|
||||
* Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT;
|
||||
int syncframeOffset = Ac3Util.findTrueHdSyncframeOffset(buffer);
|
||||
return syncframeOffset == C.INDEX_UNSET
|
||||
? 0
|
||||
: (Ac3Util.parseTrueHdSyncframeAudioSampleCount(buffer, syncframeOffset)
|
||||
* Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT);
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected audio encoding: " + encoding);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user