Skip to content

Commit 6a1649d

Browse files
committed
Changes based on internal review
1 parent 2c3eac4 commit 6a1649d

File tree

2 files changed

+78
-62
lines changed

2 files changed

+78
-62
lines changed

libraries/extractor/src/main/java/androidx/media3/extractor/ts/AdtsReader.java

+63-61
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ private void setReadingAacPceState(
301301
this.currentOutput = outputToUse;
302302
this.currentSampleDuration = currentSampleDuration;
303303
this.sampleSize = sampleSize;
304-
pceBuffer = new ParsableBitArray(new byte[min(sampleSize, AAC_PCE_MAX_SIZE)]);
304+
this.pceBuffer = new ParsableBitArray(new byte[min(sampleSize, AAC_PCE_MAX_SIZE)]);
305305
}
306306

307307
/**
@@ -574,85 +574,87 @@ private void parseAdtsHeader() throws ParserException {
574574
}
575575

576576
@RequiresNonNull("currentOutput")
577-
void readAacProgramConfigElement() {
578-
Format pendingOutputFormat = checkNotNull(this.pendingOutputFormat);
577+
private void readAacProgramConfigElement() throws ParserException {
579578
ParsableBitArray pceBuffer = checkNotNull(this.pceBuffer);
580579

581580
// See ISO 13818-7 Advanced Audio Coding (2006) Table 36 for PCE tag encoding.
582-
if (pceBuffer.readBits(3) == 5 /* PCE tag */) {
583-
// See ISO 13818-7 Advanced Audio Coding (2006) Table 25 for syntax of a PCE.
584-
pceBuffer.skipBits(10); // element_instance_tag(4), profile(2), element_instance_tag(4)
585-
586-
int channelBits = 0;
587-
// num_front_channel_elements, front_element_is_cpe(1), front_element_tag_select(4)
588-
channelBits += pceBuffer.readBits(4) * 5;
589-
// num_side_channel_elements, side_element_is_cpe(1), side_element_tag_select(4)
590-
channelBits += pceBuffer.readBits(4) * 5;
591-
// num_back_channel_elements, back_element_is_cpe(1), back_element_tag_select(4)
592-
channelBits += pceBuffer.readBits(4) * 5;
593-
// num_lfe_channel_elements, lfe_element_tag_select(4)
594-
channelBits += pceBuffer.readBits(2) * 4;
595-
// num_assoc_data_elements, assoc_data_element_tag_select(4)
596-
channelBits += pceBuffer.readBits(3) * 4;
597-
// num_valid_cc_elements, cc_element_is_ind_sw(1), valid_cc_element_tag_select(4)
598-
channelBits += pceBuffer.readBits(4) * 5;
599-
600-
if (pceBuffer.readBit()) { // mono_mixdown_present
601-
pceBuffer.skipBits(4); // mono_mixdown_element_number
602-
}
581+
if (pceBuffer.readBits(3) != 5 /* PCE tag */) {
582+
throw ParserException.createForMalformedContainer(/* message= */ null, /* cause= */ null);
583+
}
603584

604-
if (pceBuffer.readBit()) { // stereo_mixdown_present
605-
pceBuffer.skipBits(4); // stereo_mixdown_element_number
606-
}
585+
// See ISO 13818-7 Advanced Audio Coding (2006) Table 25 for syntax of a PCE.
586+
pceBuffer.skipBits(10); // element_instance_tag(4), profile(2), element_instance_tag(4)
587+
588+
int channelBits = 0;
589+
// num_front_channel_elements, front_element_is_cpe(1), front_element_tag_select(4)
590+
channelBits += pceBuffer.readBits(4) * 5;
591+
// num_side_channel_elements, side_element_is_cpe(1), side_element_tag_select(4)
592+
channelBits += pceBuffer.readBits(4) * 5;
593+
// num_back_channel_elements, back_element_is_cpe(1), back_element_tag_select(4)
594+
channelBits += pceBuffer.readBits(4) * 5;
595+
// num_lfe_channel_elements, lfe_element_tag_select(4)
596+
channelBits += pceBuffer.readBits(2) * 4;
597+
// num_assoc_data_elements, assoc_data_element_tag_select(4)
598+
channelBits += pceBuffer.readBits(3) * 4;
599+
// num_valid_cc_elements, cc_element_is_ind_sw(1), valid_cc_element_tag_select(4)
600+
channelBits += pceBuffer.readBits(4) * 5;
601+
602+
if (pceBuffer.readBit()) { // mono_mixdown_present
603+
pceBuffer.skipBits(4); // mono_mixdown_element_number
604+
}
607605

608-
if (pceBuffer.readBit()) { // matrix_mixdown_idx_present
609-
pceBuffer.skipBits(3); // matrix_mixdown_idx(2), matrix_mixdown_idx(1)
610-
}
606+
if (pceBuffer.readBit()) { // stereo_mixdown_present
607+
pceBuffer.skipBits(4); // stereo_mixdown_element_number
608+
}
609+
610+
if (pceBuffer.readBit()) { // matrix_mixdown_idx_present
611+
pceBuffer.skipBits(3); // matrix_mixdown_idx(2), matrix_mixdown_idx(1)
612+
}
613+
614+
int numAlignmentBits =
615+
8 - (pceBuffer.getPosition() + channelBits + 7) % 8 - 1; // byte_alignment
616+
int commentSizeBits = 8; // comment_field_bytes
611617

612-
int numAlignmentBits =
613-
8 - (pceBuffer.getPosition() + channelBits + 7) % 8 - 1; // byte_alignment
614-
int commentSizeBits = 8; // comment_field_bytes
618+
// Beyond this point, pceBuffer may be empty, so check before consuming.
619+
if (pceBuffer.bitsLeft() < channelBits + numAlignmentBits + commentSizeBits) {
620+
throw ParserException.createForMalformedContainer(/* message= */ null, /* cause= */ null);
621+
}
615622

616-
// Beyond this point, pceBuffer may be empty, so check before consuming.
617-
if (pceBuffer.bitsLeft() >= channelBits + numAlignmentBits + commentSizeBits) {
618-
pceBuffer.skipBits(channelBits);
623+
pceBuffer.skipBits(channelBits);
619624

620-
// Store PCE size excluding initial PCE tag, alignment bits and comment for later.
621-
int numPceBits = pceBuffer.getPosition() - 3 /* PCE tag */;
625+
// Store PCE size excluding initial PCE tag, alignment bits and comment for later.
626+
int numPceBits = pceBuffer.getPosition() - 3 /* PCE tag */;
622627

623-
pceBuffer.skipBits(numAlignmentBits);
624-
int commentSize = pceBuffer.readBits(commentSizeBits);
628+
pceBuffer.skipBits(numAlignmentBits);
629+
int commentSize = pceBuffer.readBits(commentSizeBits);
625630

626-
if (sampleSize >= pceBuffer.getBytePosition() + commentSize) {
627-
// Append PCE to format's audio specific config.
628-
byte[] oldConfig = pendingOutputFormat.initializationData.get(0);
631+
if (sampleSize < pceBuffer.getBytePosition() + commentSize) {
632+
throw ParserException.createForMalformedContainer(/* message= */ null, /* cause= */ null);
633+
}
629634

630-
int configSize = oldConfig.length;
631-
configSize += (numPceBits + 7) / 8 + 1; // Byte align and add a zero length comment.
632-
byte[] newConfig = Arrays.copyOf(oldConfig, configSize);
635+
Format pendingOutputFormat = checkNotNull(this.pendingOutputFormat);
636+
// Append PCE to format's audio specific config.
637+
byte[] oldConfig = pendingOutputFormat.initializationData.get(0);
633638

634-
pceBuffer.setPosition(3 /* PCE tag */);
635-
pceBuffer.readBits(newConfig, oldConfig.length, numPceBits);
639+
int configSize = oldConfig.length;
640+
configSize += (numPceBits + 7) / 8 + 1; // Byte align and add a zero length comment.
641+
byte[] newConfig = Arrays.copyOf(oldConfig, configSize);
636642

637-
pendingOutputFormat =
638-
pendingOutputFormat
639-
.buildUpon()
640-
.setInitializationData(ImmutableList.of(newConfig))
641-
.build();
643+
pceBuffer.setPosition(3 /* PCE tag */);
644+
pceBuffer.readBits(newConfig, oldConfig.length, numPceBits);
642645

643-
// Submit PCE-appended output format.
644-
currentOutput.format(pendingOutputFormat);
645-
hasOutputFormat = true;
646-
}
647-
}
648-
}
646+
pendingOutputFormat =
647+
pendingOutputFormat.buildUpon().setInitializationData(ImmutableList.of(newConfig)).build();
648+
649+
// Submit PCE-appended output format.
650+
this.currentOutput.format(pendingOutputFormat);
651+
this.hasOutputFormat = true;
652+
this.pendingOutputFormat = null;
649653

650654
// Pass through all accumulated data as sample data.
651655
ParsableByteArray data = new ParsableByteArray(pceBuffer.data);
652656
setReadingSampleState(currentOutput, currentSampleDuration, 0, sampleSize);
653657
readSample(data);
654-
655-
this.pendingOutputFormat = null;
656658
this.pceBuffer = null;
657659
}
658660

libraries/extractor/src/test/java/androidx/media3/extractor/ts/AdtsReaderTest.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,20 @@ public void aacPceData() throws ParserException {
209209
adtsOutput.assertSample(0, AAC_PCE_ADTS_CONTENT, 0, C.BUFFER_FLAG_KEY_FRAME, null);
210210
}
211211

212+
@Test
213+
public void aacPceDataSplit() throws ParserException {
214+
byte[] first = Arrays.copyOf(AAC_PCE_TEST_DATA, AAC_PCE_ADTS_HEADER.length + 1);
215+
byte[] second = Arrays.copyOfRange(AAC_PCE_TEST_DATA, AAC_PCE_ADTS_HEADER.length + 1, AAC_PCE_TEST_DATA.length);
216+
217+
data = new ParsableByteArray(first);
218+
feed();
219+
data = new ParsableByteArray(second);
220+
feed();
221+
222+
assertSampleCounts(0, 1);
223+
adtsOutput.assertSample(0, AAC_PCE_ADTS_CONTENT, 0, C.BUFFER_FLAG_KEY_FRAME, null);
224+
}
225+
212226
@Test
213227
public void aacPceDataFail() throws ParserException {
214228
data = new ParsableByteArray(Arrays.copyOf(AAC_PCE_TEST_DATA, AAC_PCE_TEST_DATA.length));
@@ -219,7 +233,7 @@ public void aacPceDataFail() throws ParserException {
219233
bytes[AAC_PCE_ADTS_HEADER.length] |= 0x20;
220234

221235
// Should throw as FakeTrackOutput expects a format before sampleMetadata.
222-
assertThrows(IllegalStateException.class, this::feed);
236+
assertThrows(ParserException.class, this::feed);
223237
}
224238

225239
private void feedLimited(int limit) throws ParserException {

0 commit comments

Comments
 (0)