Search in sources :

Example 1 with ParsableBitArray

use of androidx.media3.common.util.ParsableBitArray in project media by androidx.

the class DtsUtil method getNormalizedFrameHeader.

private static ParsableBitArray getNormalizedFrameHeader(byte[] frameHeader) {
    if (frameHeader[0] == FIRST_BYTE_BE) {
        // The frame is already 16-bit mode, big endian.
        return new ParsableBitArray(frameHeader);
    }
    // Data is not normalized, but we don't want to modify frameHeader.
    frameHeader = Arrays.copyOf(frameHeader, frameHeader.length);
    if (isLittleEndianFrameHeader(frameHeader)) {
        // Change endianness.
        for (int i = 0; i < frameHeader.length - 1; i += 2) {
            byte temp = frameHeader[i];
            frameHeader[i] = frameHeader[i + 1];
            frameHeader[i + 1] = temp;
        }
    }
    ParsableBitArray frameBits = new ParsableBitArray(frameHeader);
    if (frameHeader[0] == (byte) (SYNC_VALUE_14B_BE >> 24)) {
        // Discard the 2 most significant bits of each 16 bit word.
        ParsableBitArray scratchBits = new ParsableBitArray(frameHeader);
        while (scratchBits.bitsLeft() >= 16) {
            scratchBits.skipBits(2);
            frameBits.putInt(scratchBits.readBits(14), 14);
        }
    }
    frameBits.reset(frameHeader);
    return frameBits;
}
Also used : ParsableBitArray(androidx.media3.common.util.ParsableBitArray)

Example 2 with ParsableBitArray

use of androidx.media3.common.util.ParsableBitArray in project media by androidx.

the class AppInfoTableDecoder method parseAit.

@Nullable
private static Metadata parseAit(ParsableBitArray sectionData) {
    // tableId, section_syntax_indication, reserved_future_use, reserved
    sectionData.skipBits(12);
    int sectionLength = sectionData.readBits(12);
    int endOfSection = sectionData.getBytePosition() + sectionLength - 4;
    // test_application_flag, application_type, reserved, version_number, current_next_indicator,
    // section_number, last_section_number, reserved_future_use
    sectionData.skipBits(44);
    int commonDescriptorsLength = sectionData.readBits(12);
    // Since we currently only keep URL and control code, which are unique per application,
    // there is no useful information in common descriptor.
    sectionData.skipBytes(commonDescriptorsLength);
    // reserved_future_use, application_loop_length
    sectionData.skipBits(16);
    ArrayList<AppInfoTable> appInfoTables = new ArrayList<>();
    while (sectionData.getBytePosition() < endOfSection) {
        @Nullable String urlBase = null;
        @Nullable String urlExtension = null;
        // application_identifier
        sectionData.skipBits(48);
        int controlCode = sectionData.readBits(8);
        // reserved_future_use
        sectionData.skipBits(4);
        int applicationDescriptorsLoopLength = sectionData.readBits(12);
        int positionOfNextApplication = sectionData.getBytePosition() + applicationDescriptorsLoopLength;
        while (sectionData.getBytePosition() < positionOfNextApplication) {
            int descriptorTag = sectionData.readBits(8);
            int descriptorLength = sectionData.readBits(8);
            int positionOfNextDescriptor = sectionData.getBytePosition() + descriptorLength;
            if (descriptorTag == DESCRIPTOR_TRANSPORT_PROTOCOL) {
                // See section 5.3.6.
                int protocolId = sectionData.readBits(16);
                // label
                sectionData.skipBits(8);
                if (protocolId == TRANSPORT_PROTOCOL_HTTP) {
                    // See section 5.3.6.2.
                    while (sectionData.getBytePosition() < positionOfNextDescriptor) {
                        int urlBaseLength = sectionData.readBits(8);
                        urlBase = sectionData.readBytesAsString(urlBaseLength, Charsets.US_ASCII);
                        int extensionCount = sectionData.readBits(8);
                        for (int urlExtensionIndex = 0; urlExtensionIndex < extensionCount; urlExtensionIndex++) {
                            int urlExtensionLength = sectionData.readBits(8);
                            sectionData.skipBytes(urlExtensionLength);
                        }
                    }
                }
            } else if (descriptorTag == DESCRIPTOR_SIMPLE_APPLICATION_LOCATION) {
                // See section 5.3.7.
                urlExtension = sectionData.readBytesAsString(descriptorLength, Charsets.US_ASCII);
            }
            sectionData.setPosition(positionOfNextDescriptor * 8);
        }
        sectionData.setPosition(positionOfNextApplication * 8);
        if (urlBase != null && urlExtension != null) {
            appInfoTables.add(new AppInfoTable(controlCode, urlBase + urlExtension));
        }
    }
    return appInfoTables.isEmpty() ? null : new Metadata(appInfoTables);
}
Also used : ArrayList(java.util.ArrayList) Metadata(androidx.media3.common.Metadata) Nullable(androidx.annotation.Nullable) Nullable(androidx.annotation.Nullable)

Example 3 with ParsableBitArray

use of androidx.media3.common.util.ParsableBitArray in project media by androidx.

the class DvbParser method paintPixelDataSubBlock.

/**
 * Draws a pixel data sub-block, as defined by ETSI EN 300 743 7.2.5.1, into a canvas.
 */
private static void paintPixelDataSubBlock(byte[] pixelData, int[] clutEntries, int regionDepth, int horizontalAddress, int verticalAddress, @Nullable Paint paint, Canvas canvas) {
    ParsableBitArray data = new ParsableBitArray(pixelData);
    int column = horizontalAddress;
    int line = verticalAddress;
    @Nullable byte[] clutMapTable2To4 = null;
    @Nullable byte[] clutMapTable2To8 = null;
    @Nullable byte[] clutMapTable4To8 = null;
    while (data.bitsLeft() != 0) {
        int dataType = data.readBits(8);
        switch(dataType) {
            case DATA_TYPE_2BP_CODE_STRING:
                @Nullable byte[] clutMapTable2ToX;
                if (regionDepth == REGION_DEPTH_8_BIT) {
                    clutMapTable2ToX = clutMapTable2To8 == null ? defaultMap2To8 : clutMapTable2To8;
                } else if (regionDepth == REGION_DEPTH_4_BIT) {
                    clutMapTable2ToX = clutMapTable2To4 == null ? defaultMap2To4 : clutMapTable2To4;
                } else {
                    clutMapTable2ToX = null;
                }
                column = paint2BitPixelCodeString(data, clutEntries, clutMapTable2ToX, column, line, paint, canvas);
                data.byteAlign();
                break;
            case DATA_TYPE_4BP_CODE_STRING:
                @Nullable byte[] clutMapTable4ToX;
                if (regionDepth == REGION_DEPTH_8_BIT) {
                    clutMapTable4ToX = clutMapTable4To8 == null ? defaultMap4To8 : clutMapTable4To8;
                } else {
                    clutMapTable4ToX = null;
                }
                column = paint4BitPixelCodeString(data, clutEntries, clutMapTable4ToX, column, line, paint, canvas);
                data.byteAlign();
                break;
            case DATA_TYPE_8BP_CODE_STRING:
                column = paint8BitPixelCodeString(data, clutEntries, /* clutMapTable= */
                null, column, line, paint, canvas);
                break;
            case DATA_TYPE_24_TABLE_DATA:
                clutMapTable2To4 = buildClutMapTable(4, 4, data);
                break;
            case DATA_TYPE_28_TABLE_DATA:
                clutMapTable2To8 = buildClutMapTable(4, 8, data);
                break;
            case DATA_TYPE_48_TABLE_DATA:
                clutMapTable4To8 = buildClutMapTable(16, 8, data);
                break;
            case DATA_TYPE_END_LINE:
                column = horizontalAddress;
                line += 2;
                break;
            default:
                // Do nothing.
                break;
        }
    }
}
Also used : Paint(android.graphics.Paint) Nullable(androidx.annotation.Nullable) ParsableBitArray(androidx.media3.common.util.ParsableBitArray)

Example 4 with ParsableBitArray

use of androidx.media3.common.util.ParsableBitArray in project media by androidx.

the class DvbParser method decode.

/**
 * Decodes a subtitling packet, returning a list of parsed {@link Cue}s.
 *
 * @param data The subtitling packet data to decode.
 * @param limit The limit in {@code data} at which to stop decoding.
 * @return The parsed {@link Cue}s.
 */
public List<Cue> decode(byte[] data, int limit) {
    // Parse the input data.
    ParsableBitArray dataBitArray = new ParsableBitArray(data, limit);
    while (// sync_byte (8) + segment header (40)
    dataBitArray.bitsLeft() >= 48 && dataBitArray.readBits(8) == 0x0F) {
        parseSubtitlingSegment(dataBitArray, subtitleService);
    }
    @Nullable PageComposition pageComposition = subtitleService.pageComposition;
    if (pageComposition == null) {
        return Collections.emptyList();
    }
    // Update the canvas bitmap if necessary.
    DisplayDefinition displayDefinition = subtitleService.displayDefinition != null ? subtitleService.displayDefinition : defaultDisplayDefinition;
    if (bitmap == null || displayDefinition.width + 1 != bitmap.getWidth() || displayDefinition.height + 1 != bitmap.getHeight()) {
        bitmap = Bitmap.createBitmap(displayDefinition.width + 1, displayDefinition.height + 1, Bitmap.Config.ARGB_8888);
        canvas.setBitmap(bitmap);
    }
    // Build the cues.
    List<Cue> cues = new ArrayList<>();
    SparseArray<PageRegion> pageRegions = pageComposition.regions;
    for (int i = 0; i < pageRegions.size(); i++) {
        // Save clean clipping state.
        canvas.save();
        PageRegion pageRegion = pageRegions.valueAt(i);
        int regionId = pageRegions.keyAt(i);
        RegionComposition regionComposition = subtitleService.regions.get(regionId);
        // Clip drawing to the current region and display definition window.
        int baseHorizontalAddress = pageRegion.horizontalAddress + displayDefinition.horizontalPositionMinimum;
        int baseVerticalAddress = pageRegion.verticalAddress + displayDefinition.verticalPositionMinimum;
        int clipRight = min(baseHorizontalAddress + regionComposition.width, displayDefinition.horizontalPositionMaximum);
        int clipBottom = min(baseVerticalAddress + regionComposition.height, displayDefinition.verticalPositionMaximum);
        canvas.clipRect(baseHorizontalAddress, baseVerticalAddress, clipRight, clipBottom);
        ClutDefinition clutDefinition = subtitleService.cluts.get(regionComposition.clutId);
        if (clutDefinition == null) {
            clutDefinition = subtitleService.ancillaryCluts.get(regionComposition.clutId);
            if (clutDefinition == null) {
                clutDefinition = defaultClutDefinition;
            }
        }
        SparseArray<RegionObject> regionObjects = regionComposition.regionObjects;
        for (int j = 0; j < regionObjects.size(); j++) {
            int objectId = regionObjects.keyAt(j);
            RegionObject regionObject = regionObjects.valueAt(j);
            ObjectData objectData = subtitleService.objects.get(objectId);
            if (objectData == null) {
                objectData = subtitleService.ancillaryObjects.get(objectId);
            }
            if (objectData != null) {
                @Nullable Paint paint = objectData.nonModifyingColorFlag ? null : defaultPaint;
                paintPixelDataSubBlocks(objectData, clutDefinition, regionComposition.depth, baseHorizontalAddress + regionObject.horizontalPosition, baseVerticalAddress + regionObject.verticalPosition, paint, canvas);
            }
        }
        if (regionComposition.fillFlag) {
            int color;
            if (regionComposition.depth == REGION_DEPTH_8_BIT) {
                color = clutDefinition.clutEntries8Bit[regionComposition.pixelCode8Bit];
            } else if (regionComposition.depth == REGION_DEPTH_4_BIT) {
                color = clutDefinition.clutEntries4Bit[regionComposition.pixelCode4Bit];
            } else {
                color = clutDefinition.clutEntries2Bit[regionComposition.pixelCode2Bit];
            }
            fillRegionPaint.setColor(color);
            canvas.drawRect(baseHorizontalAddress, baseVerticalAddress, baseHorizontalAddress + regionComposition.width, baseVerticalAddress + regionComposition.height, fillRegionPaint);
        }
        cues.add(new Cue.Builder().setBitmap(Bitmap.createBitmap(bitmap, baseHorizontalAddress, baseVerticalAddress, regionComposition.width, regionComposition.height)).setPosition((float) baseHorizontalAddress / displayDefinition.width).setPositionAnchor(Cue.ANCHOR_TYPE_START).setLine((float) baseVerticalAddress / displayDefinition.height, Cue.LINE_TYPE_FRACTION).setLineAnchor(Cue.ANCHOR_TYPE_START).setSize((float) regionComposition.width / displayDefinition.width).setBitmapHeight((float) regionComposition.height / displayDefinition.height).build());
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        // Restore clean clipping state.
        canvas.restore();
    }
    return Collections.unmodifiableList(cues);
}
Also used : ArrayList(java.util.ArrayList) Paint(android.graphics.Paint) Paint(android.graphics.Paint) Cue(androidx.media3.common.text.Cue) Nullable(androidx.annotation.Nullable) ParsableBitArray(androidx.media3.common.util.ParsableBitArray)

Example 5 with ParsableBitArray

use of androidx.media3.common.util.ParsableBitArray in project media by androidx.

the class H263Reader method parseCsdBuffer.

/**
 * Parses a codec-specific data buffer, returning the {@link Format} of the media.
 *
 * @param csdBuffer The buffer to parse.
 * @param volStartPosition The byte offset of the start of the video object layer in the buffer.
 * @param formatId The ID for the generated format.
 * @return The {@link Format} of the media represented in the buffer.
 */
private static Format parseCsdBuffer(CsdBuffer csdBuffer, int volStartPosition, String formatId) {
    byte[] csdData = Arrays.copyOf(csdBuffer.data, csdBuffer.length);
    ParsableBitArray buffer = new ParsableBitArray(csdData);
    buffer.skipBytes(volStartPosition);
    // Parse the video object layer defined in ISO 14496-2 (2001) subsection 6.2.3.
    // video_object_layer_start_code
    buffer.skipBytes(4);
    // random_accessible_vol
    buffer.skipBit();
    // video_object_type_indication
    buffer.skipBits(8);
    if (buffer.readBit()) {
        // is_object_layer_identifier
        // video_object_layer_verid
        buffer.skipBits(4);
        // video_object_layer_priority
        buffer.skipBits(3);
    }
    float pixelWidthHeightRatio;
    int aspectRatioInfo = buffer.readBits(4);
    if (aspectRatioInfo == 0x0F) {
        // extended_PAR
        int parWidth = buffer.readBits(8);
        int parHeight = buffer.readBits(8);
        if (parHeight == 0) {
            Log.w(TAG, "Invalid aspect ratio");
            pixelWidthHeightRatio = 1f;
        } else {
            pixelWidthHeightRatio = (float) parWidth / parHeight;
        }
    } else if (aspectRatioInfo < PIXEL_WIDTH_HEIGHT_RATIO_BY_ASPECT_RATIO_INFO.length) {
        pixelWidthHeightRatio = PIXEL_WIDTH_HEIGHT_RATIO_BY_ASPECT_RATIO_INFO[aspectRatioInfo];
    } else {
        Log.w(TAG, "Invalid aspect ratio");
        pixelWidthHeightRatio = 1f;
    }
    if (buffer.readBit()) {
        // vol_control_parameters
        // chroma_format
        buffer.skipBits(2);
        // low_delay
        buffer.skipBits(1);
        if (buffer.readBit()) {
            // vbv_parameters
            // first_half_bit_rate
            buffer.skipBits(15);
            // marker_bit
            buffer.skipBit();
            // latter_half_bit_rate
            buffer.skipBits(15);
            // marker_bit
            buffer.skipBit();
            // first_half_vbv_buffer_size
            buffer.skipBits(15);
            // marker_bit
            buffer.skipBit();
            // latter_half_vbv_buffer_size
            buffer.skipBits(3);
            // first_half_vbv_occupancy
            buffer.skipBits(11);
            // marker_bit
            buffer.skipBit();
            // latter_half_vbv_occupancy
            buffer.skipBits(15);
            // marker_bit
            buffer.skipBit();
        }
    }
    int videoObjectLayerShape = buffer.readBits(2);
    if (videoObjectLayerShape != VIDEO_OBJECT_LAYER_SHAPE_RECTANGULAR) {
        Log.w(TAG, "Unhandled video object layer shape");
    }
    // marker_bit
    buffer.skipBit();
    int vopTimeIncrementResolution = buffer.readBits(16);
    // marker_bit
    buffer.skipBit();
    if (buffer.readBit()) {
        // fixed_vop_rate
        if (vopTimeIncrementResolution == 0) {
            Log.w(TAG, "Invalid vop_increment_time_resolution");
        } else {
            vopTimeIncrementResolution--;
            int numBits = 0;
            while (vopTimeIncrementResolution > 0) {
                ++numBits;
                vopTimeIncrementResolution >>= 1;
            }
            // fixed_vop_time_increment
            buffer.skipBits(numBits);
        }
    }
    // marker_bit
    buffer.skipBit();
    int videoObjectLayerWidth = buffer.readBits(13);
    // marker_bit
    buffer.skipBit();
    int videoObjectLayerHeight = buffer.readBits(13);
    // marker_bit
    buffer.skipBit();
    // interlaced
    buffer.skipBit();
    return new Format.Builder().setId(formatId).setSampleMimeType(MimeTypes.VIDEO_MP4V).setWidth(videoObjectLayerWidth).setHeight(videoObjectLayerHeight).setPixelWidthHeightRatio(pixelWidthHeightRatio).setInitializationData(Collections.singletonList(csdData)).build();
}
Also used : Format(androidx.media3.common.Format) ParsableBitArray(androidx.media3.common.util.ParsableBitArray)

Aggregations

ParsableBitArray (androidx.media3.common.util.ParsableBitArray)8 Nullable (androidx.annotation.Nullable)5 Paint (android.graphics.Paint)2 Format (androidx.media3.common.Format)2 ArrayList (java.util.ArrayList)2 Metadata (androidx.media3.common.Metadata)1 Cue (androidx.media3.common.text.Cue)1 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)1 Mesh (androidx.media3.exoplayer.video.spherical.Projection.Mesh)1 SubMesh (androidx.media3.exoplayer.video.spherical.Projection.SubMesh)1 PictureFrame (androidx.media3.extractor.metadata.flac.PictureFrame)1 ImmutableList (com.google.common.collect.ImmutableList)1 List (java.util.List)1 RequiresNonNull (org.checkerframework.checker.nullness.qual.RequiresNonNull)1