org.signal.libsignal.media.Mp4Sanitizer Maven / Gradle / Ivy
Show all versions of libsignal-client Show documentation
//
// Copyright 2023 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//
package org.signal.libsignal.media;
import static org.signal.libsignal.internal.FilterExceptions.filterExceptions;
import java.io.IOException;
import java.io.InputStream;
import org.signal.libsignal.internal.Native;
/**
* An MP4 format “sanitizer”.
*
* Currently the sanitizer always performs the following functions:
*
*
* - Return all presentation metadata present in the input as a self-contained contiguous byte
* array.
*
- Find and return a pointer to the span in the input containing the (contiguous) media data.
*
*
* “Presentation” metadata means any metadata which is required by an MP4 player to play the
* file. “Self-contained and contiguous” means that the returned metadata can be concatenated with
* the media data to form a valid MP4 file.
*
*
The original metadata may or may not need to be modified in order to perform these functions.
* In the case that the original metadata does not need to be modified, the returned sanitized
* metadata will be null to prevent needless data copying.
*
*
Unsupported MP4 features
*
* The sanitizer does not currently support:
*
*
* - “Fragmented” MP4 files, which are mostly used for adaptive-bitrate streaming.
*
- Discontiguous media data, i.e. media data (mdat) boxes interspersed with presentation
* metadata (moov).
*
- Media data references (dref) pointing to separate files.
*
- Any similar format, e.g. Quicktime File Format (mov) or the legacy MP4 version 1, which
* does not contain the "isom" compatible brand in its file type header (ftyp).
*
*/
public class Mp4Sanitizer {
/**
* Sanitize an MP4 input.
*
* It's recommended that the given {@link InputStream} be capable of {@code skip}ping, and that
* it skips fewer bytes than requested only when the end of stream is reached.
*
* @param input An MP4 format input stream.
* @param length The exact length of the input stream.
* @return The sanitized metadata.
* @throws IOException If an IO error on the input occurs.
* @throws ParseException If the input could not be parsed.
*/
public static SanitizedMetadata sanitize(InputStream input, long length)
throws IOException, ParseException {
long sanitizedMetadataHandle =
filterExceptions(
IOException.class,
ParseException.class,
() -> Native.Mp4Sanitizer_Sanitize(TrustedSkipInputStream.makeTrusted(input), length));
try {
byte[] sanitizedMetadata = Native.SanitizedMetadata_GetMetadata(sanitizedMetadataHandle);
if (sanitizedMetadata.length == 0) {
sanitizedMetadata = null;
}
long dataOffset = Native.SanitizedMetadata_GetDataOffset(sanitizedMetadataHandle);
long dataLength = Native.SanitizedMetadata_GetDataLen(sanitizedMetadataHandle);
return new SanitizedMetadata(sanitizedMetadata, dataOffset, dataLength);
} finally {
Native.SanitizedMetadata_Destroy(sanitizedMetadataHandle);
}
}
}