List of usage examples for android.media MediaCodec CRYPTO_MODE_AES_CTR
int CRYPTO_MODE_AES_CTR
To view the source code for android.media MediaCodec CRYPTO_MODE_AES_CTR.
Click Source Link
From source file:com.sonymobile.android.media.internal.ISOBMFFParser.java
protected boolean parseBox(BoxHeader header) { if (header == null) { return false; }/* www . ja v a2 s . co m*/ mCurrentBoxSequence.add(header); if (LOGS_ENABLED) Log.v(TAG, "parse box " + ccruof(header.boxType) + " with size " + header.boxDataSize); boolean parseOK = true; long boxEndOffset = mCurrentOffset + header.boxDataSize; if (header.boxType == BOX_ID_FTYP) { } else if (header.boxType == BOX_ID_MOOV) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } // Merge tracks from moov and mfra if (mMfraTracks != null) { int numTracks = mTracks.size(); int numMfraTracks = mMfraTracks.size(); if (numMfraTracks > 0) { for (int i = 0; i < numTracks; i++) { IsoTrack track = (IsoTrack) mTracks.get(i); for (int j = 0; j < numMfraTracks; j++) { IsoTrack t = mMfraTracks.get(j); if (t.getTrackId() == track.getTrackId()) { track.setTfraList(t.getTfraList()); mMfraTracks.remove(j); break; } } } } mMfraTracks = null; } // Check for unsupported tracks int numTracks = mTracks.size(); if (LOGS_ENABLED) Log.v(TAG, numTracks + " tracks, " + "Video track " + getSelectedTrackIndex(TrackType.VIDEO) + " Audio track " + getSelectedTrackIndex(TrackType.AUDIO) + " Subtitle track " + getSelectedTrackIndex(TrackType.SUBTITLE)); for (int i = 0; i < numTracks; i++) { IsoTrack track = (IsoTrack) mTracks.get(i); if (track.getMediaFormat() == null) { if (LOGS_ENABLED) Log.v(TAG, "Track " + i + " is unhandled, type " + track.getTrackType()); track.setTrackType(TrackType.UNKNOWN); } else { if (LOGS_ENABLED) Log.v(TAG, "Track " + i + " of type " + track.getTrackType() + " is OK"); track.setTrackIndex(i); } } } else if (header.boxType == BOX_ID_MVHD) { parseOK = parseMvhd(header); } else if (header.boxType == BOX_ID_TRAK) { mIsParsingTrack = true; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } if (mParseODSMData) { if (!parseODSMData(mCurrentTrack)) { if (LOGS_ENABLED) Log.e(TAG, "Error while parsing ODSM track"); mCurrentBoxSequence.removeLast(); return false; } mParseODSMData = false; } mIsParsingTrack = false; } else if (header.boxType == BOX_ID_TKHD) { parseOK = readTkhd(header); } else if (header.boxType == BOX_ID_MDIA) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_MDHD) { parseOK = parseMdhd(header); } else if (header.boxType == BOX_ID_HDLR) { parseOK = parseHdlr(header); } else if (header.boxType == BOX_ID_MINF) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } if (parseOK) { if (mCurrentTrack.getTrackType() == TrackType.AUDIO && mCurrentAudioTrack == null) { if (LOGS_ENABLED) Log.v(TAG, "Setting audio track to " + mCurrentTrack.getTrackId()); mCurrentAudioTrack = mCurrentTrack; } else if (mCurrentTrack.getTrackType() == TrackType.VIDEO && mCurrentVideoTrack == null) { if (LOGS_ENABLED) Log.v(TAG, "Setting video track to " + mCurrentTrack.getTrackId()); mCurrentVideoTrack = mCurrentTrack; } } else { if (LOGS_ENABLED) Log.e(TAG, "Error parsing minf boxes"); } } else if (header.boxType == BOX_ID_STBL) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } if (parseOK) { IsoTrack currentTrack = (IsoTrack) mTracks.get(mTracks.size() - 1); SampleTable sampleTable = currentTrack.getSampleTable(); sampleTable.setTimescale(currentTrack.getTimeScale()); if (sampleTable.calculateSampleCountAndDuration() == false) { if (LOGS_ENABLED) Log.w(TAG, "Error while calculating sample count and duration"); } int sampleCount = sampleTable.getSampleCount(); if (sampleCount > 0) { mHasSampleTable = true; } long trackDurationUs = currentTrack.getDurationUs(); if (trackDurationUs > 0) { float frameRate = (sampleCount * 1000000.0f / trackDurationUs); mCurrentTrack.getMetaData().addValue(KEY_FRAME_RATE, frameRate); } else { mCurrentTrack.getMetaData().addValue(KEY_FRAME_RATE, 0f); } } } else if (header.boxType == BOX_ID_STSD) { // skip 4 for version and flags // skip 4 for entry_count mCurrentOffset += 8; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } if (mCurrentTrack.getMediaFormat() == null) { if (LOGS_ENABLED) Log.w(TAG, "Error parsing handler in 'stsd' box"); mCurrentTrack.setTrackType(TrackType.UNKNOWN); } } else if (header.boxType == BOX_ID_AVC1 || header.boxType == BOX_ID_AVC3) { byte[] data = new byte[78]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "Error while parsing 'avc1' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentMediaFormat = new MediaFormat(); parseVisualSampleEntry(data); mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.AVC); // TODO: Update this when we add support for nalSize other than 4 mCurrentMediaFormat.setInteger("nal-size", 4); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.AVC); while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentTrack.addSampleDescriptionEntry(mCurrentMediaFormat); } else if (header.boxType == BOX_ID_AVCC) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "Error while parsing 'avcc' box", e); mCurrentBoxSequence.removeLast(); return false; } AvccData avccData = parseAvcc(data); if (avccData == null) { return false; } ByteBuffer csd0 = ByteBuffer.wrap(avccData.spsBuffer.array()); ByteBuffer csd1 = ByteBuffer.wrap(avccData.ppsBuffer.array()); mCurrentMediaFormat.setByteBuffer("csd-0", csd0); mCurrentMediaFormat.setByteBuffer("csd-1", csd1); mCurrentMediaFormat.setInteger("nal-length-size", mNALLengthSize); parseSPS(avccData.spsBuffer.array()); } else if (header.boxType == BOX_ID_STTS) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'stts' box", e); } mCurrentTrack.getSampleTable().setSttsData(data); } else if (header.boxType == BOX_ID_STSZ) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'stsz' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentTrack.getSampleTable().setStszData(data); } else if (header.boxType == BOX_ID_CTTS) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'ctts' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentTrack.getSampleTable().setCttsData(data); } else if (header.boxType == BOX_ID_STSC) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'stsc' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentTrack.getSampleTable().setStscData(data); } else if (header.boxType == BOX_ID_STSS) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'stss' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentTrack.getSampleTable().setStssData(data); } else if (header.boxType == BOX_ID_STCO) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'stco' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentTrack.getSampleTable().setStcoData(data); } else if (header.boxType == BOX_ID_CO64) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'co64' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentTrack.getSampleTable().setCo64Data(data); } else if (header.boxType == BOX_ID_MP4V) { byte[] data = new byte[78]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'mp4v' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentMediaFormat = new MediaFormat(); // mp4v is a type of VisualSampleEntry parseVisualSampleEntry(data); mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.MPEG4_VISUAL); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.MPEG4_VISUAL); while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentTrack.addSampleDescriptionEntry(mCurrentMediaFormat); } else if (header.boxType == BOX_ID_MP4A) { byte[] data = new byte[28]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'mp4a' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentMediaFormat = new MediaFormat(); parseAudioSampleEntry(data); mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.AAC); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.AAC); while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentTrack.addSampleDescriptionEntry(mCurrentMediaFormat); } else if (header.boxType == BOX_ID_ESDS) { // skip 4 for version and flags mCurrentOffset += 4; byte[] data = new byte[(int) header.boxDataSize - 4]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'esds' box", e); mCurrentBoxSequence.removeLast(); return false; } parseOK = parseESDS(data); } else if (header.boxType == BOX_ID_STPP) { mCurrentOffset += header.boxDataSize; mCurrentMediaFormat = new MediaFormat(); mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.TTML); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.TTML); mCurrentTrack.addSampleDescriptionEntry(mCurrentMediaFormat); } else if (header.boxType == BOX_ID_MVEX) { if (LOGS_ENABLED) Log.v(TAG, "found 'mvex', setting fragmented to true"); mIsFragmented = true; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_MEHD) { int versionFlags = 0; try { versionFlags = mDataSource.readInt(); int version = (versionFlags >> 24) & 0xFF; long durationTicks = 0; if (version == 1) { durationTicks = mDataSource.readLong(); } else { durationTicks = mDataSource.readInt(); } addMetaDataValue(KEY_DURATION, durationTicks * 1000 / mFileTimescale); } catch (EOFException e) { if (LOGS_ENABLED) Log.e(TAG, "EOFException while parsing 'mvex' box", e); mCurrentBoxSequence.removeLast(); return false; } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'mehd' box", e); mCurrentBoxSequence.removeLast(); return false; } } else if (header.boxType == BOX_ID_TREX) { try { Trex newTrex = new Trex(); mDataSource.skipBytes(4); // version and flags int trackId = mDataSource.readInt(); mDataSource.skipBytes(4); // Skip Default Sample Description Index newTrex.defaultSampleDuration = mDataSource.readInt(); newTrex.defaultSampleSize = mDataSource.readInt(); mDataSource.skipBytes(4); // Skip Default Sample Flags IsoTrack track = null; int numTracks = mTracks.size(); for (int i = 0; i < numTracks; i++) { IsoTrack t = (IsoTrack) (mTracks.get(i)); if (t.getTrackId() == trackId) { track = t; break; } } if (track == null) { track = (IsoTrack) createTrack(); track.setTrackId(trackId); mTracks.add(track); } if (track != null) { track.setTrex(newTrex); } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'trex' box", e); mCurrentBoxSequence.removeLast(); return false; } } else if (header.boxType == BOX_ID_MOOF) { if (mFirstMoofOffset == -1) { mIsFragmented = true; mInitDone = true; mFirstMoofOffset = header.startOffset; mCurrentBoxSequence.removeLast(); return true; } mCurrentMoofOffset = header.startOffset; mMoofDataSize = 0; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_TRAF) { mParsedSencData = false; mCurrentTrackFragment = new Traf(); mPrevTrunDataSize = 0; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_TFHD) { parseOK = parseTfhd(header); } else if (header.boxType == BOX_ID_TRUN) { parseOK = parseTrun(header); } else if (header.boxType == BOX_ID_MFRA) { if (!mFoundMfra) { mMfraTracks = new ArrayList<ISOBMFFParser.IsoTrack>(2); while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mFoundMfra = true; } } else if (header.boxType == BOX_ID_TFRA) { parseOK = parseTfra(header); } else if (header.boxType == BOX_ID_ENCA) { byte[] data = new byte[28]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'enca' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentMediaFormat = new MediaFormat(); parseAudioSampleEntry(data); while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentTrack.addSampleDescriptionEntry(mCurrentMediaFormat); } else if (header.boxType == BOX_ID_ENCV) { byte[] data = new byte[78]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'encv' box", e); mCurrentBoxSequence.removeLast(); return false; } mCurrentMediaFormat = new MediaFormat(); parseVisualSampleEntry(data); while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentTrack.addSampleDescriptionEntry(mCurrentMediaFormat); } else if (header.boxType == BOX_ID_FRMA) { try { int dataFormat = mDataSource.readInt(); if (dataFormat == BOX_ID_AVC1) { mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.AVC); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.AVC); } else if (dataFormat == BOX_ID_HVC1) { mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.HEVC); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.HEVC); } else if (dataFormat == BOX_ID_MP4V) { mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.MPEG4_VISUAL); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.MPEG4_VISUAL); } else if (dataFormat == BOX_ID_MP4A) { mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.AAC); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.AAC); } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "Exception while parsing 'frma' box", e); mCurrentBoxSequence.removeLast(); return false; } } else if (header.boxType == BOX_ID_SCHM) { try { int versionFlags = mDataSource.readInt(); mDataSource.skipBytes(8); // scheme_type and scheme_version if ((versionFlags & 0x01) != 0) { // TODO read scheme_uri if we're interested // byte[] data = new byte[(int)header.boxDataSize - 12]; // mDataSource.read(data); mDataSource.skipBytes(header.boxDataSize - 12); } } catch (EOFException e) { if (LOGS_ENABLED) Log.e(TAG, "Error parsing 'schm' box", e); mCurrentBoxSequence.removeLast(); parseOK = false; } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "Error parsing 'schm' box", e); mCurrentBoxSequence.removeLast(); parseOK = false; } } else if (header.boxType == BOX_ID_SCHI) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_EDTS) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_ELST) { parseOK = parseElst(header); } else if (header.boxType == BOX_ID_PSSH) { parseOK = parsePsshData(header); } else if (header.boxType == BOX_ID_TENC) { try { // Skip version, flags and algorithm id mDataSource.skipBytes(7); int ivSize = mDataSource.readByte(); byte[] kID = new byte[16]; mDataSource.read(kID); mCurrentTrack.setDefaultEncryptionData(ivSize, kID); parseOK = true; } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'tenc' box", e); parseOK = false; } } else if (header.boxType == BOX_ID_SENC) { if (mCurrentMoofTrackId == mCurrentTrackId && !mSkipInsertSamples && !mParsedSencData) { mParsedSencData = true; try { int versionFlags = mDataSource.readInt(); int sampleCount = mDataSource.readInt(); ArrayList<CryptoInfo> cryptoInfos = new ArrayList<CryptoInfo>(sampleCount); for (int i = 0; i < sampleCount; i++) { CryptoInfo info = new CryptoInfo(); info.mode = MediaCodec.CRYPTO_MODE_AES_CTR; info.iv = new byte[16]; if (mCurrentTrack.mDefaultIVSize == 16) { mDataSource.read(info.iv); } else { // pad IV data to 128 bits byte[] iv = new byte[8]; mDataSource.read(iv); System.arraycopy(iv, 0, info.iv, 0, 8); } if ((versionFlags & 0x00000002) > 0) { short subSampleCount = mDataSource.readShort(); info.numSubSamples = subSampleCount; info.numBytesOfClearData = new int[subSampleCount]; info.numBytesOfEncryptedData = new int[subSampleCount]; for (int j = 0; j < subSampleCount; j++) { info.numBytesOfClearData[j] = mDataSource.readShort(); info.numBytesOfEncryptedData[j] = mDataSource.readInt(); } } else { info.numSubSamples = 1; info.numBytesOfClearData = new int[1]; info.numBytesOfClearData[0] = 0; info.numBytesOfEncryptedData = new int[1]; info.numBytesOfEncryptedData[0] = -1; } if (info.numBytesOfClearData[0] == 0 && mCurrentTrack.getTrackType() == TrackType.VIDEO) { info.iv[15] = (byte) mNALLengthSize; } cryptoInfos.add(info); } mCurrentTrack.addCryptoInfos(cryptoInfos); } catch (EOFException e) { if (LOGS_ENABLED) Log.e(TAG, "Error parsing 'senc' box", e); mCurrentBoxSequence.removeLast(); parseOK = false; } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "Error parsing 'senc' box", e); mCurrentBoxSequence.removeLast(); parseOK = false; } } } else if (header.boxType == BOX_ID_SINF) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_HVC1 || header.boxType == BOX_ID_HEV1) { byte[] data = new byte[78]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'hvc1' box", e); return false; } mCurrentMediaFormat = new MediaFormat(); mCurrentMediaFormat.setString(MediaFormat.KEY_MIME, MimeType.HEVC); mCurrentTrack.getMetaData().addValue(KEY_MIME_TYPE, MimeType.HEVC); parseVisualSampleEntry(data); while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentTrack.addSampleDescriptionEntry(mCurrentMediaFormat); } else if (header.boxType == BOX_ID_HVCC) { byte[] data = new byte[(int) header.boxDataSize]; try { if (mDataSource.readAt(mCurrentOffset, data, data.length) != data.length) { mCurrentBoxSequence.removeLast(); return false; } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException while parsing 'hvcc' box", e); return false; } byte[] hvccData = parseHvcc(data); if (hvccData == null) { return false; } ByteBuffer csd0 = ByteBuffer.wrap(hvccData); mCurrentMediaFormat.setByteBuffer("csd-0", csd0); mCurrentMediaFormat.setInteger("nal-length-size", mNALLengthSize); } else if (header.boxType == BOX_ID_UDTA) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_META) { mCurrentOffset += 4; // skip version and flags while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_ILST) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else if (header.boxType == BOX_ID_ATNAM) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_TITLE; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_ATALB) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_ALBUM; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_ATART) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_ARTIST; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_AART) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_ALBUM_ARTIST; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_ATDAY) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_YEAR; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_TRKN) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_TRACK_NUMBER; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_ATGEN || header.boxType == BOX_ID_GNRE) { mCurrentMetaDataKey = KEY_GENRE; if (boxIsUnder(BOX_ID_ILST)) { while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } } else { // 3gpp metadata value try { mDataSource.skipBytes(4); // skip version and flags mDataSource.skipBytes(2); // skip language code byte[] buffer = new byte[(int) (header.boxDataSize - 6)]; mDataSource.read(buffer); String metaDataValue = null; if ((0xFF & buffer[0]) == 0xFF && (0xFF & buffer[1]) == 0xFE || (0xFF & buffer[0]) == 0xFE && (0xFF & buffer[1]) == 0xFF) { metaDataValue = new String(buffer, 0, buffer.length - 2, StandardCharsets.UTF_16); } else { metaDataValue = new String(buffer, 0, buffer.length - 1, StandardCharsets.UTF_8); } addMetaDataValue(mCurrentMetaDataKey, metaDataValue); } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException parsing 'gnre' box", e); parseOK = false; } } mCurrentMetaDataKey = null; } else if (header.boxType == BOX_ID_CPIL) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_COMPILATION; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_ATWRT) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_WRITER; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_DISK) { if (boxIsUnder(BOX_ID_ILST)) { mCurrentMetaDataKey = KEY_DISC_NUMBER; while (mCurrentOffset < boxEndOffset && parseOK) { BoxHeader nextBoxHeader = getNextBoxHeader(); parseOK = parseBox(nextBoxHeader); } mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_DATA) { parseOK = parseDataBox(header); } else if (header.boxType == BOX_ID_ID32) { parseOK = parseID3(header); } else if (header.boxType == BOX_ID_TITL) { if (!mMetaDataValues.containsKey(KEY_TITLE)) { mCurrentMetaDataKey = KEY_TITLE; parseOK = parse3GPPMetaDataString(header); mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_PERF) { if (!mMetaDataValues.containsKey(KEY_ARTIST)) { mCurrentMetaDataKey = KEY_ARTIST; parseOK = parse3GPPMetaDataString(header); mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_AUTH) { if (!mMetaDataValues.containsKey(KEY_AUTHOR)) { mCurrentMetaDataKey = KEY_AUTHOR; parseOK = parse3GPPMetaDataString(header); mCurrentMetaDataKey = null; } } else if (header.boxType == BOX_ID_ALBM) { if (!mMetaDataValues.containsKey(KEY_ALBUM)) { try { mDataSource.skipBytes(4); // skip version and flags mDataSource.skipBytes(2); // skip language code byte[] buffer = new byte[(int) (header.boxDataSize - 6)]; mDataSource.read(buffer); String metaDataValue = null; if ((0xFF & buffer[0]) == 0xFF && (0xFF & buffer[1]) == 0xFE) { if (buffer[buffer.length - 3] == 0 && buffer[buffer.length - 2] == 0) { if (!mMetaDataValues.containsKey(KEY_TRACK_NUMBER)) { String trackNumber = Byte.toString(buffer[buffer.length - 1]); addMetaDataValue(KEY_TRACK_NUMBER, trackNumber); } metaDataValue = new String(buffer, 0, buffer.length - 3, StandardCharsets.UTF_16); } else { metaDataValue = new String(buffer, StandardCharsets.UTF_16); } } else if ((0xFF & buffer[0]) == 0xFE && (0xFF & buffer[1]) == 0xFF) { if (buffer[buffer.length - 3] == 0 && buffer[buffer.length - 2] == 0) { if (!mMetaDataValues.containsKey(KEY_TRACK_NUMBER)) { String trackNumber = Byte.toString(buffer[buffer.length - 1]); addMetaDataValue(KEY_TRACK_NUMBER, trackNumber); } metaDataValue = new String(buffer, 0, buffer.length - 3, StandardCharsets.UTF_16); } else { metaDataValue = new String(buffer, 0, buffer.length - 2, StandardCharsets.UTF_16); } } else { if (buffer[buffer.length - 2] == 0) { if (!mMetaDataValues.containsKey(KEY_TRACK_NUMBER)) { String trackNumber = Byte.toString(buffer[buffer.length - 1]); addMetaDataValue(KEY_TRACK_NUMBER, trackNumber); } metaDataValue = new String(buffer, 0, buffer.length - 2, StandardCharsets.UTF_8); } else { metaDataValue = new String(buffer, 0, buffer.length - 1, StandardCharsets.UTF_8); } } addMetaDataValue(KEY_ALBUM, metaDataValue); } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException parsing 'albm' box", e); parseOK = false; } } } else if (header.boxType == BOX_ID_YRRC) { try { mDataSource.skipBytes(4); // skip version and flags if (header.boxDataSize > 6) { // This should be a 16 bit int according to spec, but some // files have this as a string mDataSource.skipBytes(2); // skip language code byte[] buffer = new byte[(int) (header.boxDataSize - 6)]; mDataSource.read(buffer); String metaDataValue = null; if ((0xFF & buffer[0]) == 0xFF && (0xFF & buffer[1]) == 0xFE || (0xFF & buffer[0]) == 0xFE && (0xFF & buffer[1]) == 0xFF) { metaDataValue = new String(buffer, 0, buffer.length - 2, StandardCharsets.UTF_16); } else { metaDataValue = new String(buffer, 0, buffer.length - 1, StandardCharsets.UTF_8); } addMetaDataValue(KEY_YEAR, metaDataValue); } else { int year = mDataSource.readShort(); String metaDataValue = Integer.toString(year); addMetaDataValue(KEY_YEAR, metaDataValue); } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "IOException parsing 'yrrc' box", e); parseOK = false; } } else if (header.boxType == BOX_ID_MDAT) { if (mTracks.size() > 0 && !mIsFragmented) { mInitDone = true; } else if (mIsFragmented && mFirstMoofOffset != -1) { mInitDone = true; } else { mMdatFound = true; } } else { long skipSize = header.boxDataSize; try { while (skipSize > Integer.MAX_VALUE) { mDataSource.skipBytes(Integer.MAX_VALUE); skipSize -= Integer.MAX_VALUE; } if (skipSize > 0) { mDataSource.skipBytes(skipSize); } } catch (IOException e) { if (LOGS_ENABLED) Log.e(TAG, "could not skip box"); mCurrentBoxSequence.removeLast(); parseOK = false; } } mCurrentOffset = boxEndOffset; mCurrentBoxSequence.removeLast(); return parseOK; }