Example usage for android.media MediaCodec CRYPTO_MODE_AES_CTR

List of usage examples for android.media MediaCodec CRYPTO_MODE_AES_CTR

Introduction

In this page you can find the example usage for android.media MediaCodec CRYPTO_MODE_AES_CTR.

Prototype

int CRYPTO_MODE_AES_CTR

To view the source code for android.media MediaCodec CRYPTO_MODE_AES_CTR.

Click Source Link

Usage

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;
}