Skip to content

Commit

Permalink
Fix handling of E-AC-3 streams with AC-3 frames
Browse files Browse the repository at this point in the history
Issue: #6602
PiperOrigin-RevId: 287816831
  • Loading branch information
andrewlewis authored and ojw28 committed Jan 2, 2020
1 parent 77f01da commit cafffcb
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 39 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
([#6733](https://github.com/google/ExoPlayer/issues/6733)). Incorrect handling
could previously cause downloads to be paused when they should have been able
to proceed.
* Fix handling of E-AC-3 streams that contain AC-3 syncframes
([#6602](https://github.com/google/ExoPlayer/issues/6602)).

### 2.11.1 (2019-12-20) ###

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@

/**
* Utility methods for parsing Dolby TrueHD and (E-)AC-3 syncframes. (E-)AC-3 parsing follows the
* definition in ETSI TS 102 366 V1.2.1.
* definition in ETSI TS 102 366 V1.4.1.
*/
public final class Ac3Util {

/** Holds sample format information as presented by a syncframe header. */
public static final class SyncFrameInfo {

/**
* AC3 stream types. See also ETSI TS 102 366 E.1.3.1.1. One of {@link #STREAM_TYPE_UNDEFINED},
* {@link #STREAM_TYPE_TYPE0}, {@link #STREAM_TYPE_TYPE1} or {@link #STREAM_TYPE_TYPE2}.
* AC3 stream types. See also E.1.3.1.1. One of {@link #STREAM_TYPE_UNDEFINED}, {@link
* #STREAM_TYPE_TYPE0}, {@link #STREAM_TYPE_TYPE1} or {@link #STREAM_TYPE_TYPE2}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
Expand Down Expand Up @@ -114,9 +114,7 @@ private SyncFrameInfo(
* The number of new samples per (E-)AC-3 audio block.
*/
private static final int AUDIO_SAMPLES_PER_AUDIO_BLOCK = 256;
/**
* Each syncframe has 6 blocks that provide 256 new audio samples. See ETSI TS 102 366 4.1.
*/
/** Each syncframe has 6 blocks that provide 256 new audio samples. See subsection 4.1. */
private static final int AC3_SYNCFRAME_AUDIO_SAMPLE_COUNT = 6 * AUDIO_SAMPLES_PER_AUDIO_BLOCK;
/**
* Number of audio blocks per E-AC-3 syncframe, indexed by numblkscod.
Expand All @@ -134,20 +132,21 @@ private SyncFrameInfo(
* Channel counts, indexed by acmod.
*/
private static final int[] CHANNEL_COUNT_BY_ACMOD = new int[] {2, 1, 2, 3, 3, 4, 4, 5};
/**
* Nominal bitrates in kbps, indexed by frmsizecod / 2. (See ETSI TS 102 366 table 4.13.)
*/
private static final int[] BITRATE_BY_HALF_FRMSIZECOD = new int[] {32, 40, 48, 56, 64, 80, 96,
112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640};
/**
* 16-bit words per syncframe, indexed by frmsizecod / 2. (See ETSI TS 102 366 table 4.13.)
*/
private static final int[] SYNCFRAME_SIZE_WORDS_BY_HALF_FRMSIZECOD_44_1 = new int[] {69, 87, 104,
121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114, 1253, 1393};
/** Nominal bitrates in kbps, indexed by frmsizecod / 2. (See table 4.13.) */
private static final int[] BITRATE_BY_HALF_FRMSIZECOD =
new int[] {
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640
};
/** 16-bit words per syncframe, indexed by frmsizecod / 2. (See table 4.13.) */
private static final int[] SYNCFRAME_SIZE_WORDS_BY_HALF_FRMSIZECOD_44_1 =
new int[] {
69, 87, 104, 121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114, 1253,
1393
};

/**
* Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to ETSI TS
* 102 366 Annex F. The reading position of {@code data} will be modified.
* Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to Annex F.
* The reading position of {@code data} will be modified.
*
* @param data The AC3SpecificBox to parse.
* @param trackId The track identifier to set on the format.
Expand Down Expand Up @@ -179,8 +178,8 @@ public static Format parseAc3AnnexFFormat(
}

/**
* Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to ETSI TS
* 102 366 Annex F. The reading position of {@code data} will be modified.
* Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to Annex
* F. The reading position of {@code data} will be modified.
*
* @param data The EC3SpecificBox to parse.
* @param trackId The track identifier to set on the format.
Expand Down Expand Up @@ -243,9 +242,10 @@ public static Format parseEAc3AnnexFFormat(
public static SyncFrameInfo parseAc3SyncframeInfo(ParsableBitArray data) {
int initialPosition = data.getPosition();
data.skipBits(40);
boolean isEac3 = data.readBits(5) == 16; // See bsid in subsection E.1.3.1.6.
// Parse the bitstream ID for AC-3 and E-AC-3 (see subsections 4.3, E.1.2 and E.1.3.1.6).
boolean isEac3 = data.readBits(5) > 10;
data.setPosition(initialPosition);
String mimeType;
@Nullable String mimeType;
@StreamType int streamType = SyncFrameInfo.STREAM_TYPE_UNDEFINED;
int sampleRate;
int acmod;
Expand All @@ -254,7 +254,7 @@ public static SyncFrameInfo parseAc3SyncframeInfo(ParsableBitArray data) {
boolean lfeon;
int channelCount;
if (isEac3) {
// Syntax from ETSI TS 102 366 V1.2.1 subsections E.1.2.1 and E.1.2.2.
// Subsection E.1.2.
data.skipBits(16); // syncword
switch (data.readBits(2)) { // strmtyp
case 0:
Expand Down Expand Up @@ -472,7 +472,8 @@ public static int parseAc3SyncframeSize(byte[] data) {
if (data.length < 6) {
return C.LENGTH_UNSET;
}
boolean isEac3 = ((data[5] & 0xFF) >> 3) == 16; // See bsid in subsection E.1.3.1.6.
// Parse the bitstream ID for AC-3 and E-AC-3 (see subsections 4.3, E.1.2 and E.1.3.1.6).
boolean isEac3 = ((data[5] & 0xF8) >> 3) > 10;
if (isEac3) {
int frmsiz = (data[2] & 0x07) << 8; // Most significant 3 bits.
frmsiz |= data[3] & 0xFF; // Least significant 8 bits.
Expand All @@ -485,24 +486,22 @@ public static int parseAc3SyncframeSize(byte[] data) {
}

/**
* Returns the number of audio samples in an AC-3 syncframe.
*/
public static int getAc3SyncframeAudioSampleCount() {
return AC3_SYNCFRAME_AUDIO_SAMPLE_COUNT;
}

/**
* Reads the number of audio samples represented by the given E-AC-3 syncframe. The buffer's
* Reads the number of audio samples represented by the given (E-)AC-3 syncframe. The buffer's
* position is not modified.
*
* @param buffer The {@link ByteBuffer} from which to read the syncframe.
* @return The number of audio samples represented by the syncframe.
*/
public static int parseEAc3SyncframeAudioSampleCount(ByteBuffer buffer) {
// See ETSI TS 102 366 subsection E.1.2.2.
int fscod = (buffer.get(buffer.position() + 4) & 0xC0) >> 6;
return AUDIO_SAMPLES_PER_AUDIO_BLOCK * (fscod == 0x03 ? 6
: BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD[(buffer.get(buffer.position() + 4) & 0x30) >> 4]);
public static int parseAc3SyncframeAudioSampleCount(ByteBuffer buffer) {
// Parse the bitstream ID for AC-3 and E-AC-3 (see subsections 4.3, E.1.2 and E.1.3.1.6).
boolean isEac3 = ((buffer.get(buffer.position() + 5) & 0xF8) >> 3) > 10;
if (isEac3) {
int fscod = (buffer.get(buffer.position() + 4) & 0xC0) >> 6;
int numblkscod = fscod == 0x03 ? 3 : (buffer.get(buffer.position() + 4) & 0x30) >> 4;
return BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD[numblkscod] * AUDIO_SAMPLES_PER_AUDIO_BLOCK;
} else {
return AC3_SYNCFRAME_AUDIO_SAMPLE_COUNT;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1166,10 +1166,9 @@ private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffe
case C.ENCODING_DTS_HD:
return DtsUtil.parseDtsAudioSampleCount(buffer);
case C.ENCODING_AC3:
return Ac3Util.getAc3SyncframeAudioSampleCount();
case C.ENCODING_E_AC3:
case C.ENCODING_E_AC3_JOC:
return Ac3Util.parseEAc3SyncframeAudioSampleCount(buffer);
return Ac3Util.parseAc3SyncframeAudioSampleCount(buffer);
case C.ENCODING_AC4:
return Ac4Util.parseAc4SyncframeAudioSampleCount(buffer);
case C.ENCODING_DOLBY_TRUEHD:
Expand Down

0 comments on commit cafffcb

Please sign in to comment.