Search in sources :

Example 6 with CryptoData

use of com.google.android.exoplayer2.extractor.TrackOutput.CryptoData in project ExoPlayer by google.

the class SampleQueueTest method capacityIncreases.

@Test
public void capacityIncreases() {
    int numberOfSamplesToInput = 3 * SampleQueue.SAMPLE_CAPACITY_INCREMENT + 1;
    sampleQueue.format(FORMAT_1);
    sampleQueue.sampleData(new ParsableByteArray(numberOfSamplesToInput), /* length= */
    numberOfSamplesToInput);
    for (int i = 0; i < numberOfSamplesToInput; i++) {
        sampleQueue.sampleMetadata(/* timeUs= */
        i * 1000, /* flags= */
        C.BUFFER_FLAG_KEY_FRAME, /* size= */
        1, /* offset= */
        numberOfSamplesToInput - i - 1, /* cryptoData= */
        null);
    }
    assertReadFormat(/* formatRequired= */
    false, FORMAT_1);
    for (int i = 0; i < numberOfSamplesToInput; i++) {
        assertReadSample(/* timeUs= */
        i * 1000, /* isKeyFrame= */
        true, /* isDecodeOnly= */
        false, /* isEncrypted= */
        false, /* sampleData= */
        new byte[1], /* offset= */
        0, /* length= */
        1);
    }
    assertReadNothing(/* formatRequired= */
    false);
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) Test(org.junit.Test)

Example 7 with CryptoData

use of com.google.android.exoplayer2.extractor.TrackOutput.CryptoData in project ExoPlayer by google.

the class SubtitleExtractor method writeToOutput.

private void writeToOutput() {
    checkStateNotNull(this.trackOutput);
    checkState(timestamps.size() == samples.size());
    int index = seekTimeUs == C.TIME_UNSET ? 0 : Util.binarySearchFloor(timestamps, seekTimeUs, /* inclusive= */
    true, /* stayInBounds= */
    true);
    for (int i = index; i < samples.size(); i++) {
        ParsableByteArray sample = samples.get(i);
        sample.setPosition(0);
        int size = sample.getData().length;
        trackOutput.sampleData(sample, size);
        trackOutput.sampleMetadata(/* timeUs= */
        timestamps.get(i), /* flags= */
        C.BUFFER_FLAG_KEY_FRAME, /* size= */
        size, /* offset= */
        0, /* cryptoData= */
        null);
    }
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray)

Example 8 with CryptoData

use of com.google.android.exoplayer2.extractor.TrackOutput.CryptoData in project ExoPlayer by google.

the class SampleDataQueue method readEncryptionData.

/**
 * Reads encryption data for the sample described by {@code extrasHolder}.
 *
 * <p>The encryption data is written into {@link DecoderInputBuffer#cryptoInfo}, and {@link
 * SampleExtrasHolder#size} is adjusted to subtract the number of bytes that were read. The same
 * value is added to {@link SampleExtrasHolder#offset}.
 *
 * @param allocationNode The first {@link AllocationNode} containing data yet to be read.
 * @param buffer The buffer into which the encryption data should be written.
 * @param extrasHolder The extras holder whose offset should be read and subsequently adjusted.
 * @param scratch A scratch {@link ParsableByteArray}.
 * @return The first {@link AllocationNode} that contains unread bytes after this method returns.
 */
private static AllocationNode readEncryptionData(AllocationNode allocationNode, DecoderInputBuffer buffer, SampleExtrasHolder extrasHolder, ParsableByteArray scratch) {
    long offset = extrasHolder.offset;
    // Read the signal byte.
    scratch.reset(1);
    allocationNode = readData(allocationNode, offset, scratch.getData(), 1);
    offset++;
    byte signalByte = scratch.getData()[0];
    boolean subsampleEncryption = (signalByte & 0x80) != 0;
    int ivSize = signalByte & 0x7F;
    // Read the initialization vector.
    CryptoInfo cryptoInfo = buffer.cryptoInfo;
    if (cryptoInfo.iv == null) {
        cryptoInfo.iv = new byte[16];
    } else {
        // Zero out cryptoInfo.iv so that if ivSize < 16, the remaining bytes are correctly set to 0.
        Arrays.fill(cryptoInfo.iv, (byte) 0);
    }
    allocationNode = readData(allocationNode, offset, cryptoInfo.iv, ivSize);
    offset += ivSize;
    // Read the subsample count, if present.
    int subsampleCount;
    if (subsampleEncryption) {
        scratch.reset(2);
        allocationNode = readData(allocationNode, offset, scratch.getData(), 2);
        offset += 2;
        subsampleCount = scratch.readUnsignedShort();
    } else {
        subsampleCount = 1;
    }
    // Write the clear and encrypted subsample sizes.
    @Nullable int[] clearDataSizes = cryptoInfo.numBytesOfClearData;
    if (clearDataSizes == null || clearDataSizes.length < subsampleCount) {
        clearDataSizes = new int[subsampleCount];
    }
    @Nullable int[] encryptedDataSizes = cryptoInfo.numBytesOfEncryptedData;
    if (encryptedDataSizes == null || encryptedDataSizes.length < subsampleCount) {
        encryptedDataSizes = new int[subsampleCount];
    }
    if (subsampleEncryption) {
        int subsampleDataLength = 6 * subsampleCount;
        scratch.reset(subsampleDataLength);
        allocationNode = readData(allocationNode, offset, scratch.getData(), subsampleDataLength);
        offset += subsampleDataLength;
        scratch.setPosition(0);
        for (int i = 0; i < subsampleCount; i++) {
            clearDataSizes[i] = scratch.readUnsignedShort();
            encryptedDataSizes[i] = scratch.readUnsignedIntToInt();
        }
    } else {
        clearDataSizes[0] = 0;
        encryptedDataSizes[0] = extrasHolder.size - (int) (offset - extrasHolder.offset);
    }
    // Populate the cryptoInfo.
    CryptoData cryptoData = Util.castNonNull(extrasHolder.cryptoData);
    cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes, cryptoData.encryptionKey, cryptoInfo.iv, cryptoData.cryptoMode, cryptoData.encryptedBlocks, cryptoData.clearBlocks);
    // Adjust the offset and size to take into account the bytes read.
    int bytesRead = (int) (offset - extrasHolder.offset);
    extrasHolder.offset += bytesRead;
    extrasHolder.size -= bytesRead;
    return allocationNode;
}
Also used : CryptoData(com.google.android.exoplayer2.extractor.TrackOutput.CryptoData) CryptoInfo(com.google.android.exoplayer2.decoder.CryptoInfo) Nullable(androidx.annotation.Nullable)

Example 9 with CryptoData

use of com.google.android.exoplayer2.extractor.TrackOutput.CryptoData in project ExoPlayer by google.

the class Mp4Extractor method readSample.

/**
 * Attempts to extract the next sample in the current mdat atom for the specified track.
 *
 * <p>Returns {@link #RESULT_SEEK} if the source should be reloaded from the position in {@code
 * positionHolder}.
 *
 * <p>Returns {@link #RESULT_END_OF_INPUT} if no samples are left. Otherwise, returns {@link
 * #RESULT_CONTINUE}.
 *
 * @param input The {@link ExtractorInput} from which to read data.
 * @param positionHolder If {@link #RESULT_SEEK} is returned, this holder is updated to hold the
 *     position of the required data.
 * @return One of the {@code RESULT_*} flags in {@link Extractor}.
 * @throws IOException If an error occurs reading from the input.
 */
private int readSample(ExtractorInput input, PositionHolder positionHolder) throws IOException {
    long inputPosition = input.getPosition();
    if (sampleTrackIndex == C.INDEX_UNSET) {
        sampleTrackIndex = getTrackIndexOfNextReadSample(inputPosition);
        if (sampleTrackIndex == C.INDEX_UNSET) {
            return RESULT_END_OF_INPUT;
        }
    }
    Mp4Track track = castNonNull(tracks)[sampleTrackIndex];
    TrackOutput trackOutput = track.trackOutput;
    int sampleIndex = track.sampleIndex;
    long position = track.sampleTable.offsets[sampleIndex];
    int sampleSize = track.sampleTable.sizes[sampleIndex];
    @Nullable TrueHdSampleRechunker trueHdSampleRechunker = track.trueHdSampleRechunker;
    long skipAmount = position - inputPosition + sampleBytesRead;
    if (skipAmount < 0 || skipAmount >= RELOAD_MINIMUM_SEEK_DISTANCE) {
        positionHolder.position = position;
        return RESULT_SEEK;
    }
    if (track.track.sampleTransformation == Track.TRANSFORMATION_CEA608_CDAT) {
        // The sample information is contained in a cdat atom. The header must be discarded for
        // committing.
        skipAmount += Atom.HEADER_SIZE;
        sampleSize -= Atom.HEADER_SIZE;
    }
    input.skipFully((int) skipAmount);
    if (track.track.nalUnitLengthFieldLength != 0) {
        // Zero the top three bytes of the array that we'll use to decode nal unit lengths, in case
        // they're only 1 or 2 bytes long.
        byte[] nalLengthData = nalLength.getData();
        nalLengthData[0] = 0;
        nalLengthData[1] = 0;
        nalLengthData[2] = 0;
        int nalUnitLengthFieldLength = track.track.nalUnitLengthFieldLength;
        int nalUnitLengthFieldLengthDiff = 4 - track.track.nalUnitLengthFieldLength;
        // start codes as we encounter them.
        while (sampleBytesWritten < sampleSize) {
            if (sampleCurrentNalBytesRemaining == 0) {
                // Read the NAL length so that we know where we find the next one.
                input.readFully(nalLengthData, nalUnitLengthFieldLengthDiff, nalUnitLengthFieldLength);
                sampleBytesRead += nalUnitLengthFieldLength;
                nalLength.setPosition(0);
                int nalLengthInt = nalLength.readInt();
                if (nalLengthInt < 0) {
                    throw ParserException.createForMalformedContainer("Invalid NAL length", /* cause= */
                    null);
                }
                sampleCurrentNalBytesRemaining = nalLengthInt;
                // Write a start code for the current NAL unit.
                nalStartCode.setPosition(0);
                trackOutput.sampleData(nalStartCode, 4);
                sampleBytesWritten += 4;
                sampleSize += nalUnitLengthFieldLengthDiff;
            } else {
                // Write the payload of the NAL unit.
                int writtenBytes = trackOutput.sampleData(input, sampleCurrentNalBytesRemaining, false);
                sampleBytesRead += writtenBytes;
                sampleBytesWritten += writtenBytes;
                sampleCurrentNalBytesRemaining -= writtenBytes;
            }
        }
    } else {
        if (MimeTypes.AUDIO_AC4.equals(track.track.format.sampleMimeType)) {
            if (sampleBytesWritten == 0) {
                Ac4Util.getAc4SampleHeader(sampleSize, scratch);
                trackOutput.sampleData(scratch, Ac4Util.SAMPLE_HEADER_SIZE);
                sampleBytesWritten += Ac4Util.SAMPLE_HEADER_SIZE;
            }
            sampleSize += Ac4Util.SAMPLE_HEADER_SIZE;
        } else if (trueHdSampleRechunker != null) {
            trueHdSampleRechunker.startSample(input);
        }
        while (sampleBytesWritten < sampleSize) {
            int writtenBytes = trackOutput.sampleData(input, sampleSize - sampleBytesWritten, false);
            sampleBytesRead += writtenBytes;
            sampleBytesWritten += writtenBytes;
            sampleCurrentNalBytesRemaining -= writtenBytes;
        }
    }
    long timeUs = track.sampleTable.timestampsUs[sampleIndex];
    @C.BufferFlags int flags = track.sampleTable.flags[sampleIndex];
    if (trueHdSampleRechunker != null) {
        trueHdSampleRechunker.sampleMetadata(trackOutput, timeUs, flags, sampleSize, /* offset= */
        0, /* cryptoData= */
        null);
        if (sampleIndex + 1 == track.sampleTable.sampleCount) {
            trueHdSampleRechunker.outputPendingSampleMetadata(trackOutput, /* cryptoData= */
            null);
        }
    } else {
        trackOutput.sampleMetadata(timeUs, flags, sampleSize, /* offset= */
        0, /* cryptoData= */
        null);
    }
    track.sampleIndex++;
    sampleTrackIndex = C.INDEX_UNSET;
    sampleBytesRead = 0;
    sampleBytesWritten = 0;
    sampleCurrentNalBytesRemaining = 0;
    return RESULT_CONTINUE;
}
Also used : TrueHdSampleRechunker(com.google.android.exoplayer2.extractor.TrueHdSampleRechunker) TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput) SeekPoint(com.google.android.exoplayer2.extractor.SeekPoint) Nullable(androidx.annotation.Nullable)

Aggregations

Nullable (androidx.annotation.Nullable)5 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)4 SeekPoint (com.google.android.exoplayer2.extractor.SeekPoint)2 TrackOutput (com.google.android.exoplayer2.extractor.TrackOutput)2 CryptoData (com.google.android.exoplayer2.extractor.TrackOutput.CryptoData)2 Test (org.junit.Test)2 SuppressLint (android.annotation.SuppressLint)1 CryptoInfo (android.media.MediaCodec.CryptoInfo)1 Format (com.google.android.exoplayer2.Format)1 CryptoInfo (com.google.android.exoplayer2.decoder.CryptoInfo)1 DrmSessionReference (com.google.android.exoplayer2.drm.DrmSessionManager.DrmSessionReference)1 TrueHdSampleRechunker (com.google.android.exoplayer2.extractor.TrueHdSampleRechunker)1 Matcher (java.util.regex.Matcher)1