Fix parsing of language code in mdhd box

Language codes in the `mdhd` box are stored as three 5-bit values, each representing a letter ('a' to 'z') using an offset of `0x60`. If the decoded characters are not in this range, the language should be treated as undefined.

PiperOrigin-RevId: 738470544
(cherry picked from commit 2a4cbc3be47b54a59aef384b288ea802e34fb2f0)
This commit is contained in:
rohks 2025-03-19 11:15:19 -07:00 committed by tonihei
parent 963bae9dd8
commit d920cf87a6
19 changed files with 39 additions and 34 deletions

View File

@ -169,12 +169,15 @@ public final class Ac3Util {
*
* @param data The AC3SpecificBox to parse.
* @param trackId The track identifier to set on the format.
* @param language The language to set on the format.
* @param language The language to set on the format, or {@code null} if unset.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The AC-3 format parsed from data in the header.
*/
public static Format parseAc3AnnexFFormat(
ParsableByteArray data, String trackId, String language, @Nullable DrmInitData drmInitData) {
ParsableByteArray data,
String trackId,
@Nullable String language,
@Nullable DrmInitData drmInitData) {
ParsableBitArray dataBitArray = new ParsableBitArray();
dataBitArray.reset(data);
@ -208,12 +211,15 @@ public final class Ac3Util {
*
* @param data The EC3SpecificBox to parse.
* @param trackId The track identifier to set on the format.
* @param language The language to set on the format.
* @param language The language to set on the format, or {@code null} if unset.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The E-AC-3 format parsed from data in the header.
*/
public static Format parseEAc3AnnexFFormat(
ParsableByteArray data, String trackId, String language, @Nullable DrmInitData drmInitData) {
ParsableByteArray data,
String trackId,
@Nullable String language,
@Nullable DrmInitData drmInitData) {
ParsableBitArray dataBitArray = new ParsableBitArray();
dataBitArray.reset(data);

View File

@ -163,14 +163,17 @@ public final class Ac4Util {
*
* @param data The AC4SpecificBox to parse.
* @param trackId The track identifier to set on the format.
* @param language The language to set on the format.
* @param language The language to set on the format, or {@code null} if unset.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The AC-4 format parsed from data in the header.
* @throws ParserException If an unsupported container feature is encountered while parsing AC-4
* Annex E.
*/
public static Format parseAc4AnnexEFormat(
ParsableByteArray data, String trackId, String language, @Nullable DrmInitData drmInitData)
ParsableByteArray data,
String trackId,
@Nullable String language,
@Nullable DrmInitData drmInitData)
throws ParserException {
ParsableBitArray dataBitArray = new ParsableBitArray();
dataBitArray.reset(data);

View File

@ -997,22 +997,34 @@ public final class BoxParser {
mediaDurationUs = Util.scaleLargeTimestamp(mediaDuration, C.MICROS_PER_SECOND, timescale);
}
}
int languageCode = mdhd.readUnsignedShort();
String language =
""
+ (char) (((languageCode >> 10) & 0x1F) + 0x60)
+ (char) (((languageCode >> 5) & 0x1F) + 0x60)
+ (char) ((languageCode & 0x1F) + 0x60);
String language = getLanguageFromCode(/* languageCode= */ mdhd.readUnsignedShort());
return new MdhdData(timescale, mediaDurationUs, language);
}
@Nullable
private static String getLanguageFromCode(int languageCode) {
char[] chars = {
(char) (((languageCode >> 10) & 0x1F) + 0x60),
(char) (((languageCode >> 5) & 0x1F) + 0x60),
(char) ((languageCode & 0x1F) + 0x60)
};
for (char c : chars) {
if (c < 'a' || c > 'z') {
return null;
}
}
return new String(chars);
}
/**
* Parses a stsd atom (defined in ISO/IEC 14496-12).
*
* @param stsd The stsd atom to decode.
* @param trackId The track's identifier in its container.
* @param rotationDegrees The rotation of the track in degrees.
* @param language The language of the track.
* @param language The language of the track, or {@code null} if unset.
* @param drmInitData {@link DrmInitData} to be included in the format, or {@code null}.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return An object containing the parsed data.
@ -1021,7 +1033,7 @@ public final class BoxParser {
ParsableByteArray stsd,
int trackId,
int rotationDegrees,
String language,
@Nullable String language,
@Nullable DrmInitData drmInitData,
boolean isQuickTime)
throws ParserException {
@ -1125,7 +1137,7 @@ public final class BoxParser {
int position,
int atomSize,
int trackId,
String language,
@Nullable String language,
StsdData out) {
parent.setPosition(position + Mp4Box.HEADER_SIZE + StsdData.STSD_HEADER_SIZE);
@ -1820,7 +1832,7 @@ public final class BoxParser {
int position,
int size,
int trackId,
String language,
@Nullable String language,
boolean isQuickTime,
@Nullable DrmInitData drmInitData,
StsdData out,
@ -2593,9 +2605,9 @@ public final class BoxParser {
private static final class MdhdData {
private final long timescale;
private final long mediaDurationUs;
private final String language;
@Nullable private final String language;
public MdhdData(long timescale, long mediaDurationUs, String language) {
public MdhdData(long timescale, long mediaDurationUs, @Nullable String language) {
this.timescale = timescale;
this.mediaDurationUs = mediaDurationUs;
this.language = language;

View File

@ -12,7 +12,6 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 16000
language = 
initializationData:
data = length 19, hash 4034F23B
data = length 8, hash 94446F01

View File

@ -12,7 +12,6 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 16000
language = 
initializationData:
data = length 19, hash 4034F23B
data = length 8, hash 94446F01

View File

@ -12,7 +12,6 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 16000
language = 
initializationData:
data = length 19, hash 4034F23B
data = length 8, hash 94446F01

View File

@ -12,7 +12,6 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 16000
language = 
initializationData:
data = length 19, hash 4034F23B
data = length 8, hash 94446F01

View File

@ -18,7 +18,6 @@ track 0:
maxInputSize = 295
channelCount = 1
sampleRate = 16000
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
initializationData:
data = length 30, hash C22462B1

View File

@ -18,7 +18,6 @@ track 0:
channelCount = 2
sampleRate = 44100
pcmEncoding = 2
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
sample 0:
time = 0

View File

@ -17,7 +17,6 @@ track 0:
maxInputSize = 1185
channelCount = 6
sampleRate = 48000
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
initializationData:
data = length 27, hash 9EE6F879

View File

@ -42,7 +42,6 @@ track 1:
maxInputSize = 627
channelCount = 2
sampleRate = 48000
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
initializationData:
data = length 2, hash 560

View File

@ -552,7 +552,6 @@ track 1:
maxInputSize = 877
channelCount = 2
sampleRate = 48000
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
initializationData:
data = length 2, hash 560

View File

@ -543,7 +543,6 @@ track 1:
codecs = mp4a.40.2
channelCount = 2
sampleRate = 48000
language = ```
initializationData:
data = length 2, hash 560
sample 0:

View File

@ -416,7 +416,6 @@ track 1:
maxInputSize = 877
channelCount = 2
sampleRate = 48000
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
initializationData:
data = length 2, hash 560

View File

@ -552,7 +552,6 @@ track 1:
maxInputSize = 877
channelCount = 2
sampleRate = 48000
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
initializationData:
data = length 2, hash 560

View File

@ -552,7 +552,6 @@ track 1:
maxInputSize = 877
channelCount = 2
sampleRate = 48000
language = ```
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
initializationData:
data = length 2, hash 560

View File

@ -18,7 +18,6 @@ track 0:
maxInputSize = 295
channelCount = 1
sampleRate = 16000
language = ```
metadata = entries=[Mp4Timestamp: creation time=3000000000, modification time=4000000000, timescale=10000]
initializationData:
data = length 30, hash C22462B1

View File

@ -17,7 +17,6 @@ track 0:
maxInputSize = 1185
channelCount = 6
sampleRate = 48000
language = ```
metadata = entries=[Mp4Timestamp: creation time=3000000000, modification time=4000000000, timescale=10000]
initializationData:
data = length 27, hash 9EE6F879

View File

@ -57,7 +57,6 @@ track 1:
maxInputSize = 627
channelCount = 2
sampleRate = 48000
language = ```
metadata = entries=[xyz: latitude=51.5932, longitude=-0.2431, Mp4Timestamp: creation time=3000000000, modification time=4000000000, timescale=10000]
initializationData:
data = length 2, hash 560