|
39 | 39 | private static final int AUDIO_DECODER_ERROR_INVALID_DATA = -1; |
40 | 40 | private static final int AUDIO_DECODER_ERROR_OTHER = -2; |
41 | 41 |
|
| 42 | + // FLAC parsing constants |
| 43 | + private static final byte[] flacStreamMarker = {'f', 'L', 'a', 'C'}; |
| 44 | + private static final int FLAC_METADATA_TYPE_STREAM_INFO = 0; |
| 45 | + private static final int FLAC_METADATA_BLOCK_HEADER_SIZE = 4; |
| 46 | + private static final int FLAC_STREAM_INFO_DATA_SIZE = 34; |
| 47 | + |
42 | 48 | private final String codecName; |
43 | 49 | @Nullable private final byte[] extraData; |
44 | 50 | private final @C.PcmEncoding int encoding; |
@@ -198,49 +204,6 @@ private static byte[] getExtraData(String mimeType, List<byte[]> initializationD |
198 | 204 | } |
199 | 205 | } |
200 | 206 |
|
201 | | - @Nullable |
202 | | - private static byte[] getFlacExtraData(List<byte[]> initializationData) { |
203 | | - for (int i = 0; i < initializationData.size(); i++) { |
204 | | - byte[] out = extractFlacStreamInfo(initializationData.get(i)); |
205 | | - if (out != null) { |
206 | | - return out; |
207 | | - } |
208 | | - } |
209 | | - return null; |
210 | | - } |
211 | | - |
212 | | - @Nullable |
213 | | - private static byte[] extractFlacStreamInfo(byte[] data) { |
214 | | - final int STREAMINFO_LEN = 34; |
215 | | - int off = 0; |
216 | | - |
217 | | - if (data.length >= 4 |
218 | | - && data[0] == (byte) 'f' |
219 | | - && data[1] == (byte) 'L' |
220 | | - && data[2] == (byte) 'a' |
221 | | - && data[3] == (byte) 'C') { |
222 | | - off = 4; |
223 | | - } |
224 | | - |
225 | | - if (data.length - off == STREAMINFO_LEN) { |
226 | | - byte[] out = new byte[STREAMINFO_LEN]; |
227 | | - System.arraycopy(data, off, out, 0, STREAMINFO_LEN); |
228 | | - return out; |
229 | | - } |
230 | | - |
231 | | - if (data.length >= off + 4) { |
232 | | - int type = data[off] & 0x7F; |
233 | | - int len = ((data[off + 1] & 0xFF) << 16) | ((data[off + 2] & 0xFF) << 8) | (data[off + 3] & 0xFF); |
234 | | - if (type == 0 && len == STREAMINFO_LEN && data.length >= off + 4 + STREAMINFO_LEN) { |
235 | | - byte[] out = new byte[STREAMINFO_LEN]; |
236 | | - System.arraycopy(data, off + 4, out, 0, STREAMINFO_LEN); |
237 | | - return out; |
238 | | - } |
239 | | - } |
240 | | - |
241 | | - return null; |
242 | | - } |
243 | | - |
244 | 207 | private static byte[] getAlacExtraData(List<byte[]> initializationData) { |
245 | 208 | // FFmpeg's ALAC decoder expects an ALAC atom, which contains the ALAC "magic cookie", as extra |
246 | 209 | // data. initializationData[0] contains only the magic cookie, and so we need to package it into |
@@ -272,6 +235,71 @@ private static byte[] getVorbisExtraData(List<byte[]> initializationData) { |
272 | 235 | return extraData; |
273 | 236 | } |
274 | 237 |
|
| 238 | + @Nullable |
| 239 | + private static byte[] getFlacExtraData(List<byte[]> initializationData) { |
| 240 | + for (int i = 0; i < initializationData.size(); i++) { |
| 241 | + byte[] out = extractFlacStreamInfo(initializationData.get(i)); |
| 242 | + if (out != null) { |
| 243 | + return out; |
| 244 | + } |
| 245 | + } |
| 246 | + return null; |
| 247 | + } |
| 248 | + |
| 249 | + @Nullable |
| 250 | + private static byte[] extractFlacStreamInfo(byte[] data) { |
| 251 | + int offset = 0; |
| 252 | + if (arrayStartsWith(data, flacStreamMarker)) { |
| 253 | + offset = flacStreamMarker.length; |
| 254 | + } |
| 255 | + |
| 256 | + |
| 257 | + if (data.length - offset == FLAC_STREAM_INFO_DATA_SIZE) { |
| 258 | + byte[] streamInfo = new byte[FLAC_STREAM_INFO_DATA_SIZE]; |
| 259 | + System.arraycopy(data, offset, streamInfo, 0, FLAC_STREAM_INFO_DATA_SIZE); |
| 260 | + return streamInfo; |
| 261 | + } |
| 262 | + |
| 263 | + if (data.length >= offset + FLAC_METADATA_BLOCK_HEADER_SIZE) { |
| 264 | + int type = data[offset] & 0x7F; |
| 265 | + int length = |
| 266 | + ((data[offset + 1] & 0xFF) << 16) |
| 267 | + | ((data[offset + 2] & 0xFF) << 8) |
| 268 | + | (data[offset + 3] & 0xFF); |
| 269 | + |
| 270 | + if (type == FLAC_METADATA_TYPE_STREAM_INFO |
| 271 | + && length == FLAC_STREAM_INFO_DATA_SIZE |
| 272 | + && data.length |
| 273 | + >= offset |
| 274 | + + FLAC_METADATA_BLOCK_HEADER_SIZE |
| 275 | + + FLAC_STREAM_INFO_DATA_SIZE) { |
| 276 | + byte[] streamInfo = new byte[FLAC_STREAM_INFO_DATA_SIZE]; |
| 277 | + System.arraycopy( |
| 278 | + data, |
| 279 | + offset + FLAC_METADATA_BLOCK_HEADER_SIZE, |
| 280 | + streamInfo, |
| 281 | + 0, |
| 282 | + FLAC_STREAM_INFO_DATA_SIZE); |
| 283 | + return streamInfo; |
| 284 | + } |
| 285 | + } |
| 286 | + |
| 287 | + return null; |
| 288 | + } |
| 289 | + |
| 290 | + private static boolean arrayStartsWith(byte[] data, byte[] prefix) { |
| 291 | + if (data.length < prefix.length) { |
| 292 | + return false; |
| 293 | + } |
| 294 | + for (int i = 0; i < prefix.length; i++) { |
| 295 | + if (data[i] != prefix[i]) { |
| 296 | + return false; |
| 297 | + } |
| 298 | + } |
| 299 | + return true; |
| 300 | + } |
| 301 | + |
| 302 | + |
275 | 303 | private native long ffmpegInitialize( |
276 | 304 | String codecName, |
277 | 305 | @Nullable byte[] extraData, |
|
0 commit comments