1515 */
1616package androidx .media3 .common .util ;
1717
18+ import static androidx .media3 .common .util .Assertions .checkArgument ;
19+
1820import android .util .Pair ;
1921import androidx .annotation .Nullable ;
2022import androidx .media3 .common .C ;
@@ -31,6 +33,12 @@ public final class CodecSpecificDataUtil {
3133 private static final String [] HEVC_GENERAL_PROFILE_SPACE_STRINGS =
3234 new String [] {"" , "A" , "B" , "C" };
3335
36+ // MP4V-ES
37+ private static final int VISUAL_OBJECT_LAYER = 1 ;
38+ private static final int VISUAL_OBJECT_LAYER_START = 0x20 ;
39+ private static final int EXTENDED_PAR = 0x0F ;
40+ private static final int RECTANGULAR = 0x00 ;
41+
3442 /**
3543 * Parses an ALAC AudioSpecificConfig (i.e. an <a
3644 * href="https://github.com/macosforge/alac/blob/master/ALACMagicCookieDescription.txt">ALACSpecificConfig</a>).
@@ -72,6 +80,87 @@ public static boolean parseCea708InitializationData(List<byte[]> initializationD
7280 && initializationData .get (0 )[0 ] == 1 ;
7381 }
7482
83+ /**
84+ * Parses an MPEG-4 Visual configuration information, as defined in ISO/IEC14496-2.
85+ *
86+ * @param videoSpecificConfig A byte array containing the MPEG-4 Visual configuration information
87+ * to parse.
88+ * @return A pair of the video's width and height.
89+ */
90+ public static Pair <Integer , Integer > getVideoResolutionFromMpeg4VideoConfig (
91+ byte [] videoSpecificConfig ) {
92+ int offset = 0 ;
93+ boolean foundVOL = false ;
94+ ParsableByteArray scratchBytes = new ParsableByteArray (videoSpecificConfig );
95+ while (offset + 3 < videoSpecificConfig .length ) {
96+ if (scratchBytes .readUnsignedInt24 () != VISUAL_OBJECT_LAYER
97+ || (videoSpecificConfig [offset + 3 ] & 0xF0 ) != VISUAL_OBJECT_LAYER_START ) {
98+ scratchBytes .setPosition (scratchBytes .getPosition () - 2 );
99+ offset ++;
100+ continue ;
101+ }
102+ foundVOL = true ;
103+ break ;
104+ }
105+
106+ checkArgument (foundVOL , "Invalid input: VOL not found." );
107+
108+ ParsableBitArray scratchBits = new ParsableBitArray (videoSpecificConfig );
109+ // Skip the start codecs from the bitstream
110+ scratchBits .skipBits ((offset + 4 ) * 8 );
111+ scratchBits .skipBits (1 ); // random_accessible_vol
112+ scratchBits .skipBits (8 ); // video_object_type_indication
113+
114+ if (scratchBits .readBit ()) { // object_layer_identifier
115+ scratchBits .skipBits (4 ); // video_object_layer_verid
116+ scratchBits .skipBits (3 ); // video_object_layer_priority
117+ }
118+
119+ int aspectRatioInfo = scratchBits .readBits (4 );
120+ if (aspectRatioInfo == EXTENDED_PAR ) {
121+ scratchBits .skipBits (8 ); // par_width
122+ scratchBits .skipBits (8 ); // par_height
123+ }
124+
125+ if (scratchBits .readBit ()) { // vol_control_parameters
126+ scratchBits .skipBits (2 ); // chroma_format
127+ scratchBits .skipBits (1 ); // low_delay
128+ if (scratchBits .readBit ()) { // vbv_parameters
129+ scratchBits .skipBits (79 );
130+ }
131+ }
132+
133+ int videoObjectLayerShape = scratchBits .readBits (2 );
134+ checkArgument (
135+ videoObjectLayerShape == RECTANGULAR ,
136+ "Only supports rectangular video object layer shape." );
137+
138+ checkArgument (scratchBits .readBit ()); // marker_bit
139+ int vopTimeIncrementResolution = scratchBits .readBits (16 );
140+ checkArgument (scratchBits .readBit ()); // marker_bit
141+
142+ if (scratchBits .readBit ()) { // fixed_vop_rate
143+ checkArgument (vopTimeIncrementResolution > 0 );
144+ vopTimeIncrementResolution --;
145+ int numBitsToSkip = 0 ;
146+ while (vopTimeIncrementResolution > 0 ) {
147+ numBitsToSkip ++;
148+ vopTimeIncrementResolution >>= 1 ;
149+ }
150+ scratchBits .skipBits (numBitsToSkip ); // fixed_vop_time_increment
151+ }
152+
153+ checkArgument (scratchBits .readBit ()); // marker_bit
154+ int videoObjectLayerWidth = scratchBits .readBits (13 );
155+ checkArgument (scratchBits .readBit ()); // marker_bit
156+ int videoObjectLayerHeight = scratchBits .readBits (13 );
157+ checkArgument (scratchBits .readBit ()); // marker_bit
158+
159+ scratchBits .skipBits (1 ); // interlaced
160+
161+ return Pair .create (videoObjectLayerWidth , videoObjectLayerHeight );
162+ }
163+
75164 /**
76165 * Builds an RFC 6381 AVC codec string using the provided parameters.
77166 *
0 commit comments