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)).
|
advancing ([#3841](https://github.com/google/ExoPlayer/issues/3841)).
|
||||||
* Add an option to skip silent audio in `PlaybackParameters`
|
* Add an option to skip silent audio in `PlaybackParameters`
|
||||||
((#2635)[https://github.com/google/ExoPlayer/issues/2635]).
|
((#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:
|
* Caching:
|
||||||
* Add release method to Cache interface.
|
* Add release method to Cache interface.
|
||||||
* Prevent multiple instances of SimpleCache in the same folder.
|
* 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.
|
* 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.
|
* 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]);
|
: 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
|
* Returns the number of audio samples represented by the given TrueHD syncframe, or 0 if the
|
||||||
* buffer is not the start of a syncframe.
|
* buffer is not the start of a syncframe.
|
||||||
@ -481,25 +501,22 @@ public final class Ac3Util {
|
|||||||
|| (syncframe[7] & 0xFE) != 0xBA) {
|
|| (syncframe[7] & 0xFE) != 0xBA) {
|
||||||
return 0;
|
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
|
* Reads the number of audio samples represented by a TrueHD syncframe. The buffer's position is
|
||||||
* is not the start of a syncframe. The buffer's position is not modified.
|
* not modified.
|
||||||
*
|
*
|
||||||
* @param buffer The {@link ByteBuffer} from which to read the syncframe. Must have at least
|
* @param buffer The {@link ByteBuffer} from which to read the syncframe.
|
||||||
* {@link #TRUEHD_SYNCFRAME_PREFIX_LENGTH} bytes remaining.
|
* @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, or 0 if the buffer is not the
|
* @return The number of audio samples represented by the syncframe.
|
||||||
* start of a syncframe.
|
|
||||||
*/
|
*/
|
||||||
public static int parseTrueHdSyncframeAudioSampleCount(ByteBuffer buffer) {
|
public static int parseTrueHdSyncframeAudioSampleCount(ByteBuffer buffer, int offset) {
|
||||||
// TODO: Link to specification if available.
|
// TODO: Link to specification if available.
|
||||||
// The syncword ends 0xBA for TrueHD or 0xBB for MLP.
|
boolean isMlp = (buffer.get(buffer.position() + offset + 7) & 0xFF) == 0xBB;
|
||||||
if ((buffer.getInt(buffer.position() + 4) & 0xFEFFFFFF) != 0xBA6F72F8) {
|
return 40 << ((buffer.get(buffer.position() + offset + (isMlp ? 9 : 8)) >> 4) & 0x07);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 40 << (buffer.get(buffer.position() + 8) & 0x07);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getAc3SyncframeSize(int fscod, int frmsizecod) {
|
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) {
|
} else if (encoding == C.ENCODING_E_AC3) {
|
||||||
return Ac3Util.parseEAc3SyncframeAudioSampleCount(buffer);
|
return Ac3Util.parseEAc3SyncframeAudioSampleCount(buffer);
|
||||||
} else if (encoding == C.ENCODING_DOLBY_TRUEHD) {
|
} else if (encoding == C.ENCODING_DOLBY_TRUEHD) {
|
||||||
return Ac3Util.parseTrueHdSyncframeAudioSampleCount(buffer)
|
int syncframeOffset = Ac3Util.findTrueHdSyncframeOffset(buffer);
|
||||||
* Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT;
|
return syncframeOffset == C.INDEX_UNSET
|
||||||
|
? 0
|
||||||
|
: (Ac3Util.parseTrueHdSyncframeAudioSampleCount(buffer, syncframeOffset)
|
||||||
|
* Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unexpected audio encoding: " + encoding);
|
throw new IllegalStateException("Unexpected audio encoding: " + encoding);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user