summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libstagefright/binding/DecoderData.cpp24
-rw-r--r--media/libstagefright/binding/MP4Metadata.cpp470
-rw-r--r--media/libstagefright/binding/include/mp4_demuxer/DecoderData.h13
-rw-r--r--media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h10
-rw-r--r--media/libstagefright/binding/include/mp4parse.h113
-rw-r--r--media/libstagefright/binding/mp4parse-cargo.patch45
-rw-r--r--media/libstagefright/binding/mp4parse/Cargo.toml29
-rw-r--r--media/libstagefright/binding/mp4parse/src/boxes.rs62
-rw-r--r--media/libstagefright/binding/mp4parse/src/lib.rs1704
-rw-r--r--media/libstagefright/binding/mp4parse/src/tests.rs860
-rw-r--r--media/libstagefright/binding/mp4parse/tests/afl.rs53
-rw-r--r--media/libstagefright/binding/mp4parse/tests/minimal.mp4bin2591 -> 0 bytes
-rw-r--r--media/libstagefright/binding/mp4parse/tests/public.rs97
-rw-r--r--media/libstagefright/binding/mp4parse_capi/Cargo.toml26
-rw-r--r--media/libstagefright/binding/mp4parse_capi/build.rs12
-rw-r--r--media/libstagefright/binding/mp4parse_capi/src/lib.rs870
-rwxr-xr-xmedia/libstagefright/binding/update-rust.sh56
17 files changed, 0 insertions, 4444 deletions
diff --git a/media/libstagefright/binding/DecoderData.cpp b/media/libstagefright/binding/DecoderData.cpp
index aaf2fb32c..bd51d12aa 100644
--- a/media/libstagefright/binding/DecoderData.cpp
+++ b/media/libstagefright/binding/DecoderData.cpp
@@ -13,10 +13,6 @@
#include "mozilla/ArrayUtils.h"
#include "include/ESDS.h"
-#ifdef MOZ_RUST_MP4PARSE
-#include "mp4parse.h"
-#endif
-
using namespace stagefright;
namespace mp4_demuxer
@@ -187,26 +183,6 @@ MP4VideoInfo::Update(const MetaData* aMetaData, const char* aMimeType)
}
-#ifdef MOZ_RUST_MP4PARSE
-void
-MP4VideoInfo::Update(const mp4parse_track_info* track,
- const mp4parse_track_video_info* video)
-{
- if (track->codec == MP4PARSE_CODEC_AVC) {
- mMimeType = MEDIA_MIMETYPE_VIDEO_AVC;
- } else if (track->codec == MP4PARSE_CODEC_VP9) {
- mMimeType = NS_LITERAL_CSTRING("video/vp9");
- }
- mTrackId = track->track_id;
- mDuration = track->duration;
- mMediaTime = track->media_time;
- mDisplay.width = video->display_width;
- mDisplay.height = video->display_height;
- mImage.width = video->image_width;
- mImage.height = video->image_height;
-}
-#endif
-
bool
MP4VideoInfo::IsValid() const
{
diff --git a/media/libstagefright/binding/MP4Metadata.cpp b/media/libstagefright/binding/MP4Metadata.cpp
index eb5350704..686c2b67e 100644
--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -24,14 +24,6 @@
#include <stdint.h>
#include <vector>
-#ifdef MOZ_RUST_MP4PARSE
-// OpusDecoder header is really needed only by MP4 in rust
-#include "OpusDecoder.h"
-#include "mp4parse.h"
-
-struct FreeMP4Parser { void operator()(mp4parse_parser* aPtr) { mp4parse_free(aPtr); } };
-#endif
-
using namespace stagefright;
namespace mp4_demuxer
@@ -104,65 +96,8 @@ private:
bool mCanSeek;
};
-#ifdef MOZ_RUST_MP4PARSE
-
-// Wrap an mp4_demuxer::Stream to remember the read offset.
-
-class RustStreamAdaptor {
-public:
- explicit RustStreamAdaptor(Stream* aSource)
- : mSource(aSource)
- , mOffset(0)
- {
- }
-
- ~RustStreamAdaptor() {}
-
- bool Read(uint8_t* buffer, uintptr_t size, size_t* bytes_read);
-
-private:
- Stream* mSource;
- CheckedInt<size_t> mOffset;
-};
-
-class MP4MetadataRust
-{
-public:
- explicit MP4MetadataRust(Stream* aSource);
- ~MP4MetadataRust();
-
- static bool HasCompleteMetadata(Stream* aSource);
- static already_AddRefed<mozilla::MediaByteBuffer> Metadata(Stream* aSource);
- uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
- mozilla::UniquePtr<mozilla::TrackInfo> GetTrackInfo(mozilla::TrackInfo::TrackType aType,
- size_t aTrackNumber) const;
- bool CanSeek() const;
-
- const CryptoFile& Crypto() const;
-
- bool ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID);
-
-private:
- Maybe<uint32_t> TrackTypeToGlobalTrackIndex(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const;
-
- CryptoFile mCrypto;
- RefPtr<Stream> mSource;
- RustStreamAdaptor mRustSource;
- mozilla::UniquePtr<mp4parse_parser, FreeMP4Parser> mRustParser;
-};
-#endif
-
MP4Metadata::MP4Metadata(Stream* aSource)
: mStagefright(MakeUnique<MP4MetadataStagefright>(aSource))
-#ifdef MOZ_RUST_MP4PARSE
- , mRust(MakeUnique<MP4MetadataRust>(aSource))
- , mPreferRust(false)
- , mReportedAudioTrackTelemetry(false)
- , mReportedVideoTrackTelemetry(false)
-#ifndef RELEASE_OR_BETA
- , mRustTestMode(MediaPrefs::RustTestMode())
-#endif
-#endif
{
}
@@ -202,70 +137,9 @@ MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
uint32_t numTracks = mStagefright->GetNumberTracks(aType);
-#ifdef MOZ_RUST_MP4PARSE
- if (!mRust) {
- return numTracks;
- }
-
- uint32_t numTracksRust = mRust->GetNumberTracks(aType);
- MOZ_LOG(sLog, LogLevel::Info, ("%s tracks found: stagefright=%u rust=%u",
- TrackTypeToString(aType), numTracks, numTracksRust));
-
- bool numTracksMatch = numTracks == numTracksRust;
-
- if (aType == mozilla::TrackInfo::kAudioTrack && !mReportedAudioTrackTelemetry) {
- Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO,
- numTracksMatch);
- mReportedAudioTrackTelemetry = true;
- } else if (aType == mozilla::TrackInfo::kVideoTrack && !mReportedVideoTrackTelemetry) {
- Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO,
- numTracksMatch);
- mReportedVideoTrackTelemetry = true;
- }
-
- if (mPreferRust || ShouldPreferRust()) {
- MOZ_LOG(sLog, LogLevel::Info, ("Preferring rust demuxer"));
- mPreferRust = true;
- return numTracksRust;
- }
-#endif // MOZ_RUST_MP4PARSE
-
return numTracks;
}
-#ifdef MOZ_RUST_MP4PARSE
-bool MP4Metadata::ShouldPreferRust() const {
- if (!mRust) {
- return false;
- }
- // See if there's an Opus track.
- uint32_t numTracks = mRust->GetNumberTracks(TrackInfo::kAudioTrack);
- for (auto i = 0; i < numTracks; i++) {
- auto info = mRust->GetTrackInfo(TrackInfo::kAudioTrack, i);
- if (!info) {
- return false;
- }
- if (info->mMimeType.EqualsASCII("audio/opus") ||
- info->mMimeType.EqualsASCII("audio/flac")) {
- return true;
- }
- }
-
- numTracks = mRust->GetNumberTracks(TrackInfo::kVideoTrack);
- for (auto i = 0; i < numTracks; i++) {
- auto info = mRust->GetTrackInfo(TrackInfo::kVideoTrack, i);
- if (!info) {
- return false;
- }
- if (info->mMimeType.EqualsASCII("video/vp9")) {
- return true;
- }
- }
- // Otherwise, fall back.
- return false;
-}
-#endif // MOZ_RUST_MP4PARSE
-
mozilla::UniquePtr<mozilla::TrackInfo>
MP4Metadata::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
size_t aTrackNumber) const
@@ -273,56 +147,6 @@ MP4Metadata::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
mozilla::UniquePtr<mozilla::TrackInfo> info =
mStagefright->GetTrackInfo(aType, aTrackNumber);
-#ifdef MOZ_RUST_MP4PARSE
- if (!mRust) {
- return info;
- }
-
- mozilla::UniquePtr<mozilla::TrackInfo> infoRust =
- mRust->GetTrackInfo(aType, aTrackNumber);
-
-#ifndef RELEASE_OR_BETA
- if (mRustTestMode && info) {
- MOZ_DIAGNOSTIC_ASSERT(infoRust);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mId == info->mId);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mKind == info->mKind);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mLabel == info->mLabel);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mLanguage == info->mLanguage);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mEnabled == info->mEnabled);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mTrackId == info->mTrackId);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mMimeType == info->mMimeType);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mDuration == info->mDuration);
- MOZ_DIAGNOSTIC_ASSERT(infoRust->mMediaTime == info->mMediaTime);
- switch (aType) {
- case mozilla::TrackInfo::kAudioTrack: {
- AudioInfo *audioRust = infoRust->GetAsAudioInfo(), *audio = info->GetAsAudioInfo();
- MOZ_DIAGNOSTIC_ASSERT(audioRust->mRate == audio->mRate);
- MOZ_DIAGNOSTIC_ASSERT(audioRust->mChannels == audio->mChannels);
- MOZ_DIAGNOSTIC_ASSERT(audioRust->mBitDepth == audio->mBitDepth);
- // TODO: These fields aren't implemented in the Rust demuxer yet.
- //MOZ_DIAGNOSTIC_ASSERT(audioRust->mProfile != audio->mProfile);
- //MOZ_DIAGNOSTIC_ASSERT(audioRust->mExtendedProfile != audio->mExtendedProfile);
- break;
- }
- case mozilla::TrackInfo::kVideoTrack: {
- VideoInfo *videoRust = infoRust->GetAsVideoInfo(), *video = info->GetAsVideoInfo();
- MOZ_DIAGNOSTIC_ASSERT(videoRust->mDisplay == video->mDisplay);
- MOZ_DIAGNOSTIC_ASSERT(videoRust->mImage == video->mImage);
- break;
- }
- default:
- break;
- }
- }
-#endif
-
- if (!mPreferRust) {
- return info;
- }
- MOZ_ASSERT(infoRust);
- return infoRust;
-#endif
-
return info;
}
@@ -341,12 +165,6 @@ MP4Metadata::Crypto() const
bool
MP4Metadata::ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
{
-#ifdef MOZ_RUST_MP4PARSE
- if (mRust && mPreferRust && mRust->ReadTrackIndex(aDest, aTrackID)) {
- return true;
- }
- aDest.Clear();
-#endif
return mStagefright->ReadTrackIndex(aDest, aTrackID);
}
@@ -589,292 +407,4 @@ MP4MetadataStagefright::Metadata(Stream* aSource)
return parser->Metadata();
}
-#ifdef MOZ_RUST_MP4PARSE
-bool
-RustStreamAdaptor::Read(uint8_t* buffer, uintptr_t size, size_t* bytes_read)
-{
- if (!mOffset.isValid()) {
- static LazyLogModule sLog("MP4Metadata");
- MOZ_LOG(sLog, LogLevel::Error, ("Overflow in source stream offset"));
- return false;
- }
- bool rv = mSource->ReadAt(mOffset.value(), buffer, size, bytes_read);
- if (rv) {
- mOffset += *bytes_read;
- }
- return rv;
-}
-
-// Wrapper to allow rust to call our read adaptor.
-static intptr_t
-read_source(uint8_t* buffer, uintptr_t size, void* userdata)
-{
- MOZ_ASSERT(buffer);
- MOZ_ASSERT(userdata);
-
- auto source = reinterpret_cast<RustStreamAdaptor*>(userdata);
- size_t bytes_read = 0;
- bool rv = source->Read(buffer, size, &bytes_read);
- if (!rv) {
- static LazyLogModule sLog("MP4Metadata");
- MOZ_LOG(sLog, LogLevel::Warning, ("Error reading source data"));
- return -1;
- }
- return bytes_read;
-}
-
-MP4MetadataRust::MP4MetadataRust(Stream* aSource)
- : mSource(aSource)
- , mRustSource(aSource)
-{
- mp4parse_io io = { read_source, &mRustSource };
- mRustParser.reset(mp4parse_new(&io));
- MOZ_ASSERT(mRustParser);
-
- static LazyLogModule sLog("MP4Metadata");
- mp4parse_error rv = mp4parse_read(mRustParser.get());
- MOZ_LOG(sLog, LogLevel::Debug, ("rust parser returned %d\n", rv));
- Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_SUCCESS,
- rv == MP4PARSE_OK);
- if (rv != MP4PARSE_OK) {
- MOZ_ASSERT(rv > 0);
- Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_ERROR_CODE, rv);
- }
-}
-
-MP4MetadataRust::~MP4MetadataRust()
-{
-}
-
-bool
-TrackTypeEqual(TrackInfo::TrackType aLHS, mp4parse_track_type aRHS)
-{
- switch (aLHS) {
- case TrackInfo::kAudioTrack:
- return aRHS == MP4PARSE_TRACK_TYPE_AUDIO;
- case TrackInfo::kVideoTrack:
- return aRHS == MP4PARSE_TRACK_TYPE_VIDEO;
- default:
- return false;
- }
-}
-
-uint32_t
-MP4MetadataRust::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
-{
- static LazyLogModule sLog("MP4Metadata");
-
- uint32_t tracks;
- auto rv = mp4parse_get_track_count(mRustParser.get(), &tracks);
- if (rv != MP4PARSE_OK) {
- MOZ_LOG(sLog, LogLevel::Warning,
- ("rust parser error %d counting tracks", rv));
- return 0;
- }
- MOZ_LOG(sLog, LogLevel::Info, ("rust parser found %u tracks", tracks));
-
- uint32_t total = 0;
- for (uint32_t i = 0; i < tracks; ++i) {
- mp4parse_track_info track_info;
- rv = mp4parse_get_track_info(mRustParser.get(), i, &track_info);
- if (rv != MP4PARSE_OK) {
- continue;
- }
- if (TrackTypeEqual(aType, track_info.track_type)) {
- total += 1;
- }
- }
-
- return total;
-}
-
-Maybe<uint32_t>
-MP4MetadataRust::TrackTypeToGlobalTrackIndex(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const
-{
- uint32_t tracks;
- auto rv = mp4parse_get_track_count(mRustParser.get(), &tracks);
- if (rv != MP4PARSE_OK) {
- return Nothing();
- }
-
- /* The MP4Metadata API uses a per-TrackType index of tracks, but mp4parse
- (and libstagefright) use a global track index. Convert the index by
- counting the tracks of the requested type and returning the global
- track index when a match is found. */
- uint32_t perType = 0;
- for (uint32_t i = 0; i < tracks; ++i) {
- mp4parse_track_info track_info;
- rv = mp4parse_get_track_info(mRustParser.get(), i, &track_info);
- if (rv != MP4PARSE_OK) {
- continue;
- }
- if (TrackTypeEqual(aType, track_info.track_type)) {
- if (perType == aTrackNumber) {
- return Some(i);
- }
- perType += 1;
- }
- }
-
- return Nothing();
-}
-
-mozilla::UniquePtr<mozilla::TrackInfo>
-MP4MetadataRust::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
- size_t aTrackNumber) const
-{
- static LazyLogModule sLog("MP4Metadata");
-
- Maybe<uint32_t> trackIndex = TrackTypeToGlobalTrackIndex(aType, aTrackNumber);
- if (trackIndex.isNothing()) {
- return nullptr;
- }
-
- mp4parse_track_info info;
- auto rv = mp4parse_get_track_info(mRustParser.get(), trackIndex.value(), &info);
- if (rv != MP4PARSE_OK) {
- MOZ_LOG(sLog, LogLevel::Warning, ("mp4parse_get_track_info returned %d", rv));
- return nullptr;
- }
-#ifdef DEBUG
- const char* codec_string = "unrecognized";
- switch (info.codec) {
- case MP4PARSE_CODEC_UNKNOWN: codec_string = "unknown"; break;
- case MP4PARSE_CODEC_AAC: codec_string = "aac"; break;
- case MP4PARSE_CODEC_OPUS: codec_string = "opus"; break;
- case MP4PARSE_CODEC_FLAC: codec_string = "flac"; break;
- case MP4PARSE_CODEC_AVC: codec_string = "h.264"; break;
- case MP4PARSE_CODEC_VP9: codec_string = "vp9"; break;
- case MP4PARSE_CODEC_MP3: codec_string = "mp3"; break;
- }
- MOZ_LOG(sLog, LogLevel::Debug, ("track codec %s (%u)\n",
- codec_string, info.codec));
-#endif
-
- // This specialization interface is crazy.
- UniquePtr<mozilla::TrackInfo> e;
- switch (aType) {
- case TrackInfo::TrackType::kAudioTrack: {
- mp4parse_track_audio_info audio;
- auto rv = mp4parse_get_track_audio_info(mRustParser.get(), trackIndex.value(), &audio);
- if (rv != MP4PARSE_OK) {
- MOZ_LOG(sLog, LogLevel::Warning, ("mp4parse_get_track_audio_info returned error %d", rv));
- return nullptr;
- }
- auto track = mozilla::MakeUnique<mozilla::AudioInfo>();
- if (info.codec == MP4PARSE_CODEC_OPUS) {
- track->mMimeType = NS_LITERAL_CSTRING("audio/opus");
- // The Opus decoder expects the container's codec delay or
- // pre-skip value, in microseconds, as a 64-bit int at the
- // start of the codec-specific config blob.
- MOZ_ASSERT(audio.codec_specific_config.data);
- MOZ_ASSERT(audio.codec_specific_config.length >= 12);
- uint16_t preskip =
- LittleEndian::readUint16(audio.codec_specific_config.data + 10);
- MOZ_LOG(sLog, LogLevel::Debug,
- ("Copying opus pre-skip value of %d as CodecDelay.",(int)preskip));
- OpusDataDecoder::AppendCodecDelay(track->mCodecSpecificConfig,
- mozilla::FramesToUsecs(preskip, 48000).value());
- } else if (info.codec == MP4PARSE_CODEC_AAC) {
- track->mMimeType = MEDIA_MIMETYPE_AUDIO_AAC;
- } else if (info.codec == MP4PARSE_CODEC_FLAC) {
- track->mMimeType = MEDIA_MIMETYPE_AUDIO_FLAC;
- } else if (info.codec == MP4PARSE_CODEC_MP3) {
- track->mMimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
- }
- track->mCodecSpecificConfig->AppendElements(
- audio.codec_specific_config.data,
- audio.codec_specific_config.length);
- track->mRate = audio.sample_rate;
- track->mChannels = audio.channels;
- track->mBitDepth = audio.bit_depth;
- track->mDuration = info.duration;
- track->mMediaTime = info.media_time;
- track->mTrackId = info.track_id;
- e = Move(track);
- }
- break;
- case TrackInfo::TrackType::kVideoTrack: {
- mp4parse_track_video_info video;
- auto rv = mp4parse_get_track_video_info(mRustParser.get(), trackIndex.value(), &video);
- if (rv != MP4PARSE_OK) {
- MOZ_LOG(sLog, LogLevel::Warning, ("mp4parse_get_track_video_info returned error %d", rv));
- return nullptr;
- }
- auto track = mozilla::MakeUnique<MP4VideoInfo>();
- track->Update(&info, &video);
- e = Move(track);
- }
- break;
- default:
- MOZ_LOG(sLog, LogLevel::Warning, ("unhandled track type %d", aType));
- return nullptr;
- break;
- }
-
- // No duration in track, use fragment_duration.
- if (e && !e->mDuration) {
- mp4parse_fragment_info info;
- auto rv = mp4parse_get_fragment_info(mRustParser.get(), &info);
- if (rv == MP4PARSE_OK) {
- e->mDuration = info.fragment_duration;
- }
- }
-
- if (e && e->IsValid()) {
- return e;
- }
- MOZ_LOG(sLog, LogLevel::Debug, ("TrackInfo didn't validate"));
-
- return nullptr;
-}
-
-bool
-MP4MetadataRust::CanSeek() const
-{
- MOZ_ASSERT(false, "Not yet implemented");
- return false;
-}
-
-const CryptoFile&
-MP4MetadataRust::Crypto() const
-{
- MOZ_ASSERT(false, "Not yet implemented");
- return mCrypto;
-}
-
-bool
-MP4MetadataRust::ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
-{
- uint8_t fragmented = false;
- auto rv = mp4parse_is_fragmented(mRustParser.get(), aTrackID, &fragmented);
- if (rv != MP4PARSE_OK) {
- return false;
- }
-
- if (fragmented) {
- return true;
- }
-
- // For non-fragmented mp4.
- NS_WARNING("Not yet implemented");
-
- return false;
-}
-
-/*static*/ bool
-MP4MetadataRust::HasCompleteMetadata(Stream* aSource)
-{
- MOZ_ASSERT(false, "Not yet implemented");
- return false;
-}
-
-/*static*/ already_AddRefed<mozilla::MediaByteBuffer>
-MP4MetadataRust::Metadata(Stream* aSource)
-{
- MOZ_ASSERT(false, "Not yet implemented");
- return nullptr;
-}
-#endif
-
} // namespace mp4_demuxer
diff --git a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
index 87262c26a..383c4a13c 100644
--- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
@@ -19,14 +19,6 @@ namespace stagefright
class MetaData;
}
-#ifdef MOZ_RUST_MP4PARSE
-extern "C" {
-typedef struct mp4parse_track_info mp4parse_track_info;
-typedef struct mp4parse_track_audio_info mp4parse_track_audio_info;
-typedef struct mp4parse_track_video_info mp4parse_track_video_info;
-}
-#endif
-
namespace mp4_demuxer
{
@@ -80,11 +72,6 @@ public:
void Update(const stagefright::MetaData* aMetaData,
const char* aMimeType);
-#ifdef MOZ_RUST_MP4PARSE
- void Update(const mp4parse_track_info* track,
- const mp4parse_track_video_info* video);
-#endif
-
virtual bool IsValid() const override;
};
diff --git a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
index 83eca69d3..2907f4c45 100644
--- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
@@ -37,16 +37,6 @@ public:
private:
UniquePtr<MP4MetadataStagefright> mStagefright;
-#ifdef MOZ_RUST_MP4PARSE
- UniquePtr<MP4MetadataRust> mRust;
- mutable bool mPreferRust;
- mutable bool mReportedAudioTrackTelemetry;
- mutable bool mReportedVideoTrackTelemetry;
-#ifndef RELEASE_OR_BETA
- mutable bool mRustTestMode;
-#endif
- bool ShouldPreferRust() const;
-#endif
};
} // namespace mp4_demuxer
diff --git a/media/libstagefright/binding/include/mp4parse.h b/media/libstagefright/binding/include/mp4parse.h
deleted file mode 100644
index 6650661cb..000000000
--- a/media/libstagefright/binding/include/mp4parse.h
+++ /dev/null
@@ -1,113 +0,0 @@
-
-#ifndef cheddar_generated_mp4parse_h
-#define cheddar_generated_mp4parse_h
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <stdbool.h>
-
-// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT
-
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-typedef enum mp4parse_error {
- MP4PARSE_OK = 0,
- MP4PARSE_ERROR_BADARG = 1,
- MP4PARSE_ERROR_INVALID = 2,
- MP4PARSE_ERROR_UNSUPPORTED = 3,
- MP4PARSE_ERROR_EOF = 4,
- MP4PARSE_ERROR_IO = 5,
-} mp4parse_error;
-
-typedef enum mp4parse_track_type {
- MP4PARSE_TRACK_TYPE_VIDEO = 0,
- MP4PARSE_TRACK_TYPE_AUDIO = 1,
-} mp4parse_track_type;
-
-typedef enum mp4parse_codec {
- MP4PARSE_CODEC_UNKNOWN,
- MP4PARSE_CODEC_AAC,
- MP4PARSE_CODEC_FLAC,
- MP4PARSE_CODEC_OPUS,
- MP4PARSE_CODEC_AVC,
- MP4PARSE_CODEC_VP9,
- MP4PARSE_CODEC_MP3,
-} mp4parse_codec;
-
-typedef struct mp4parse_track_info {
- mp4parse_track_type track_type;
- mp4parse_codec codec;
- uint32_t track_id;
- uint64_t duration;
- int64_t media_time;
-} mp4parse_track_info;
-
-typedef struct mp4parse_codec_specific_config {
- uint32_t length;
- uint8_t const* data;
-} mp4parse_codec_specific_config;
-
-typedef struct mp4parse_track_audio_info {
- uint16_t channels;
- uint16_t bit_depth;
- uint32_t sample_rate;
- mp4parse_codec_specific_config codec_specific_config;
-} mp4parse_track_audio_info;
-
-typedef struct mp4parse_track_video_info {
- uint32_t display_width;
- uint32_t display_height;
- uint16_t image_width;
- uint16_t image_height;
-} mp4parse_track_video_info;
-
-typedef struct mp4parse_fragment_info {
- uint64_t fragment_duration;
-} mp4parse_fragment_info;
-
-typedef struct mp4parse_parser mp4parse_parser;
-
-typedef struct mp4parse_io {
- intptr_t (*read)(uint8_t* buffer, uintptr_t size, void* userdata);
- void* userdata;
-} mp4parse_io;
-
-/// Allocate an `mp4parse_parser*` to read from the supplied `mp4parse_io`.
-mp4parse_parser* mp4parse_new(mp4parse_io const* io);
-
-/// Free an `mp4parse_parser*` allocated by `mp4parse_new()`.
-void mp4parse_free(mp4parse_parser* parser);
-
-/// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
-mp4parse_error mp4parse_read(mp4parse_parser* parser);
-
-/// Return the number of tracks parsed by previous `mp4parse_read()` call.
-mp4parse_error mp4parse_get_track_count(mp4parse_parser const* parser, uint32_t* count);
-
-/// Fill the supplied `mp4parse_track_info` with metadata for `track`.
-mp4parse_error mp4parse_get_track_info(mp4parse_parser* parser, uint32_t track_index, mp4parse_track_info* info);
-
-/// Fill the supplied `mp4parse_track_audio_info` with metadata for `track`.
-mp4parse_error mp4parse_get_track_audio_info(mp4parse_parser* parser, uint32_t track_index, mp4parse_track_audio_info* info);
-
-/// Fill the supplied `mp4parse_track_video_info` with metadata for `track`.
-mp4parse_error mp4parse_get_track_video_info(mp4parse_parser* parser, uint32_t track_index, mp4parse_track_video_info* info);
-
-mp4parse_error mp4parse_get_fragment_info(mp4parse_parser* parser, mp4parse_fragment_info* info);
-
-mp4parse_error mp4parse_is_fragmented(mp4parse_parser* parser, uint32_t track_id, uint8_t* fragmented);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
diff --git a/media/libstagefright/binding/mp4parse-cargo.patch b/media/libstagefright/binding/mp4parse-cargo.patch
deleted file mode 100644
index 9b0ca7134..000000000
--- a/media/libstagefright/binding/mp4parse-cargo.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-diff --git a/media/libstagefright/binding/mp4parse/Cargo.toml b/media/libstagefright/binding/mp4parse/Cargo.toml
-index ff9422c..814c4c6 100644
---- a/media/libstagefright/binding/mp4parse/Cargo.toml
-+++ b/media/libstagefright/binding/mp4parse/Cargo.toml
-@@ -18,17 +18,11 @@ exclude = [
- ]
-
- [dependencies]
--byteorder = "0.5.0"
--afl = { version = "0.1.1", optional = true }
--afl-plugin = { version = "0.1.1", optional = true }
--abort_on_panic = { version = "1.0.0", optional = true }
-+byteorder = "0.5.0"
-
- [dev-dependencies]
- test-assembler = "0.1.2"
-
--[features]
--fuzz = ["afl", "afl-plugin", "abort_on_panic"]
--
- # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
- [profile.release]
- debug-assertions = true
-diff --git a/media/libstagefright/binding/mp4parse_capi/Cargo.toml b/media/libstagefright/binding/mp4parse_capi/Cargo.toml
-index aeeebc65..5c0836a 100644
---- a/media/libstagefright/binding/mp4parse_capi/Cargo.toml
-+++ b/media/libstagefright/binding/mp4parse_capi/Cargo.toml
-@@ -18,17 +18,9 @@ exclude = [
- "*.mp4",
- ]
-
--build = "build.rs"
--
- [dependencies]
- "mp4parse" = {version = "0.6.0", path = "../mp4parse"}
-
--[build-dependencies]
--rusty-cheddar = "0.3.2"
--
--[features]
--fuzz = ["mp4parse/fuzz"]
--
- # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
- [profile.release]
- debug-assertions = true
diff --git a/media/libstagefright/binding/mp4parse/Cargo.toml b/media/libstagefright/binding/mp4parse/Cargo.toml
deleted file mode 100644
index affcef72b..000000000
--- a/media/libstagefright/binding/mp4parse/Cargo.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[package]
-name = "mp4parse"
-version = "0.6.0"
-authors = [
- "Ralph Giles <giles@mozilla.com>",
- "Matthew Gregan <kinetik@flim.org>",
- "Alfredo Yang <ayang@mozilla.com>",
-]
-
-description = "Parser for ISO base media file format (mp4)"
-documentation = "https://mp4parse-docs.surge.sh/mp4parse/"
-license = "MPL-2.0"
-
-repository = "https://github.com/mozilla/mp4parse-rust"
-
-# Avoid complaints about trying to package test files.
-exclude = [
- "*.mp4",
-]
-
-[dependencies]
-byteorder = "0.5.0"
-
-[dev-dependencies]
-test-assembler = "0.1.2"
-
-# Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
-[profile.release]
-debug-assertions = true
diff --git a/media/libstagefright/binding/mp4parse/src/boxes.rs b/media/libstagefright/binding/mp4parse/src/boxes.rs
deleted file mode 100644
index 689439ade..000000000
--- a/media/libstagefright/binding/mp4parse/src/boxes.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-macro_rules! box_database {
- ($($boxenum:ident $boxtype:expr),*,) => {
- #[derive(Debug, Clone, Copy, PartialEq)]
- pub enum BoxType {
- $($boxenum),*,
- UnknownBox(u32),
- }
-
- impl From<u32> for BoxType {
- fn from(t: u32) -> BoxType {
- use self::BoxType::*;
- match t {
- $($boxtype => $boxenum),*,
- _ => UnknownBox(t),
- }
- }
- }
- }
-}
-
-box_database!(
- FileTypeBox 0x66747970, // "ftyp"
- MovieBox 0x6d6f6f76, // "moov"
- MovieHeaderBox 0x6d766864, // "mvhd"
- TrackBox 0x7472616b, // "trak"
- TrackHeaderBox 0x746b6864, // "tkhd"
- EditBox 0x65647473, // "edts"
- MediaBox 0x6d646961, // "mdia"
- EditListBox 0x656c7374, // "elst"
- MediaHeaderBox 0x6d646864, // "mdhd"
- HandlerBox 0x68646c72, // "hdlr"
- MediaInformationBox 0x6d696e66, // "minf"
- SampleTableBox 0x7374626c, // "stbl"
- SampleDescriptionBox 0x73747364, // "stsd"
- TimeToSampleBox 0x73747473, // "stts"
- SampleToChunkBox 0x73747363, // "stsc"
- SampleSizeBox 0x7374737a, // "stsz"
- ChunkOffsetBox 0x7374636f, // "stco"
- ChunkLargeOffsetBox 0x636f3634, // "co64"
- SyncSampleBox 0x73747373, // "stss"
- AVCSampleEntry 0x61766331, // "avc1"
- AVC3SampleEntry 0x61766333, // "avc3" - Need to check official name in spec.
- AVCConfigurationBox 0x61766343, // "avcC"
- MP4AudioSampleEntry 0x6d703461, // "mp4a"
- ESDBox 0x65736473, // "esds"
- VP8SampleEntry 0x76703038, // "vp08"
- VP9SampleEntry 0x76703039, // "vp09"
- VPCodecConfigurationBox 0x76706343, // "vpcC"
- FLACSampleEntry 0x664c6143, // "fLaC"
- FLACSpecificBox 0x64664c61, // "dfLa"
- OpusSampleEntry 0x4f707573, // "Opus"
- OpusSpecificBox 0x644f7073, // "dOps"
- ProtectedVisualSampleEntry 0x656e6376, // "encv" - Need to check official name in spec.
- ProtectedAudioSampleEntry 0x656e6361, // "enca" - Need to check official name in spec.
- MovieExtendsBox 0x6d766578, // "mvex"
- MovieExtendsHeaderBox 0x6d656864, // "mehd"
- QTWaveAtom 0x77617665, // "wave" - quicktime atom
-);
diff --git a/media/libstagefright/binding/mp4parse/src/lib.rs b/media/libstagefright/binding/mp4parse/src/lib.rs
deleted file mode 100644
index 37606a5e2..000000000
--- a/media/libstagefright/binding/mp4parse/src/lib.rs
+++ /dev/null
@@ -1,1704 +0,0 @@
-//! Module for parsing ISO Base Media Format aka video/mp4 streams.
-
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-#![cfg_attr(feature = "fuzz", feature(plugin))]
-#![cfg_attr(feature = "fuzz", plugin(afl_plugin))]
-#[cfg(feature = "fuzz")]
-extern crate afl;
-
-extern crate byteorder;
-use byteorder::ReadBytesExt;
-use std::io::{Read, Take};
-use std::io::Cursor;
-use std::cmp;
-
-mod boxes;
-use boxes::BoxType;
-
-// Unit tests.
-#[cfg(test)]
-mod tests;
-
-// Arbitrary buffer size limit used for raw read_bufs on a box.
-const BUF_SIZE_LIMIT: u64 = 1024 * 1024;
-
-static DEBUG_MODE: std::sync::atomic::AtomicBool = std::sync::atomic::ATOMIC_BOOL_INIT;
-
-pub fn set_debug_mode(mode: bool) {
- DEBUG_MODE.store(mode, std::sync::atomic::Ordering::SeqCst);
-}
-
-#[inline(always)]
-fn get_debug_mode() -> bool {
- DEBUG_MODE.load(std::sync::atomic::Ordering::Relaxed)
-}
-
-macro_rules! log {
- ($($args:tt)*) => (
- if get_debug_mode() {
- println!( $( $args )* );
- }
- )
-}
-
-/// Describes parser failures.
-///
-/// This enum wraps the standard `io::Error` type, unified with
-/// our own parser error states and those of crates we use.
-#[derive(Debug)]
-pub enum Error {
- /// Parse error caused by corrupt or malformed data.
- InvalidData(&'static str),
- /// Parse error caused by limited parser support rather than invalid data.
- Unsupported(&'static str),
- /// Reflect `std::io::ErrorKind::UnexpectedEof` for short data.
- UnexpectedEOF,
- /// Propagate underlying errors from `std::io`.
- Io(std::io::Error),
- /// read_mp4 terminated without detecting a moov box.
- NoMoov,
-}
-
-impl From<std::io::Error> for Error {
- fn from(err: std::io::Error) -> Error {
- match err.kind() {
- std::io::ErrorKind::UnexpectedEof => Error::UnexpectedEOF,
- _ => Error::Io(err),
- }
- }
-}
-
-impl From<std::string::FromUtf8Error> for Error {
- fn from(_: std::string::FromUtf8Error) -> Error {
- Error::InvalidData("invalid utf8")
- }
-}
-
-/// Result shorthand using our Error enum.
-pub type Result<T> = std::result::Result<T, Error>;
-
-/// Basic ISO box structure.
-///
-/// mp4 files are a sequence of possibly-nested 'box' structures. Each box
-/// begins with a header describing the length of the box's data and a
-/// four-byte box type which identifies the type of the box. Together these
-/// are enough to interpret the contents of that section of the file.
-#[derive(Debug, Clone, Copy)]
-struct BoxHeader {
- /// Box type.
- name: BoxType,
- /// Size of the box in bytes.
- size: u64,
- /// Offset to the start of the contained data (or header size).
- offset: u64,
-}
-
-/// File type box 'ftyp'.
-#[derive(Debug)]
-struct FileTypeBox {
- major_brand: u32,
- minor_version: u32,
- compatible_brands: Vec<u32>,
-}
-
-/// Movie header box 'mvhd'.
-#[derive(Debug)]
-struct MovieHeaderBox {
- pub timescale: u32,
- duration: u64,
-}
-
-/// Track header box 'tkhd'
-#[derive(Debug, Clone)]
-pub struct TrackHeaderBox {
- track_id: u32,
- pub disabled: bool,
- pub duration: u64,
- pub width: u32,
- pub height: u32,
-}
-
-/// Edit list box 'elst'
-#[derive(Debug)]
-struct EditListBox {
- edits: Vec<Edit>,
-}
-
-#[derive(Debug)]
-struct Edit {
- segment_duration: u64,
- media_time: i64,
- media_rate_integer: i16,
- media_rate_fraction: i16,
-}
-
-/// Media header box 'mdhd'
-#[derive(Debug)]
-struct MediaHeaderBox {
- timescale: u32,
- duration: u64,
-}
-
-// Chunk offset box 'stco' or 'co64'
-#[derive(Debug)]
-struct ChunkOffsetBox {
- offsets: Vec<u64>,
-}
-
-// Sync sample box 'stss'
-#[derive(Debug)]
-struct SyncSampleBox {
- samples: Vec<u32>,
-}
-
-// Sample to chunk box 'stsc'
-#[derive(Debug)]
-struct SampleToChunkBox {
- samples: Vec<SampleToChunk>,
-}
-
-#[derive(Debug)]
-struct SampleToChunk {
- first_chunk: u32,
- samples_per_chunk: u32,
- sample_description_index: u32,
-}
-
-// Sample size box 'stsz'
-#[derive(Debug)]
-struct SampleSizeBox {
- sample_size: u32,
- sample_sizes: Vec<u32>,
-}
-
-// Time to sample box 'stts'
-#[derive(Debug)]
-struct TimeToSampleBox {
- samples: Vec<Sample>,
-}
-
-#[derive(Debug)]
-struct Sample {
- sample_count: u32,
- sample_delta: u32,
-}
-
-// Handler reference box 'hdlr'
-#[derive(Debug)]
-struct HandlerBox {
- handler_type: u32,
-}
-
-// Sample description box 'stsd'
-#[derive(Debug)]
-struct SampleDescriptionBox {
- descriptions: Vec<SampleEntry>,
-}
-
-#[derive(Debug, Clone)]
-pub enum SampleEntry {
- Audio(AudioSampleEntry),
- Video(VideoSampleEntry),
- Unknown,
-}
-
-#[allow(non_camel_case_types)]
-#[derive(Debug, Clone)]
-pub struct ES_Descriptor {
- pub audio_codec: CodecType,
- pub audio_sample_rate: Option<u32>,
- pub audio_channel_count: Option<u16>,
- pub codec_specific_config: Vec<u8>,
-}
-
-#[allow(non_camel_case_types)]
-#[derive(Debug, Clone)]
-pub enum AudioCodecSpecific {
- ES_Descriptor(ES_Descriptor),
- FLACSpecificBox(FLACSpecificBox),
- OpusSpecificBox(OpusSpecificBox),
-}
-
-#[derive(Debug, Clone)]
-pub struct AudioSampleEntry {
- data_reference_index: u16,
- pub channelcount: u16,
- pub samplesize: u16,
- pub samplerate: u32,
- pub codec_specific: AudioCodecSpecific,
-}
-
-#[derive(Debug, Clone)]
-pub enum VideoCodecSpecific {
- AVCConfig(Vec<u8>),
- VPxConfig(VPxConfigBox),
-}
-
-#[derive(Debug, Clone)]
-pub struct VideoSampleEntry {
- data_reference_index: u16,
- pub width: u16,
- pub height: u16,
- pub codec_specific: VideoCodecSpecific,
-}
-
-/// Represent a Video Partition Codec Configuration 'vpcC' box (aka vp9).
-#[derive(Debug, Clone)]
-pub struct VPxConfigBox {
- profile: u8,
- level: u8,
- pub bit_depth: u8,
- pub color_space: u8, // Really an enum
- pub chroma_subsampling: u8,
- transfer_function: u8,
- video_full_range: bool,
- pub codec_init: Vec<u8>, // Empty for vp8/vp9.
-}
-
-#[derive(Debug, Clone)]
-pub struct FLACMetadataBlock {
- pub block_type: u8,
- pub data: Vec<u8>,
-}
-
-/// Represet a FLACSpecificBox 'dfLa'
-#[derive(Debug, Clone)]
-pub struct FLACSpecificBox {
- version: u8,
- pub blocks: Vec<FLACMetadataBlock>,
-}
-
-#[derive(Debug, Clone)]
-struct ChannelMappingTable {
- stream_count: u8,
- coupled_count: u8,
- channel_mapping: Vec<u8>,
-}
-
-/// Represent an OpusSpecificBox 'dOps'
-#[derive(Debug, Clone)]
-pub struct OpusSpecificBox {
- pub version: u8,
- output_channel_count: u8,
- pre_skip: u16,
- input_sample_rate: u32,
- output_gain: i16,
- channel_mapping_family: u8,
- channel_mapping_table: Option<ChannelMappingTable>,
-}
-
-#[derive(Debug)]
-pub struct MovieExtendsBox {
- pub fragment_duration: Option<MediaScaledTime>,
-}
-
-/// Internal data structures.
-#[derive(Debug, Default)]
-pub struct MediaContext {
- pub timescale: Option<MediaTimeScale>,
- /// Tracks found in the file.
- pub tracks: Vec<Track>,
- pub mvex: Option<MovieExtendsBox>,
-}
-
-impl MediaContext {
- pub fn new() -> MediaContext {
- Default::default()
- }
-}
-
-#[derive(Debug, PartialEq)]
-pub enum TrackType {
- Audio,
- Video,
- Unknown,
-}
-
-impl Default for TrackType {
- fn default() -> Self { TrackType::Unknown }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum CodecType {
- Unknown,
- MP3,
- AAC,
- FLAC,
- Opus,
- H264,
- VP9,
- VP8,
- EncryptedVideo,
- EncryptedAudio,
-}
-
-impl Default for CodecType {
- fn default() -> Self { CodecType::Unknown }
-}
-
-/// The media's global (mvhd) timescale in units per second.
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct MediaTimeScale(pub u64);
-
-/// A time to be scaled by the media's global (mvhd) timescale.
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct MediaScaledTime(pub u64);
-
-/// The track's local (mdhd) timescale.
-/// Members are timescale units per second and the track id.
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct TrackTimeScale(pub u64, pub usize);
-
-/// A time to be scaled by the track's local (mdhd) timescale.
-/// Members are time in scale units and the track id.
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct TrackScaledTime(pub u64, pub usize);
-
-/// A fragmented file contains no sample data in stts, stsc, and stco.
-#[derive(Debug, Default)]
-pub struct EmptySampleTableBoxes {
- pub empty_stts : bool,
- pub empty_stsc : bool,
- pub empty_stco : bool,
-}
-
-/// Check boxes contain data.
-impl EmptySampleTableBoxes {
- pub fn all_empty(&self) -> bool {
- self.empty_stts & self.empty_stsc & self.empty_stco
- }
-}
-
-#[derive(Debug, Default)]
-pub struct Track {
- id: usize,
- pub track_type: TrackType,
- pub empty_duration: Option<MediaScaledTime>,
- pub media_time: Option<TrackScaledTime>,
- pub timescale: Option<TrackTimeScale>,
- pub duration: Option<TrackScaledTime>,
- pub track_id: Option<u32>,
- pub codec_type: CodecType,
- pub empty_sample_boxes: EmptySampleTableBoxes,
- pub data: Option<SampleEntry>,
- pub tkhd: Option<TrackHeaderBox>, // TODO(kinetik): find a nicer way to export this.
-}
-
-impl Track {
- fn new(id: usize) -> Track {
- Track { id: id, ..Default::default() }
- }
-}
-
-struct BMFFBox<'a, T: 'a + Read> {
- head: BoxHeader,
- content: Take<&'a mut T>,
-}
-
-struct BoxIter<'a, T: 'a + Read> {
- src: &'a mut T,
-}
-
-impl<'a, T: Read> BoxIter<'a, T> {
- fn new(src: &mut T) -> BoxIter<T> {
- BoxIter { src: src }
- }
-
- fn next_box(&mut self) -> Result<Option<BMFFBox<T>>> {
- let r = read_box_header(self.src);
- match r {
- Ok(h) => Ok(Some(BMFFBox {
- head: h,
- content: self.src.take(h.size - h.offset),
- })),
- Err(Error::UnexpectedEOF) => Ok(None),
- Err(e) => Err(e),
- }
- }
-}
-
-impl<'a, T: Read> Read for BMFFBox<'a, T> {
- fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- self.content.read(buf)
- }
-}
-
-impl<'a, T: Read> BMFFBox<'a, T> {
- fn bytes_left(&self) -> usize {
- self.content.limit() as usize
- }
-
- fn get_header(&self) -> &BoxHeader {
- &self.head
- }
-
- fn box_iter<'b>(&'b mut self) -> BoxIter<BMFFBox<'a, T>> {
- BoxIter::new(self)
- }
-}
-
-/// Read and parse a box header.
-///
-/// Call this first to determine the type of a particular mp4 box
-/// and its length. Used internally for dispatching to specific
-/// parsers for the internal content, or to get the length to
-/// skip unknown or uninteresting boxes.
-fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
- let size32 = try!(be_u32(src));
- let name = BoxType::from(try!(be_u32(src)));
- let size = match size32 {
- // valid only for top-level box and indicates it's the last box in the file. usually mdat.
- 0 => return Err(Error::Unsupported("unknown sized box")),
- 1 => {
- let size64 = try!(be_u64(src));
- if size64 < 16 {
- return Err(Error::InvalidData("malformed wide size"));
- }
- size64
- }
- 2...7 => return Err(Error::InvalidData("malformed size")),
- _ => size32 as u64,
- };
- let offset = match size32 {
- 1 => 4 + 4 + 8,
- _ => 4 + 4,
- };
- assert!(offset <= size);
- Ok(BoxHeader {
- name: name,
- size: size,
- offset: offset,
- })
-}
-
-/// Parse the extra header fields for a full box.
-fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> Result<(u8, u32)> {
- let version = try!(src.read_u8());
- let flags_a = try!(src.read_u8());
- let flags_b = try!(src.read_u8());
- let flags_c = try!(src.read_u8());
- Ok((version,
- (flags_a as u32) << 16 | (flags_b as u32) << 8 | (flags_c as u32)))
-}
-
-/// Skip over the entire contents of a box.
-fn skip_box_content<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
- // Skip the contents of unknown chunks.
- let to_skip = {
- let header = src.get_header();
- log!("{:?} (skipped)", header);
- (header.size - header.offset) as usize
- };
- assert!(to_skip == src.bytes_left());
- skip(src, to_skip)
-}
-
-/// Skip over the remain data of a box.
-fn skip_box_remain<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
- let remain = {
- let header = src.get_header();
- let len = src.bytes_left();
- log!("remain {} (skipped) in {:?}", len, header);
- len
- };
- skip(src, remain)
-}
-
-macro_rules! check_parser_state {
- ( $src:expr ) => {
- if $src.limit() > 0 {
- log!("bad parser state: {} content bytes left", $src.limit());
- return Err(Error::InvalidData("unread box content or bad parser sync"));
- }
- }
-}
-
-/// Read the contents of a box, including sub boxes.
-///
-/// Metadata is accumulated in the passed-through `MediaContext` struct,
-/// which can be examined later.
-pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
- let mut found_ftyp = false;
- let mut found_moov = false;
- // TODO(kinetik): Top-level parsing should handle zero-sized boxes
- // rather than throwing an error.
- let mut iter = BoxIter::new(f);
- while let Some(mut b) = try!(iter.next_box()) {
- // box ordering: ftyp before any variable length box (inc. moov),
- // but may not be first box in file if file signatures etc. present
- // fragmented mp4 order: ftyp, moov, pairs of moof/mdat (1-multiple), mfra
-
- // "special": uuid, wide (= 8 bytes)
- // isom: moov, mdat, free, skip, udta, ftyp, moof, mfra
- // iso2: pdin, meta
- // iso3: meco
- // iso5: styp, sidx, ssix, prft
- // unknown, maybe: id32
-
- // qt: pnot
-
- // possibly allow anything where all printable and/or all lowercase printable
- // "four printable characters from the ISO 8859-1 character set"
- match b.head.name {
- BoxType::FileTypeBox => {
- let ftyp = try!(read_ftyp(&mut b));
- found_ftyp = true;
- log!("{:?}", ftyp);
- }
- BoxType::MovieBox => {
- try!(read_moov(&mut b, context));
- found_moov = true;
- }
- _ => try!(skip_box_content(&mut b)),
- };
- check_parser_state!(b.content);
- if found_moov {
- log!("found moov {}, could stop pure 'moov' parser now", if found_ftyp {
- "and ftyp"
- } else {
- "but no ftyp"
- });
- }
- }
-
- // XXX(kinetik): This isn't perfect, as a "moov" with no contents is
- // treated as okay but we haven't found anything useful. Needs more
- // thought for clearer behaviour here.
- if found_moov {
- Ok(())
- } else {
- Err(Error::NoMoov)
- }
-}
-
-fn parse_mvhd<T: Read>(f: &mut BMFFBox<T>) -> Result<(MovieHeaderBox, Option<MediaTimeScale>)> {
- let mvhd = try!(read_mvhd(f));
- if mvhd.timescale == 0 {
- return Err(Error::InvalidData("zero timescale in mdhd"));
- }
- let timescale = Some(MediaTimeScale(mvhd.timescale as u64));
- Ok((mvhd, timescale))
-}
-
-fn read_moov<T: Read>(f: &mut BMFFBox<T>, context: &mut MediaContext) -> Result<()> {
- let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::MovieHeaderBox => {
- let (mvhd, timescale) = try!(parse_mvhd(&mut b));
- context.timescale = timescale;
- log!("{:?}", mvhd);
- }
- BoxType::TrackBox => {
- let mut track = Track::new(context.tracks.len());
- try!(read_trak(&mut b, &mut track));
- context.tracks.push(track);
- }
- BoxType::MovieExtendsBox => {
- let mvex = try!(read_mvex(&mut b));
- log!("{:?}", mvex);
- context.mvex = Some(mvex);
- }
- _ => try!(skip_box_content(&mut b)),
- };
- check_parser_state!(b.content);
- }
- Ok(())
-}
-
-fn read_mvex<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieExtendsBox> {
- let mut iter = src.box_iter();
- let mut fragment_duration = None;
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::MovieExtendsHeaderBox => {
- let duration = try!(read_mehd(&mut b));
- fragment_duration = Some(duration);
- },
- _ => try!(skip_box_content(&mut b)),
- }
- }
- Ok(MovieExtendsBox {
- fragment_duration: fragment_duration,
- })
-}
-
-fn read_mehd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaScaledTime> {
- let (version, _) = try!(read_fullbox_extra(src));
- let fragment_duration = match version {
- 1 => try!(be_u64(src)),
- 0 => try!(be_u32(src)) as u64,
- _ => return Err(Error::InvalidData("unhandled mehd version")),
- };
- Ok(MediaScaledTime(fragment_duration))
-}
-
-fn read_trak<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
- let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::TrackHeaderBox => {
- let tkhd = try!(read_tkhd(&mut b));
- track.track_id = Some(tkhd.track_id);
- track.tkhd = Some(tkhd.clone());
- log!("{:?}", tkhd);
- }
- BoxType::EditBox => try!(read_edts(&mut b, track)),
- BoxType::MediaBox => try!(read_mdia(&mut b, track)),
- _ => try!(skip_box_content(&mut b)),
- };
- check_parser_state!(b.content);
- }
- Ok(())
-}
-
-fn read_edts<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
- let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::EditListBox => {
- let elst = try!(read_elst(&mut b));
- let mut empty_duration = 0;
- let mut idx = 0;
- if elst.edits.len() > 2 {
- return Err(Error::Unsupported("more than two edits"));
- }
- if elst.edits[idx].media_time == -1 {
- empty_duration = elst.edits[idx].segment_duration;
- if elst.edits.len() < 2 {
- return Err(Error::InvalidData("expected additional edit"));
- }
- idx += 1;
- }
- track.empty_duration = Some(MediaScaledTime(empty_duration));
- if elst.edits[idx].media_time < 0 {
- return Err(Error::InvalidData("unexpected negative media time in edit"));
- }
- track.media_time = Some(TrackScaledTime(elst.edits[idx].media_time as u64,
- track.id));
- log!("{:?}", elst);
- }
- _ => try!(skip_box_content(&mut b)),
- };
- check_parser_state!(b.content);
- }
- Ok(())
-}
-
-fn parse_mdhd<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<(MediaHeaderBox, Option<TrackScaledTime>, Option<TrackTimeScale>)> {
- let mdhd = try!(read_mdhd(f));
- let duration = match mdhd.duration {
- std::u64::MAX => None,
- duration => Some(TrackScaledTime(duration, track.id)),
- };
- if mdhd.timescale == 0 {
- return Err(Error::InvalidData("zero timescale in mdhd"));
- }
- let timescale = Some(TrackTimeScale(mdhd.timescale as u64, track.id));
- Ok((mdhd, duration, timescale))
-}
-
-fn read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
- let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::MediaHeaderBox => {
- let (mdhd, duration, timescale) = try!(parse_mdhd(&mut b, track));
- track.duration = duration;
- track.timescale = timescale;
- log!("{:?}", mdhd);
- }
- BoxType::HandlerBox => {
- let hdlr = try!(read_hdlr(&mut b));
- match hdlr.handler_type {
- 0x76696465 /* 'vide' */ => track.track_type = TrackType::Video,
- 0x736f756e /* 'soun' */ => track.track_type = TrackType::Audio,
- _ => (),
- }
- log!("{:?}", hdlr);
- }
- BoxType::MediaInformationBox => try!(read_minf(&mut b, track)),
- _ => try!(skip_box_content(&mut b)),
- };
- check_parser_state!(b.content);
- }
- Ok(())
-}
-
-fn read_minf<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
- let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::SampleTableBox => try!(read_stbl(&mut b, track)),
- _ => try!(skip_box_content(&mut b)),
- };
- check_parser_state!(b.content);
- }
- Ok(())
-}
-
-fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
- let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::SampleDescriptionBox => {
- let stsd = try!(read_stsd(&mut b, track));
- log!("{:?}", stsd);
- }
- BoxType::TimeToSampleBox => {
- let stts = try!(read_stts(&mut b));
- track.empty_sample_boxes.empty_stts = stts.samples.is_empty();
- log!("{:?}", stts);
- }
- BoxType::SampleToChunkBox => {
- let stsc = try!(read_stsc(&mut b));
- track.empty_sample_boxes.empty_stsc = stsc.samples.is_empty();
- log!("{:?}", stsc);
- }
- BoxType::SampleSizeBox => {
- let stsz = try!(read_stsz(&mut b));
- log!("{:?}", stsz);
- }
- BoxType::ChunkOffsetBox => {
- let stco = try!(read_stco(&mut b));
- track.empty_sample_boxes.empty_stco = stco.offsets.is_empty();
- log!("{:?}", stco);
- }
- BoxType::ChunkLargeOffsetBox => {
- let co64 = try!(read_co64(&mut b));
- log!("{:?}", co64);
- }
- BoxType::SyncSampleBox => {
- let stss = try!(read_stss(&mut b));
- log!("{:?}", stss);
- }
- _ => try!(skip_box_content(&mut b)),
- };
- check_parser_state!(b.content);
- }
- Ok(())
-}
-
-/// Parse an ftyp box.
-fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
- let major = try!(be_u32(src));
- let minor = try!(be_u32(src));
- let bytes_left = src.bytes_left();
- if bytes_left % 4 != 0 {
- return Err(Error::InvalidData("invalid ftyp size"));
- }
- // Is a brand_count of zero valid?
- let brand_count = bytes_left / 4;
- let mut brands = Vec::new();
- for _ in 0..brand_count {
- brands.push(try!(be_u32(src)));
- }
- Ok(FileTypeBox {
- major_brand: major,
- minor_version: minor,
- compatible_brands: brands,
- })
-}
-
-/// Parse an mvhd box.
-fn read_mvhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieHeaderBox> {
- let (version, _) = try!(read_fullbox_extra(src));
- match version {
- // 64 bit creation and modification times.
- 1 => {
- try!(skip(src, 16));
- }
- // 32 bit creation and modification times.
- 0 => {
- try!(skip(src, 8));
- }
- _ => return Err(Error::InvalidData("unhandled mvhd version")),
- }
- let timescale = try!(be_u32(src));
- let duration = match version {
- 1 => try!(be_u64(src)),
- 0 => {
- let d = try!(be_u32(src));
- if d == std::u32::MAX {
- std::u64::MAX
- } else {
- d as u64
- }
- }
- _ => return Err(Error::InvalidData("unhandled mvhd version")),
- };
- // Skip remaining fields.
- try!(skip(src, 80));
- Ok(MovieHeaderBox {
- timescale: timescale,
- duration: duration,
- })
-}
-
-/// Parse a tkhd box.
-fn read_tkhd<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox> {
- let (version, flags) = try!(read_fullbox_extra(src));
- let disabled = flags & 0x1u32 == 0 || flags & 0x2u32 == 0;
- match version {
- // 64 bit creation and modification times.
- 1 => {
- try!(skip(src, 16));
- }
- // 32 bit creation and modification times.
- 0 => {
- try!(skip(src, 8));
- }
- _ => return Err(Error::InvalidData("unhandled tkhd version")),
- }
- let track_id = try!(be_u32(src));
- try!(skip(src, 4));
- let duration = match version {
- 1 => try!(be_u64(src)),
- 0 => try!(be_u32(src)) as u64,
- _ => return Err(Error::InvalidData("unhandled tkhd version")),
- };
- // Skip uninteresting fields.
- try!(skip(src, 52));
- let width = try!(be_u32(src));
- let height = try!(be_u32(src));
- Ok(TrackHeaderBox {
- track_id: track_id,
- disabled: disabled,
- duration: duration,
- width: width,
- height: height,
- })
-}
-
-/// Parse a elst box.
-fn read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox> {
- let (version, _) = try!(read_fullbox_extra(src));
- let edit_count = try!(be_u32(src));
- if edit_count == 0 {
- return Err(Error::InvalidData("invalid edit count"));
- }
- let mut edits = Vec::new();
- for _ in 0..edit_count {
- let (segment_duration, media_time) = match version {
- 1 => {
- // 64 bit segment duration and media times.
- (try!(be_u64(src)), try!(be_i64(src)))
- }
- 0 => {
- // 32 bit segment duration and media times.
- (try!(be_u32(src)) as u64, try!(be_i32(src)) as i64)
- }
- _ => return Err(Error::InvalidData("unhandled elst version")),
- };
- let media_rate_integer = try!(be_i16(src));
- let media_rate_fraction = try!(be_i16(src));
- edits.push(Edit {
- segment_duration: segment_duration,
- media_time: media_time,
- media_rate_integer: media_rate_integer,
- media_rate_fraction: media_rate_fraction,
- })
- }
-
- Ok(EditListBox {
- edits: edits,
- })
-}
-
-/// Parse a mdhd box.
-fn read_mdhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox> {
- let (version, _) = try!(read_fullbox_extra(src));
- let (timescale, duration) = match version {
- 1 => {
- // Skip 64-bit creation and modification times.
- try!(skip(src, 16));
-
- // 64 bit duration.
- (try!(be_u32(src)), try!(be_u64(src)))
- }
- 0 => {
- // Skip 32-bit creation and modification times.
- try!(skip(src, 8));
-
- // 32 bit duration.
- let timescale = try!(be_u32(src));
- let duration = {
- // Since we convert the 32-bit duration to 64-bit by
- // upcasting, we need to preserve the special all-1s
- // ("unknown") case by hand.
- let d = try!(be_u32(src));
- if d == std::u32::MAX {
- std::u64::MAX
- } else {
- d as u64
- }
- };
- (timescale, duration)
- }
- _ => return Err(Error::InvalidData("unhandled mdhd version")),
- };
-
- // Skip uninteresting fields.
- try!(skip(src, 4));
-
- Ok(MediaHeaderBox {
- timescale: timescale,
- duration: duration,
- })
-}
-
-/// Parse a stco box.
-fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
- let (_, _) = try!(read_fullbox_extra(src));
- let offset_count = try!(be_u32(src));
- let mut offsets = Vec::new();
- for _ in 0..offset_count {
- offsets.push(try!(be_u32(src)) as u64);
- }
-
- // Padding could be added in some contents.
- try!(skip_box_remain(src));
-
- Ok(ChunkOffsetBox {
- offsets: offsets,
- })
-}
-
-/// Parse a co64 box.
-fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
- let (_, _) = try!(read_fullbox_extra(src));
- let offset_count = try!(be_u32(src));
- let mut offsets = Vec::new();
- for _ in 0..offset_count {
- offsets.push(try!(be_u64(src)));
- }
-
- // Padding could be added in some contents.
- try!(skip_box_remain(src));
-
- Ok(ChunkOffsetBox {
- offsets: offsets,
- })
-}
-
-/// Parse a stss box.
-fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
- let (_, _) = try!(read_fullbox_extra(src));
- let sample_count = try!(be_u32(src));
- let mut samples = Vec::new();
- for _ in 0..sample_count {
- samples.push(try!(be_u32(src)));
- }
-
- // Padding could be added in some contents.
- try!(skip_box_remain(src));
-
- Ok(SyncSampleBox {
- samples: samples,
- })
-}
-
-/// Parse a stsc box.
-fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
- let (_, _) = try!(read_fullbox_extra(src));
- let sample_count = try!(be_u32(src));
- let mut samples = Vec::new();
- for _ in 0..sample_count {
- let first_chunk = try!(be_u32(src));
- let samples_per_chunk = try!(be_u32(src));
- let sample_description_index = try!(be_u32(src));
- samples.push(SampleToChunk {
- first_chunk: first_chunk,
- samples_per_chunk: samples_per_chunk,
- sample_description_index: sample_description_index,
- });
- }
-
- // Padding could be added in some contents.
- try!(skip_box_remain(src));
-
- Ok(SampleToChunkBox {
- samples: samples,
- })
-}
-
-/// Parse a stsz box.
-fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
- let (_, _) = try!(read_fullbox_extra(src));
- let sample_size = try!(be_u32(src));
- let sample_count = try!(be_u32(src));
- let mut sample_sizes = Vec::new();
- if sample_size == 0 {
- for _ in 0..sample_count {
- sample_sizes.push(try!(be_u32(src)));
- }
- }
-
- // Padding could be added in some contents.
- try!(skip_box_remain(src));
-
- Ok(SampleSizeBox {
- sample_size: sample_size,
- sample_sizes: sample_sizes,
- })
-}
-
-/// Parse a stts box.
-fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
- let (_, _) = try!(read_fullbox_extra(src));
- let sample_count = try!(be_u32(src));
- let mut samples = Vec::new();
- for _ in 0..sample_count {
- let sample_count = try!(be_u32(src));
- let sample_delta = try!(be_u32(src));
- samples.push(Sample {
- sample_count: sample_count,
- sample_delta: sample_delta,
- });
- }
-
- // Padding could be added in some contents.
- try!(skip_box_remain(src));
-
- Ok(TimeToSampleBox {
- samples: samples,
- })
-}
-
-/// Parse a VPx Config Box.
-fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> {
- let (version, _) = try!(read_fullbox_extra(src));
- if version != 0 {
- return Err(Error::Unsupported("unknown vpcC version"));
- }
-
- let profile = try!(src.read_u8());
- let level = try!(src.read_u8());
- let (bit_depth, color_space) = {
- let byte = try!(src.read_u8());
- ((byte >> 4) & 0x0f, byte & 0x0f)
- };
- let (chroma_subsampling, transfer_function, video_full_range) = {
- let byte = try!(src.read_u8());
- ((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
- };
-
- let codec_init_size = try!(be_u16(src));
- let codec_init = try!(read_buf(src, codec_init_size as usize));
-
- // TODO(rillian): validate field value ranges.
- Ok(VPxConfigBox {
- profile: profile,
- level: level,
- bit_depth: bit_depth,
- color_space: color_space,
- chroma_subsampling: chroma_subsampling,
- transfer_function: transfer_function,
- video_full_range: video_full_range,
- codec_init: codec_init,
- })
-}
-
-fn read_flac_metadata<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACMetadataBlock> {
- let temp = try!(src.read_u8());
- let block_type = temp & 0x7f;
- let length = try!(be_u24(src));
- if length as usize > src.bytes_left() {
- return Err(Error::InvalidData(
- "FLACMetadataBlock larger than parent box"));
- }
- let data = try!(read_buf(src, length as usize));
- Ok(FLACMetadataBlock {
- block_type: block_type,
- data: data,
- })
-}
-
-fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
- // Tags for elementary stream description
- const ESDESCR_TAG: u8 = 0x03;
- const DECODER_CONFIG_TAG: u8 = 0x04;
- const DECODER_SPECIFIC_TAG: u8 = 0x05;
-
- let frequency_table =
- vec![(0x1, 96000), (0x1, 88200), (0x2, 64000), (0x3, 48000),
- (0x4, 44100), (0x5, 32000), (0x6, 24000), (0x7, 22050),
- (0x8, 16000), (0x9, 12000), (0xa, 11025), (0xb, 8000),
- (0xc, 7350)];
-
- let (_, _) = try!(read_fullbox_extra(src));
-
- let esds_size = src.head.size - src.head.offset - 4;
- if esds_size > BUF_SIZE_LIMIT {
- return Err(Error::InvalidData("esds box exceeds BUF_SIZE_LIMIT"));
- }
- let esds_array = try!(read_buf(src, esds_size as usize));
-
- // Parsing DecoderConfig descriptor to get the object_profile_indicator
- // for correct codec type, audio sample rate and channel counts.
- let (object_profile_indicator, sample_frequency, channels) = {
- let mut object_profile: u8 = 0;
- let mut sample_frequency = None;
- let mut channels = None;
-
- // clone a esds cursor for parsing.
- let esds = &mut Cursor::new(&esds_array);
- let next_tag = try!(esds.read_u8());
-
- if next_tag != ESDESCR_TAG {
- return Err(Error::Unsupported("fail to parse ES descriptor"));
- }
-
- let esds_extend = try!(esds.read_u8());
- // extension tag start from 0x80.
- let esds_end = if esds_extend >= 0x80 {
- // skip remaining extension.
- try!(skip(esds, 2));
- esds.position() + try!(esds.read_u8()) as u64
- } else {
- esds.position() + esds_extend as u64
- };
- try!(skip(esds, 2));
-
- let esds_flags = try!(esds.read_u8());
-
- // Stream dependency flag, first bit from left most.
- if esds_flags & 0x80 > 0 {
- // Skip uninteresting fields.
- try!(skip(esds, 2));
- }
-
- // Url flag, second bit from left most.
- if esds_flags & 0x40 > 0 {
- // Skip uninteresting fields.
- let skip_es_len: usize = try!(esds.read_u8()) as usize + 2;
- try!(skip(esds, skip_es_len));
- }
-
- // find DecoderConfig descriptor (tag = DECODER_CONFIG_TAG)
- if esds_end > esds.position() {
- let next_tag = try!(esds.read_u8());
- if next_tag == DECODER_CONFIG_TAG {
- let dcds_extend = try!(esds.read_u8());
- // extension tag start from 0x80.
- if dcds_extend >= 0x80 {
- // skip remains extension and length.
- try!(skip(esds, 3));
- }
-
- object_profile = try!(esds.read_u8());
-
- // Skip uninteresting fields.
- try!(skip(esds, 12));
- }
- }
-
-
- // find DecoderSpecific descriptor (tag = DECODER_SPECIFIC_TAG)
- if esds_end > esds.position() {
- let next_tag = try!(esds.read_u8());
- if next_tag == DECODER_SPECIFIC_TAG {
- let dsds_extend = try!(esds.read_u8());
- // extension tag start from 0x80.
- if dsds_extend >= 0x80 {
- // skip remains extension and length.
- try!(skip(esds, 3));
- }
-
- let audio_specific_config = try!(be_u16(esds));
-
- let sample_index = (audio_specific_config & 0x07FF) >> 7;
-
- let channel_counts = (audio_specific_config & 0x007F) >> 3;
-
- sample_frequency =
- frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1);
-
- channels = Some(channel_counts);
- }
- }
-
- (object_profile, sample_frequency, channels)
- };
-
- let codec = match object_profile_indicator {
- 0x40 | 0x41 => CodecType::AAC,
- 0x6B => CodecType::MP3,
- _ => CodecType::Unknown,
- };
-
- if codec == CodecType::Unknown {
- return Err(Error::Unsupported("unknown audio codec"));
- }
-
- Ok(ES_Descriptor {
- audio_codec: codec,
- audio_sample_rate: sample_frequency,
- audio_channel_count: channels,
- codec_specific_config: esds_array,
- })
-}
-
-/// Parse `FLACSpecificBox`.
-fn read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox> {
- let (version, flags) = try!(read_fullbox_extra(src));
- if version != 0 {
- return Err(Error::Unsupported("unknown dfLa (FLAC) version"));
- }
- if flags != 0 {
- return Err(Error::InvalidData("no-zero dfLa (FLAC) flags"));
- }
- let mut blocks = Vec::new();
- while src.bytes_left() > 0 {
- let block = try!(read_flac_metadata(src));
- blocks.push(block);
- }
- // The box must have at least one meta block, and the first block
- // must be the METADATA_BLOCK_STREAMINFO
- if blocks.is_empty() {
- return Err(Error::InvalidData("FLACSpecificBox missing metadata"));
- } else if blocks[0].block_type != 0 {
- println!("flac metadata block:\n {:?}", blocks[0]);
- return Err(Error::InvalidData(
- "FLACSpecificBox must have STREAMINFO metadata first"));
- } else if blocks[0].data.len() != 34 {
- return Err(Error::InvalidData(
- "FLACSpecificBox STREAMINFO block is the wrong size"));
- }
- Ok(FLACSpecificBox {
- version: version,
- blocks: blocks,
- })
-}
-
-/// Parse `OpusSpecificBox`.
-fn read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox> {
- let version = try!(src.read_u8());
- if version != 0 {
- return Err(Error::Unsupported("unknown dOps (Opus) version"));
- }
-
- let output_channel_count = try!(src.read_u8());
- let pre_skip = try!(be_u16(src));
- let input_sample_rate = try!(be_u32(src));
- let output_gain = try!(be_i16(src));
- let channel_mapping_family = try!(src.read_u8());
-
- let channel_mapping_table = if channel_mapping_family == 0 {
- None
- } else {
- let stream_count = try!(src.read_u8());
- let coupled_count = try!(src.read_u8());
- let channel_mapping = try!(read_buf(src, output_channel_count as usize));
-
- Some(ChannelMappingTable {
- stream_count: stream_count,
- coupled_count: coupled_count,
- channel_mapping: channel_mapping,
- })
- };
-
- // TODO(kinetik): validate field value ranges.
- Ok(OpusSpecificBox {
- version: version,
- output_channel_count: output_channel_count,
- pre_skip: pre_skip,
- input_sample_rate: input_sample_rate,
- output_gain: output_gain,
- channel_mapping_family: channel_mapping_family,
- channel_mapping_table: channel_mapping_table,
- })
-}
-
-/// Re-serialize the Opus codec-specific config data as an `OpusHead` packet.
-///
-/// Some decoders expect the initialization data in the format used by the
-/// Ogg and WebM encapsulations. To support this we prepend the `OpusHead`
-/// tag and byte-swap the data from big- to little-endian relative to the
-/// dOps box.
-pub fn serialize_opus_header<W: byteorder::WriteBytesExt + std::io::Write>(opus: &OpusSpecificBox, dst: &mut W) -> Result<()> {
- match dst.write(b"OpusHead") {
- Err(e) => return Err(Error::from(e)),
- Ok(bytes) => {
- if bytes != 8 {
- return Err(Error::InvalidData("Couldn't write OpusHead tag."));
- }
- }
- }
- // In mp4 encapsulation, the version field is 0, but in ogg
- // it is 1. While decoders generally accept zero as well, write
- // out the version of the header we're supporting rather than
- // whatever we parsed out of mp4.
- try!(dst.write_u8(1));
- try!(dst.write_u8(opus.output_channel_count));
- try!(dst.write_u16::<byteorder::LittleEndian>(opus.pre_skip));
- try!(dst.write_u32::<byteorder::LittleEndian>(opus.input_sample_rate));
- try!(dst.write_i16::<byteorder::LittleEndian>(opus.output_gain));
- try!(dst.write_u8(opus.channel_mapping_family));
- match opus.channel_mapping_table {
- None => {}
- Some(ref table) => {
- try!(dst.write_u8(table.stream_count));
- try!(dst.write_u8(table.coupled_count));
- match dst.write(&table.channel_mapping) {
- Err(e) => return Err(Error::from(e)),
- Ok(bytes) => {
- if bytes != table.channel_mapping.len() {
- return Err(Error::InvalidData("Couldn't write channel mapping table data."));
- }
- }
- }
- }
- };
- Ok(())
-}
-
-/// Parse a hdlr box.
-fn read_hdlr<T: Read>(src: &mut BMFFBox<T>) -> Result<HandlerBox> {
- let (_, _) = try!(read_fullbox_extra(src));
-
- // Skip uninteresting fields.
- try!(skip(src, 4));
-
- let handler_type = try!(be_u32(src));
-
- // Skip uninteresting fields.
- try!(skip(src, 12));
-
- let bytes_left = src.bytes_left();
- let _name = try!(read_null_terminated_string(src, bytes_left));
-
- Ok(HandlerBox {
- handler_type: handler_type,
- })
-}
-
-/// Parse an video description inside an stsd box.
-fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
- let name = src.get_header().name;
- track.codec_type = match name {
- BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
- BoxType::VP8SampleEntry => CodecType::VP8,
- BoxType::VP9SampleEntry => CodecType::VP9,
- BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
- _ => CodecType::Unknown,
- };
-
- // Skip uninteresting fields.
- try!(skip(src, 6));
-
- let data_reference_index = try!(be_u16(src));
-
- // Skip uninteresting fields.
- try!(skip(src, 16));
-
- let width = try!(be_u16(src));
- let height = try!(be_u16(src));
-
- // Skip uninteresting fields.
- try!(skip(src, 14));
-
- let _compressorname = try!(read_fixed_length_pascal_string(src, 32));
-
- // Skip uninteresting fields.
- try!(skip(src, 4));
-
- // Skip clap/pasp/etc. for now.
- let mut codec_specific = None;
- let mut iter = src.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::AVCConfigurationBox => {
- if (name != BoxType::AVCSampleEntry &&
- name != BoxType::AVC3SampleEntry &&
- name != BoxType::ProtectedVisualSampleEntry) ||
- codec_specific.is_some() {
- return Err(Error::InvalidData("malformed video sample entry"));
- }
- let avcc_size = b.head.size - b.head.offset;
- if avcc_size > BUF_SIZE_LIMIT {
- return Err(Error::InvalidData("avcC box exceeds BUF_SIZE_LIMIT"));
- }
- let avcc = try!(read_buf(&mut b.content, avcc_size as usize));
- // TODO(kinetik): Parse avcC box? For now we just stash the data.
- codec_specific = Some(VideoCodecSpecific::AVCConfig(avcc));
- }
- BoxType::VPCodecConfigurationBox => { // vpcC
- if (name != BoxType::VP8SampleEntry &&
- name != BoxType::VP9SampleEntry) ||
- codec_specific.is_some() {
- return Err(Error::InvalidData("malformed video sample entry"));
- }
- let vpcc = try!(read_vpcc(&mut b));
- codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc));
- }
- _ => try!(skip_box_content(&mut b)),
- }
- check_parser_state!(b.content);
- }
-
- codec_specific
- .map(|codec_specific| SampleEntry::Video(VideoSampleEntry {
- data_reference_index: data_reference_index,
- width: width,
- height: height,
- codec_specific: codec_specific,
- }))
- .ok_or_else(|| Error::InvalidData("malformed video sample entry"))
-}
-
-fn read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
- let mut codec_specific = None;
- let mut iter = src.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::ESDBox => {
- let esds = try!(read_esds(&mut b));
- codec_specific = Some(esds);
- },
- _ => try!(skip_box_content(&mut b)),
- }
- }
-
- codec_specific.ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
-}
-
-/// Parse an audio description inside an stsd box.
-fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
- let name = src.get_header().name;
- track.codec_type = match name {
- // TODO(kinetik): stagefright inspects ESDS to detect MP3 (audio/mpeg).
- BoxType::MP4AudioSampleEntry => CodecType::AAC,
- BoxType::FLACSampleEntry => CodecType::FLAC,
- BoxType::OpusSampleEntry => CodecType::Opus,
- BoxType::ProtectedAudioSampleEntry => CodecType::EncryptedAudio,
- _ => CodecType::Unknown,
- };
-
- // Skip uninteresting fields.
- try!(skip(src, 6));
-
- let data_reference_index = try!(be_u16(src));
-
- // XXX(kinetik): This is "reserved" in BMFF, but some old QT MOV variant
- // uses it, need to work out if we have to support it. Without checking
- // here and reading extra fields after samplerate (or bailing with an
- // error), the parser loses sync completely.
- let version = try!(be_u16(src));
-
- // Skip uninteresting fields.
- try!(skip(src, 6));
-
- let channelcount = try!(be_u16(src));
- let samplesize = try!(be_u16(src));
-
- // Skip uninteresting fields.
- try!(skip(src, 4));
-
- let samplerate = try!(be_u32(src));
-
- match version {
- 0 => (),
- 1 => {
- // Quicktime sound sample description version 1.
- // Skip uninteresting fields.
- try!(skip(src, 16));
- },
- _ => return Err(Error::Unsupported("unsupported non-isom audio sample entry")),
- }
-
- // Skip chan/etc. for now.
- let mut codec_specific = None;
- let mut iter = src.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- match b.head.name {
- BoxType::ESDBox => {
- if (name != BoxType::MP4AudioSampleEntry &&
- name != BoxType::ProtectedAudioSampleEntry) ||
- codec_specific.is_some() {
- return Err(Error::InvalidData("malformed audio sample entry"));
- }
-
- let esds = try!(read_esds(&mut b));
- track.codec_type = esds.audio_codec;
- codec_specific = Some(AudioCodecSpecific::ES_Descriptor(esds));
- }
- BoxType::FLACSpecificBox => {
- if name != BoxType::FLACSampleEntry ||
- codec_specific.is_some() {
- return Err(Error::InvalidData("malformed audio sample entry"));
- }
- let dfla = try!(read_dfla(&mut b));
- track.codec_type = CodecType::FLAC;
- codec_specific = Some(AudioCodecSpecific::FLACSpecificBox(dfla));
- }
- BoxType::OpusSpecificBox => {
- if name != BoxType::OpusSampleEntry ||
- codec_specific.is_some() {
- return Err(Error::InvalidData("malformed audio sample entry"));
- }
- let dops = try!(read_dops(&mut b));
- track.codec_type = CodecType::Opus;
- codec_specific = Some(AudioCodecSpecific::OpusSpecificBox(dops));
- }
- BoxType::QTWaveAtom => {
- let qt_esds = try!(read_qt_wave_atom(&mut b));
- track.codec_type = qt_esds.audio_codec;
- codec_specific = Some(AudioCodecSpecific::ES_Descriptor(qt_esds));
- }
- _ => try!(skip_box_content(&mut b)),
- }
- check_parser_state!(b.content);
- }
-
- codec_specific
- .map(|codec_specific| SampleEntry::Audio(AudioSampleEntry {
- data_reference_index: data_reference_index,
- channelcount: channelcount,
- samplesize: samplesize,
- samplerate: samplerate,
- codec_specific: codec_specific,
- }))
- .ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
-}
-
-/// Parse a stsd box.
-fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleDescriptionBox> {
- let (_, _) = try!(read_fullbox_extra(src));
-
- let description_count = try!(be_u32(src));
- let mut descriptions = Vec::new();
-
- {
- // TODO(kinetik): check if/when more than one desc per track? do we need to support?
- let mut iter = src.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
- let description = match track.track_type {
- TrackType::Video => read_video_sample_entry(&mut b, track),
- TrackType::Audio => read_audio_sample_entry(&mut b, track),
- TrackType::Unknown => Err(Error::Unsupported("unknown track type")),
- };
- let description = match description {
- Ok(desc) => desc,
- Err(Error::Unsupported(_)) => {
- // read_{audio,video}_desc may have returned Unsupported
- // after partially reading the box content, so we can't
- // simply use skip_box_content here.
- let to_skip = b.bytes_left();
- try!(skip(&mut b, to_skip));
- SampleEntry::Unknown
- }
- Err(e) => return Err(e),
- };
- if track.data.is_none() {
- track.data = Some(description.clone());
- } else {
- log!("** don't know how to handle multiple descriptions **");
- }
- descriptions.push(description);
- check_parser_state!(b.content);
- if descriptions.len() == description_count as usize {
- break;
- }
- }
- }
-
- // Padding could be added in some contents.
- try!(skip_box_remain(src));
-
- Ok(SampleDescriptionBox {
- descriptions: descriptions,
- })
-}
-
-/// Skip a number of bytes that we don't care to parse.
-fn skip<T: Read>(src: &mut T, mut bytes: usize) -> Result<()> {
- const BUF_SIZE: usize = 64 * 1024;
- let mut buf = vec![0; BUF_SIZE];
- while bytes > 0 {
- let buf_size = cmp::min(bytes, BUF_SIZE);
- let len = try!(src.take(buf_size as u64).read(&mut buf));
- if len == 0 {
- return Err(Error::UnexpectedEOF);
- }
- bytes -= len;
- }
- Ok(())
-}
-
-/// Read size bytes into a Vector or return error.
-fn read_buf<T: ReadBytesExt>(src: &mut T, size: usize) -> Result<Vec<u8>> {
- let mut buf = vec![0; size];
- let r = try!(src.read(&mut buf));
- if r != size {
- return Err(Error::InvalidData("failed buffer read"));
- }
- Ok(buf)
-}
-
-// TODO(kinetik): Find a copy of ISO/IEC 14496-1 to confirm various string encodings.
-// XXX(kinetik): definition of "null-terminated" string is fuzzy, we have:
-// - zero or more byte strings, with a single null terminating the string.
-// - zero byte strings with no null terminator (i.e. zero space in the box for the string)
-// - length-prefixed strings with no null terminator (e.g. bear_rotate_0.mp4)
-fn read_null_terminated_string<T: ReadBytesExt>(src: &mut T, mut size: usize) -> Result<String> {
- let mut buf = Vec::new();
- while size > 0 {
- let c = try!(src.read_u8());
- if c == 0 {
- break;
- }
- buf.push(c);
- size -= 1;
- }
- String::from_utf8(buf).map_err(From::from)
-}
-
-#[allow(dead_code)]
-fn read_pascal_string<T: ReadBytesExt>(src: &mut T) -> Result<String> {
- let len = try!(src.read_u8());
- let buf = try!(read_buf(src, len as usize));
- String::from_utf8(buf).map_err(From::from)
-}
-
-// Weird string encoding with a length prefix and a fixed sized buffer which
-// contains padding if the string doesn't fill the buffer.
-fn read_fixed_length_pascal_string<T: Read>(src: &mut T, size: usize) -> Result<String> {
- assert!(size > 0);
- let len = cmp::min(try!(src.read_u8()) as usize, size - 1);
- let buf = try!(read_buf(src, len));
- try!(skip(src, size - 1 - buf.len()));
- String::from_utf8(buf).map_err(From::from)
-}
-
-fn be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16> {
- src.read_i16::<byteorder::BigEndian>().map_err(From::from)
-}
-
-fn be_i32<T: ReadBytesExt>(src: &mut T) -> Result<i32> {
- src.read_i32::<byteorder::BigEndian>().map_err(From::from)
-}
-
-fn be_i64<T: ReadBytesExt>(src: &mut T) -> Result<i64> {
- src.read_i64::<byteorder::BigEndian>().map_err(From::from)
-}
-
-fn be_u16<T: ReadBytesExt>(src: &mut T) -> Result<u16> {
- src.read_u16::<byteorder::BigEndian>().map_err(From::from)
-}
-
-fn be_u24<T: ReadBytesExt>(src: &mut T) -> Result<u32> {
- src.read_uint::<byteorder::BigEndian>(3)
- .map(|v| v as u32)
- .map_err(From::from)
-}
-
-fn be_u32<T: ReadBytesExt>(src: &mut T) -> Result<u32> {
- src.read_u32::<byteorder::BigEndian>().map_err(From::from)
-}
-
-fn be_u64<T: ReadBytesExt>(src: &mut T) -> Result<u64> {
- src.read_u64::<byteorder::BigEndian>().map_err(From::from)
-}
diff --git a/media/libstagefright/binding/mp4parse/src/tests.rs b/media/libstagefright/binding/mp4parse/src/tests.rs
deleted file mode 100644
index 7063b3790..000000000
--- a/media/libstagefright/binding/mp4parse/src/tests.rs
+++ /dev/null
@@ -1,860 +0,0 @@
-//! Module for parsing ISO Base Media Format aka video/mp4 streams.
-//! Internal unit tests.
-
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-use std::io::Cursor;
-use super::read_mp4;
-use super::MediaContext;
-use super::Error;
-extern crate test_assembler;
-use self::test_assembler::*;
-
-use boxes::BoxType;
-
-enum BoxSize {
- Short(u32),
- Long(u64),
- UncheckedShort(u32),
- UncheckedLong(u64),
- Auto,
-}
-
-fn make_box<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
- where F: Fn(Section) -> Section
-{
- let mut section = Section::new();
- let box_size = Label::new();
- section = match size {
- BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
- BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
- BoxSize::Auto => section.B32(&box_size),
- };
- section = section.append_bytes(name);
- section = match size {
- // The spec allows the 32-bit size to be 0 to indicate unknown
- // length streams. It's not clear if this is valid when using a
- // 64-bit size, so prohibit it for now.
- BoxSize::Long(size) => {
- assert!(size > 0);
- section.B64(size)
- }
- BoxSize::UncheckedLong(size) => section.B64(size),
- _ => section,
- };
- section = func(section);
- match size {
- BoxSize::Short(size) => {
- if size > 0 {
- assert_eq!(size as u64, section.size())
- }
- }
- BoxSize::Long(size) => assert_eq!(size, section.size()),
- BoxSize::Auto => {
- assert!(section.size() <= u32::max_value() as u64,
- "Tried to use a long box with BoxSize::Auto");
- box_size.set_const(section.size());
- }
- // Skip checking BoxSize::Unchecked* cases.
- _ => (),
- }
- Cursor::new(section.get_contents().unwrap())
-}
-
-fn make_fullbox<F>(size: BoxSize, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
- where F: Fn(Section) -> Section
-{
- make_box(size, name, |s| {
- func(s.B8(version)
- .B8(0)
- .B8(0)
- .B8(0))
- })
-}
-
-#[test]
-fn read_box_header_short() {
- let mut stream = make_box(BoxSize::Short(8), b"test", |s| s);
- let header = super::read_box_header(&mut stream).unwrap();
- assert_eq!(header.name, BoxType::UnknownBox(0x74657374)); // "test"
- assert_eq!(header.size, 8);
-}
-
-#[test]
-fn read_box_header_long() {
- let mut stream = make_box(BoxSize::Long(16), b"test", |s| s);
- let header = super::read_box_header(&mut stream).unwrap();
- assert_eq!(header.name, BoxType::UnknownBox(0x74657374)); // "test"
- assert_eq!(header.size, 16);
-}
-
-#[test]
-fn read_box_header_short_unknown_size() {
- let mut stream = make_box(BoxSize::Short(0), b"test", |s| s);
- match super::read_box_header(&mut stream) {
- Err(Error::Unsupported(s)) => assert_eq!(s, "unknown sized box"),
- _ => panic!("unexpected result reading box with unknown size"),
- };
-}
-
-#[test]
-fn read_box_header_short_invalid_size() {
- let mut stream = make_box(BoxSize::UncheckedShort(2), b"test", |s| s);
- match super::read_box_header(&mut stream) {
- Err(Error::InvalidData(s)) => assert_eq!(s, "malformed size"),
- _ => panic!("unexpected result reading box with invalid size"),
- };
-}
-
-#[test]
-fn read_box_header_long_invalid_size() {
- let mut stream = make_box(BoxSize::UncheckedLong(2), b"test", |s| s);
- match super::read_box_header(&mut stream) {
- Err(Error::InvalidData(s)) => assert_eq!(s, "malformed wide size"),
- _ => panic!("unexpected result reading box with invalid size"),
- };
-}
-
-#[test]
-fn read_ftyp() {
- let mut stream = make_box(BoxSize::Short(24), b"ftyp", |s| {
- s.append_bytes(b"mp42")
- .B32(0) // minor version
- .append_bytes(b"isom")
- .append_bytes(b"mp42")
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::FileTypeBox);
- assert_eq!(stream.head.size, 24);
- let parsed = super::read_ftyp(&mut stream).unwrap();
- assert_eq!(parsed.major_brand, 0x6d703432); // mp42
- assert_eq!(parsed.minor_version, 0);
- assert_eq!(parsed.compatible_brands.len(), 2);
- assert_eq!(parsed.compatible_brands[0], 0x69736f6d); // isom
- assert_eq!(parsed.compatible_brands[1], 0x6d703432); // mp42
-}
-
-#[test]
-fn read_truncated_ftyp() {
- // We declare a 24 byte box, but only write 20 bytes.
- let mut stream = make_box(BoxSize::UncheckedShort(24), b"ftyp", |s| {
- s.append_bytes(b"mp42")
- .B32(0) // minor version
- .append_bytes(b"isom")
- });
- let mut context = MediaContext::new();
- match read_mp4(&mut stream, &mut context) {
- Err(Error::UnexpectedEOF) => (),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
- }
-}
-
-#[test]
-fn read_ftyp_case() {
- // Brands in BMFF are represented as a u32, so it would seem clear that
- // 0x6d703432 ("mp42") is not equal to 0x4d503432 ("MP42"), but some
- // demuxers treat these as case-insensitive strings, e.g. street.mp4's
- // major brand is "MP42". I haven't seen case-insensitive
- // compatible_brands (which we also test here), but it doesn't seem
- // unlikely given the major_brand behaviour.
- let mut stream = make_box(BoxSize::Auto, b"ftyp", |s| {
- s.append_bytes(b"MP42")
- .B32(0) // minor version
- .append_bytes(b"ISOM")
- .append_bytes(b"MP42")
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::FileTypeBox);
- assert_eq!(stream.head.size, 24);
- let parsed = super::read_ftyp(&mut stream).unwrap();
- assert_eq!(parsed.major_brand, 0x4d503432);
- assert_eq!(parsed.minor_version, 0);
- assert_eq!(parsed.compatible_brands.len(), 2);
- assert_eq!(parsed.compatible_brands[0], 0x49534f4d); // ISOM
- assert_eq!(parsed.compatible_brands[1], 0x4d503432); // MP42
-}
-
-#[test]
-fn read_elst_v0() {
- let mut stream = make_fullbox(BoxSize::Short(28), b"elst", 0, |s| {
- s.B32(1) // list count
- // first entry
- .B32(1234) // duration
- .B32(5678) // time
- .B16(12) // rate integer
- .B16(34) // rate fraction
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::EditListBox);
- assert_eq!(stream.head.size, 28);
- let parsed = super::read_elst(&mut stream).unwrap();
- assert_eq!(parsed.edits.len(), 1);
- assert_eq!(parsed.edits[0].segment_duration, 1234);
- assert_eq!(parsed.edits[0].media_time, 5678);
- assert_eq!(parsed.edits[0].media_rate_integer, 12);
- assert_eq!(parsed.edits[0].media_rate_fraction, 34);
-}
-
-#[test]
-fn read_elst_v1() {
- let mut stream = make_fullbox(BoxSize::Short(56), b"elst", 1, |s| {
- s.B32(2) // list count
- // first entry
- .B64(1234) // duration
- .B64(5678) // time
- .B16(12) // rate integer
- .B16(34) // rate fraction
- // second entry
- .B64(1234) // duration
- .B64(5678) // time
- .B16(12) // rate integer
- .B16(34) // rate fraction
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::EditListBox);
- assert_eq!(stream.head.size, 56);
- let parsed = super::read_elst(&mut stream).unwrap();
- assert_eq!(parsed.edits.len(), 2);
- assert_eq!(parsed.edits[1].segment_duration, 1234);
- assert_eq!(parsed.edits[1].media_time, 5678);
- assert_eq!(parsed.edits[1].media_rate_integer, 12);
- assert_eq!(parsed.edits[1].media_rate_fraction, 34);
-}
-
-#[test]
-fn read_mdhd_v0() {
- let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd", 0, |s| {
- s.B32(0)
- .B32(0)
- .B32(1234) // timescale
- .B32(5678) // duration
- .B32(0)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
- assert_eq!(stream.head.size, 32);
- let parsed = super::read_mdhd(&mut stream).unwrap();
- assert_eq!(parsed.timescale, 1234);
- assert_eq!(parsed.duration, 5678);
-}
-
-#[test]
-fn read_mdhd_v1() {
- let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd", 1, |s| {
- s.B64(0)
- .B64(0)
- .B32(1234) // timescale
- .B64(5678) // duration
- .B32(0)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
- assert_eq!(stream.head.size, 44);
- let parsed = super::read_mdhd(&mut stream).unwrap();
- assert_eq!(parsed.timescale, 1234);
- assert_eq!(parsed.duration, 5678);
-}
-
-#[test]
-fn read_mdhd_unknown_duration() {
- let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd", 0, |s| {
- s.B32(0)
- .B32(0)
- .B32(1234) // timescale
- .B32(::std::u32::MAX) // duration
- .B32(0)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
- assert_eq!(stream.head.size, 32);
- let parsed = super::read_mdhd(&mut stream).unwrap();
- assert_eq!(parsed.timescale, 1234);
- assert_eq!(parsed.duration, ::std::u64::MAX);
-}
-
-#[test]
-fn read_mdhd_invalid_timescale() {
- let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd", 1, |s| {
- s.B64(0)
- .B64(0)
- .B32(0) // timescale
- .B64(5678) // duration
- .B32(0)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
- assert_eq!(stream.head.size, 44);
- let r = super::parse_mdhd(&mut stream, &mut super::Track::new(0));
- assert_eq!(r.is_err(), true);
-}
-
-#[test]
-fn read_mvhd_v0() {
- let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd", 0, |s| {
- s.B32(0)
- .B32(0)
- .B32(1234)
- .B32(5678)
- .append_repeated(0, 80)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
- assert_eq!(stream.head.size, 108);
- let parsed = super::read_mvhd(&mut stream).unwrap();
- assert_eq!(parsed.timescale, 1234);
- assert_eq!(parsed.duration, 5678);
-}
-
-#[test]
-fn read_mvhd_v1() {
- let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd", 1, |s| {
- s.B64(0)
- .B64(0)
- .B32(1234)
- .B64(5678)
- .append_repeated(0, 80)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
- assert_eq!(stream.head.size, 120);
- let parsed = super::read_mvhd(&mut stream).unwrap();
- assert_eq!(parsed.timescale, 1234);
- assert_eq!(parsed.duration, 5678);
-}
-
-#[test]
-fn read_mvhd_invalid_timescale() {
- let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd", 1, |s| {
- s.B64(0)
- .B64(0)
- .B32(0)
- .B64(5678)
- .append_repeated(0, 80)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
- assert_eq!(stream.head.size, 120);
- let r = super::parse_mvhd(&mut stream);
- assert_eq!(r.is_err(), true);
-}
-
-#[test]
-fn read_mvhd_unknown_duration() {
- let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd", 0, |s| {
- s.B32(0)
- .B32(0)
- .B32(1234)
- .B32(::std::u32::MAX)
- .append_repeated(0, 80)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
- assert_eq!(stream.head.size, 108);
- let parsed = super::read_mvhd(&mut stream).unwrap();
- assert_eq!(parsed.timescale, 1234);
- assert_eq!(parsed.duration, ::std::u64::MAX);
-}
-
-#[test]
-fn read_vpcc() {
- let data_length = 12u16;
- let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 0, |s| {
- s.B8(2)
- .B8(0)
- .B8(0x82)
- .B8(0)
- .B16(data_length)
- .append_repeated(42, data_length as usize)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::VPCodecConfigurationBox);
- let r = super::read_vpcc(&mut stream);
- assert!(r.is_ok());
-}
-
-#[test]
-fn read_hdlr() {
- let mut stream = make_fullbox(BoxSize::Short(45), b"hdlr", 0, |s| {
- s.B32(0)
- .append_bytes(b"vide")
- .B32(0)
- .B32(0)
- .B32(0)
- .append_bytes(b"VideoHandler")
- .B8(0) // null-terminate string
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::HandlerBox);
- assert_eq!(stream.head.size, 45);
- let parsed = super::read_hdlr(&mut stream).unwrap();
- assert_eq!(parsed.handler_type, 0x76696465); // vide
-}
-
-#[test]
-fn read_hdlr_short_name() {
- let mut stream = make_fullbox(BoxSize::Short(33), b"hdlr", 0, |s| {
- s.B32(0)
- .append_bytes(b"vide")
- .B32(0)
- .B32(0)
- .B32(0)
- .B8(0) // null-terminate string
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::HandlerBox);
- assert_eq!(stream.head.size, 33);
- let parsed = super::read_hdlr(&mut stream).unwrap();
- assert_eq!(parsed.handler_type, 0x76696465); // vide
-}
-
-#[test]
-fn read_hdlr_zero_length_name() {
- let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr", 0, |s| {
- s.B32(0)
- .append_bytes(b"vide")
- .B32(0)
- .B32(0)
- .B32(0)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::HandlerBox);
- assert_eq!(stream.head.size, 32);
- let parsed = super::read_hdlr(&mut stream).unwrap();
- assert_eq!(parsed.handler_type, 0x76696465); // vide
-}
-
-fn flac_streaminfo() -> Vec<u8> {
- vec![
- 0x10, 0x00, 0x10, 0x00, 0x00, 0x0a, 0x11, 0x00,
- 0x38, 0x32, 0x0a, 0xc4, 0x42, 0xf0, 0x00, 0xc9,
- 0xdf, 0xae, 0xb5, 0x66, 0xfc, 0x02, 0x15, 0xa3,
- 0xb1, 0x54, 0x61, 0x47, 0x0f, 0xfb, 0x05, 0x00,
- 0x33, 0xad,
- ]
-}
-
-#[test]
-fn read_flac() {
- let mut stream = make_box(BoxSize::Auto, b"fLaC", |s| {
- s.append_repeated(0, 6) // reserved
- .B16(1) // data reference index
- .B32(0) // reserved
- .B32(0) // reserved
- .B16(2) // channel count
- .B16(16) // bits per sample
- .B16(0) // pre_defined
- .B16(0) // reserved
- .B32(44100 << 16) // Sample rate
- .append_bytes(&make_dfla(FlacBlockType::StreamInfo, true,
- &flac_streaminfo(), FlacBlockLength::Correct)
- .into_inner())
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- let mut track = super::Track::new(0);
- let r = super::read_audio_sample_entry(&mut stream, &mut track);
- r.unwrap();
-}
-
-#[derive(Clone, Copy)]
-enum FlacBlockType {
- StreamInfo = 0,
- _Padding = 1,
- _Application = 2,
- _Seektable = 3,
- _Comment = 4,
- _Cuesheet = 5,
- _Picture = 6,
- _Reserved,
- _Invalid = 127,
-}
-
-enum FlacBlockLength {
- Correct,
- Incorrect(usize),
-}
-
-fn make_dfla(block_type: FlacBlockType, last: bool, data: &Vec<u8>,
- data_length: FlacBlockLength) -> Cursor<Vec<u8>> {
- assert!(data.len() < 1<<24);
- make_fullbox(BoxSize::Auto, b"dfLa", 0, |s| {
- let flag = match last {
- true => 1,
- false => 0,
- };
- let size = match data_length {
- FlacBlockLength::Correct => (data.len() as u32) & 0xffffff,
- FlacBlockLength::Incorrect(size) => {
- assert!(size < 1<<24);
- (size as u32) & 0xffffff
- }
- };
- let block_type = (block_type as u32) & 0x7f;
- s.B32(flag << 31 | block_type << 24 | size)
- .append_bytes(data)
- })
-}
-
-#[test]
-fn read_dfla() {
- let mut stream = make_dfla(FlacBlockType::StreamInfo, true,
- &flac_streaminfo(), FlacBlockLength::Correct);
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
- let dfla = super::read_dfla(&mut stream).unwrap();
- assert_eq!(dfla.version, 0);
-}
-
-#[test]
-fn long_flac_metadata() {
- let streaminfo = flac_streaminfo();
- let mut stream = make_dfla(FlacBlockType::StreamInfo, true,
- &streaminfo,
- FlacBlockLength::Incorrect(streaminfo.len() + 4));
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
- let r = super::read_dfla(&mut stream);
- assert!(r.is_err());
-}
-
-#[test]
-fn read_opus() {
- let mut stream = make_box(BoxSize::Auto, b"Opus", |s| {
- s.append_repeated(0, 6)
- .B16(1) // data reference index
- .B32(0)
- .B32(0)
- .B16(2) // channel count
- .B16(16) // bits per sample
- .B16(0)
- .B16(0)
- .B32(48000 << 16) // Sample rate is always 48 kHz for Opus.
- .append_bytes(&make_dops().into_inner())
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- let mut track = super::Track::new(0);
- let r = super::read_audio_sample_entry(&mut stream, &mut track);
- assert!(r.is_ok());
-}
-
-fn make_dops() -> Cursor<Vec<u8>> {
- make_box(BoxSize::Auto, b"dOps", |s| {
- s.B8(0) // version
- .B8(2) // channel count
- .B16(348) // pre-skip
- .B32(44100) // original sample rate
- .B16(0) // gain
- .B8(0) // channel mapping
- })
-}
-
-#[test]
-fn read_dops() {
- let mut stream = make_dops();
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- assert_eq!(stream.head.name, BoxType::OpusSpecificBox);
- let r = super::read_dops(&mut stream);
- assert!(r.is_ok());
-}
-
-#[test]
-fn serialize_opus_header() {
- let opus = super::OpusSpecificBox {
- version: 0,
- output_channel_count: 1,
- pre_skip: 342,
- input_sample_rate: 24000,
- output_gain: 0,
- channel_mapping_family: 0,
- channel_mapping_table: None,
- };
- let mut v = Vec::<u8>::new();
- super::serialize_opus_header(&opus, &mut v).unwrap();
- assert!(v.len() == 19);
- assert!(v == vec![
- 0x4f, 0x70, 0x75, 0x73, 0x48,0x65, 0x61, 0x64,
- 0x01, 0x01, 0x56, 0x01,
- 0xc0, 0x5d, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- ]);
- let opus = super::OpusSpecificBox {
- version: 0,
- output_channel_count: 6,
- pre_skip: 152,
- input_sample_rate: 48000,
- output_gain: 0,
- channel_mapping_family: 1,
- channel_mapping_table: Some(super::ChannelMappingTable {
- stream_count: 4,
- coupled_count: 2,
- channel_mapping: vec![0, 4, 1, 2, 3, 5],
- }),
- };
- let mut v = Vec::<u8>::new();
- super::serialize_opus_header(&opus, &mut v).unwrap();
- assert!(v.len() == 27);
- assert!(v == vec![
- 0x4f, 0x70, 0x75, 0x73, 0x48,0x65, 0x61, 0x64,
- 0x01, 0x06, 0x98, 0x00,
- 0x80, 0xbb, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x04, 0x02,
- 0x00, 0x04, 0x01, 0x02, 0x03, 0x05,
- ]);
-}
-
-#[test]
-fn avcc_limit() {
- let mut stream = make_box(BoxSize::Auto, b"avc1", |s| {
- s.append_repeated(0, 6)
- .B16(1)
- .append_repeated(0, 16)
- .B16(320)
- .B16(240)
- .append_repeated(0, 14)
- .append_repeated(0, 32)
- .append_repeated(0, 4)
- .B32(0xffffffff)
- .append_bytes(b"avcC")
- .append_repeated(0, 100)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- let mut track = super::Track::new(0);
- match super::read_video_sample_entry(&mut stream, &mut track) {
- Err(Error::InvalidData(s)) => assert_eq!(s, "avcC box exceeds BUF_SIZE_LIMIT"),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
- }
-}
-
-#[test]
-fn esds_limit() {
- let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
- s.append_repeated(0, 6)
- .B16(1)
- .B32(0)
- .B32(0)
- .B16(2)
- .B16(16)
- .B16(0)
- .B16(0)
- .B32(48000 << 16)
- .B32(0xffffffff)
- .append_bytes(b"esds")
- .append_repeated(0, 100)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- let mut track = super::Track::new(0);
- match super::read_audio_sample_entry(&mut stream, &mut track) {
- Err(Error::InvalidData(s)) => assert_eq!(s, "esds box exceeds BUF_SIZE_LIMIT"),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
- }
-}
-
-#[test]
-fn esds_limit_2() {
- let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
- s.append_repeated(0, 6)
- .B16(1)
- .B32(0)
- .B32(0)
- .B16(2)
- .B16(16)
- .B16(0)
- .B16(0)
- .B32(48000 << 16)
- .B32(8)
- .append_bytes(b"esds")
- .append_repeated(0, 4)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- let mut track = super::Track::new(0);
- match super::read_audio_sample_entry(&mut stream, &mut track) {
- Err(Error::UnexpectedEOF) => (),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
- }
-}
-
-#[test]
-fn read_elst_zero_entries() {
- let mut stream = make_fullbox(BoxSize::Auto, b"elst", 0, |s| {
- s.B32(0)
- .B16(12)
- .B16(34)
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- match super::read_elst(&mut stream) {
- Err(Error::InvalidData(s)) => assert_eq!(s, "invalid edit count"),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
- }
-}
-
-fn make_elst() -> Cursor<Vec<u8>> {
- make_fullbox(BoxSize::Auto, b"elst", 1, |s| {
- s.B32(1)
- // first entry
- .B64(1234) // duration
- .B64(0xffffffffffffffff) // time
- .B16(12) // rate integer
- .B16(34) // rate fraction
- })
-}
-
-#[test]
-fn read_edts_bogus() {
- // First edit list entry has a media_time of -1, so we expect a second
- // edit list entry to be present to provide a valid media_time.
- let mut stream = make_box(BoxSize::Auto, b"edts", |s| {
- s.append_bytes(&make_elst().into_inner())
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- let mut track = super::Track::new(0);
- match super::read_edts(&mut stream, &mut track) {
- Err(Error::InvalidData(s)) => assert_eq!(s, "expected additional edit"),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
- }
-}
-
-#[test]
-fn invalid_pascal_string() {
- // String claims to be 32 bytes long (we provide 33 bytes to account for
- // the 1 byte length prefix).
- let pstr = "\x20xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
- let mut stream = Cursor::new(pstr);
- // Reader wants to limit the total read length to 32 bytes, so any
- // returned string must be no longer than 31 bytes.
- let s = super::read_fixed_length_pascal_string(&mut stream, 32).unwrap();
- assert_eq!(s.len(), 31);
-}
-
-#[test]
-fn skip_padding_in_boxes() {
- // Padding data could be added in the end of these boxes. Parser needs to skip
- // them instead of returning error.
- let box_names = vec![b"stts", b"stsc", b"stsz", b"stco", b"co64", b"stss"];
-
- for name in box_names {
- let mut stream = make_fullbox(BoxSize::Auto, name, 1, |s| {
- s.append_repeated(0, 100) // add padding data
- });
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- match name {
- b"stts" => {
- super::read_stts(&mut stream).expect("fail to skip padding: stts");
- },
- b"stsc" => {
- super::read_stsc(&mut stream).expect("fail to skip padding: stsc");
- },
- b"stsz" => {
- super::read_stsz(&mut stream).expect("fail to skip padding: stsz");
- },
- b"stco" => {
- super::read_stco(&mut stream).expect("fail to skip padding: stco");
- },
- b"co64" => {
- super::read_co64(&mut stream).expect("fail to skip padding: co64");
- },
- b"stss" => {
- super::read_stss(&mut stream).expect("fail to skip padding: stss");
- },
- _ => (),
- }
- }
-}
-
-#[test]
-fn skip_padding_in_stsd() {
- // Padding data could be added in the end of stsd boxes. Parser needs to skip
- // them instead of returning error.
- let avc = make_box(BoxSize::Auto, b"avc1", |s| {
- s.append_repeated(0, 6)
- .B16(1)
- .append_repeated(0, 16)
- .B16(320)
- .B16(240)
- .append_repeated(0, 14)
- .append_repeated(0, 32)
- .append_repeated(0, 4)
- .B32(0xffffffff)
- .append_bytes(b"avcC")
- .append_repeated(0, 100)
- }).into_inner();
- let mut stream = make_fullbox(BoxSize::Auto, b"stsd", 0, |s| {
- s.B32(1)
- .append_bytes(avc.as_slice())
- .append_repeated(0, 100) // add padding data
- });
-
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- super::read_stsd(&mut stream, &mut super::Track::new(0))
- .expect("fail to skip padding: stsd");
-}
-
-#[test]
-fn read_qt_wave_atom() {
- let esds = make_fullbox(BoxSize::Auto, b"esds", 0, |s| {
- s.B8(0x03) // elementary stream descriptor tag
- .B8(0x0b) // esds length
- .append_repeated(0, 2)
- .B8(0x00) // flags
- .B8(0x04) // decoder config descriptor tag
- .B8(0x0d) // dcds length
- .B8(0x6b) // mp3
- .append_repeated(0, 12)
- }).into_inner();
- let wave = make_box(BoxSize::Auto, b"wave", |s| {
- s.append_bytes(esds.as_slice())
- }).into_inner();
- let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
- s.append_repeated(0, 6)
- .B16(1) // data_reference_count
- .B16(1) // verion: qt -> 1
- .append_repeated(0, 6)
- .B16(2)
- .B16(16)
- .append_repeated(0, 4)
- .B32(48000 << 16)
- .append_repeated(0, 16)
- .append_bytes(wave.as_slice())
- });
-
- let mut iter = super::BoxIter::new(&mut stream);
- let mut stream = iter.next_box().unwrap().unwrap();
- let mut track = super::Track::new(0);
- super::read_audio_sample_entry(&mut stream, &mut track)
- .expect("fail to read qt wave atom");
- assert_eq!(track.codec_type, super::CodecType::MP3);
-}
diff --git a/media/libstagefright/binding/mp4parse/tests/afl.rs b/media/libstagefright/binding/mp4parse/tests/afl.rs
deleted file mode 100644
index d4ffec0df..000000000
--- a/media/libstagefright/binding/mp4parse/tests/afl.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-/// Regression tests from American Fuzzy Lop test cases.
-
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-/// These all caused panics at some point during development.
-
-extern crate mp4parse;
-
-use std::io::Cursor;
-
-/// https://github.com/mozilla/mp4parse-rust/issues/2
-///
-/// Test a box with 4-byte size, smaller than the smallest header.
-#[test]
-fn fuzz_2() {
- let mut c = Cursor::new(b"\x00\x00\x00\x04\xa6\x00\x04\xa6".to_vec());
- let mut context = mp4parse::MediaContext::new();
- let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
-
-/// https://github.com/mozilla/mp4parse-rust/issues/4
-///
-/// Test a large (64 bit) box header with zero declared size.
-#[test]
-fn fuzz_4() {
- let mut c = Cursor::new(b"\x00\x00\x00\x01\x30\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00".to_vec());
- let mut context = mp4parse::MediaContext::new();
- let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
-
-/// https://github.com/mozilla/mp4parse-rust/issues/5
-///
-/// Declares 202116104 compatible brands but does not supply them,
-/// verifying read is properly bounded at the end of the stream.
-#[test]
-fn fuzz_5() {
- let mut c = Cursor::new(b"\x30\x30\x30\x30\x66\x74\x79\x70\x30\x30\x30\x30\x30\x30\x30\x30".to_vec());
- let mut context = mp4parse::MediaContext::new();
- let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
-
-/// https://github.com/mozilla/mp4parse-rust/issues/6
-///
-/// Declares an ftyp box with a single invalid (short - 3 byte) compatible
-/// brand and excludes the extra 3 bytes from the stream.
-#[test]
-fn fuzz_6() {
- let mut c = Cursor::new(b"\x00\x00\x00\x13\x66\x74\x79\x70\x30\x30\x30\x30\x30\x30\x30\x30".to_vec());
- let mut context = mp4parse::MediaContext::new();
- let _ = mp4parse::read_mp4(&mut c, &mut context);
-}
diff --git a/media/libstagefright/binding/mp4parse/tests/minimal.mp4 b/media/libstagefright/binding/mp4parse/tests/minimal.mp4
deleted file mode 100644
index 9fe1e6722..000000000
--- a/media/libstagefright/binding/mp4parse/tests/minimal.mp4
+++ /dev/null
Binary files differ
diff --git a/media/libstagefright/binding/mp4parse/tests/public.rs b/media/libstagefright/binding/mp4parse/tests/public.rs
deleted file mode 100644
index 1d36f5f5a..000000000
--- a/media/libstagefright/binding/mp4parse/tests/public.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-/// Check if needed fields are still public.
-
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-extern crate mp4parse as mp4;
-
-use std::io::{Cursor, Read};
-use std::fs::File;
-
-// Taken from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
-#[test]
-fn public_api() {
- let mut fd = File::open("tests/minimal.mp4").expect("Unknown file");
- let mut buf = Vec::new();
- fd.read_to_end(&mut buf).expect("File error");
-
- let mut c = Cursor::new(&buf);
- let mut context = mp4::MediaContext::new();
- mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
- assert_eq!(context.timescale, Some(mp4::MediaTimeScale(1000)));
- for track in context.tracks {
- match track.data {
- Some(mp4::SampleEntry::Video(v)) => {
- // track part
- assert_eq!(track.duration, Some(mp4::TrackScaledTime(512, 0)));
- assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
- assert_eq!(track.media_time, Some(mp4::TrackScaledTime(0, 0)));
- assert_eq!(track.timescale, Some(mp4::TrackTimeScale(12800, 0)));
- assert_eq!(v.width, 320);
- assert_eq!(v.height, 240);
-
- // track.tkhd part
- let tkhd = track.tkhd.unwrap();
- assert_eq!(tkhd.disabled, false);
- assert_eq!(tkhd.duration, 40);
- assert_eq!(tkhd.width, 20971520);
- assert_eq!(tkhd.height, 15728640);
-
- // track.data part
- assert_eq!(match v.codec_specific {
- mp4::VideoCodecSpecific::AVCConfig(v) => {
- assert!(v.len() > 0);
- "AVC"
- }
- mp4::VideoCodecSpecific::VPxConfig(vpx) => {
- // We don't enter in here, we just check if fields are public.
- assert!(vpx.bit_depth > 0);
- assert!(vpx.color_space > 0);
- assert!(vpx.chroma_subsampling > 0);
- assert!(vpx.codec_init.len() > 0);
- "VPx"
- }
- }, "AVC");
- }
- Some(mp4::SampleEntry::Audio(a)) => {
- // track part
- assert_eq!(track.duration, Some(mp4::TrackScaledTime(2944, 1)));
- assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
- assert_eq!(track.media_time, Some(mp4::TrackScaledTime(1024, 1)));
- assert_eq!(track.timescale, Some(mp4::TrackTimeScale(48000, 1)));
-
- // track.tkhd part
- let tkhd = track.tkhd.unwrap();
- assert_eq!(tkhd.disabled, false);
- assert_eq!(tkhd.duration, 62);
- assert_eq!(tkhd.width, 0);
- assert_eq!(tkhd.height, 0);
-
- // track.data part
- assert_eq!(match a.codec_specific {
- mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
- assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
- assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
- "ES"
- }
- mp4::AudioCodecSpecific::FLACSpecificBox(flac) => {
- // STREAMINFO block must be present and first.
- assert!(flac.blocks.len() > 0);
- assert!(flac.blocks[0].block_type == 0);
- assert!(flac.blocks[0].data.len() == 34);
- "FLAC"
- }
- mp4::AudioCodecSpecific::OpusSpecificBox(opus) => {
- // We don't enter in here, we just check if fields are public.
- assert!(opus.version > 0);
- "Opus"
- }
- }, "ES");
- assert!(a.samplesize > 0);
- assert!(a.samplerate > 0);
- }
- Some(mp4::SampleEntry::Unknown) | None => {}
- }
- }
-}
diff --git a/media/libstagefright/binding/mp4parse_capi/Cargo.toml b/media/libstagefright/binding/mp4parse_capi/Cargo.toml
deleted file mode 100644
index 5c0836abe..000000000
--- a/media/libstagefright/binding/mp4parse_capi/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "mp4parse_capi"
-version = "0.6.0"
-authors = [
- "Ralph Giles <giles@mozilla.com>",
- "Matthew Gregan <kinetik@flim.org>",
- "Alfredo Yang <ayang@mozilla.com>",
-]
-
-description = "Parser for ISO base media file format (mp4)"
-documentation = "https://mp4parse-docs.surge.sh/mp4parse/"
-license = "MPL-2.0"
-
-repository = "https://github.com/mozilla/mp4parse-rust"
-
-# Avoid complaints about trying to package test files.
-exclude = [
- "*.mp4",
-]
-
-[dependencies]
-"mp4parse" = {version = "0.6.0", path = "../mp4parse"}
-
-# Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
-[profile.release]
-debug-assertions = true
diff --git a/media/libstagefright/binding/mp4parse_capi/build.rs b/media/libstagefright/binding/mp4parse_capi/build.rs
deleted file mode 100644
index 29f2a85ce..000000000
--- a/media/libstagefright/binding/mp4parse_capi/build.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-extern crate cheddar;
-
-fn main() {
- println!("cargo:rerun-if-changed=src/lib.rs");
- // Generate mp4parse.h.
- cheddar::Cheddar::new().expect("could not read manifest")
- .insert_code("// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT\n\n")
- .insert_code("// This Source Code Form is subject to the terms of the Mozilla Public\n")
- .insert_code("// License, v. 2.0. If a copy of the MPL was not distributed with this\n")
- .insert_code("// file, You can obtain one at https://mozilla.org/MPL/2.0/.")
- .run_build("include/mp4parse.h");
-}
diff --git a/media/libstagefright/binding/mp4parse_capi/src/lib.rs b/media/libstagefright/binding/mp4parse_capi/src/lib.rs
deleted file mode 100644
index f52d8b169..000000000
--- a/media/libstagefright/binding/mp4parse_capi/src/lib.rs
+++ /dev/null
@@ -1,870 +0,0 @@
-//! C API for mp4parse module.
-//!
-//! Parses ISO Base Media Format aka video/mp4 streams.
-//!
-//! # Examples
-//!
-//! ```rust
-//! extern crate mp4parse_capi;
-//! use std::io::Read;
-//!
-//! extern fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
-//! let mut input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
-//! let mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
-//! match input.read(&mut buf) {
-//! Ok(n) => n as isize,
-//! Err(_) => -1,
-//! }
-//! }
-//!
-//! let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
-//! let io = mp4parse_capi::mp4parse_io {
-//! read: buf_read,
-//! userdata: &mut file as *mut _ as *mut std::os::raw::c_void
-//! };
-//! unsafe {
-//! let parser = mp4parse_capi::mp4parse_new(&io);
-//! let rv = mp4parse_capi::mp4parse_read(parser);
-//! assert_eq!(rv, mp4parse_capi::mp4parse_error::MP4PARSE_OK);
-//! mp4parse_capi::mp4parse_free(parser);
-//! }
-//! ```
-
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-extern crate mp4parse;
-
-use std::io::Read;
-use std::collections::HashMap;
-
-// Symbols we need from our rust api.
-use mp4parse::MediaContext;
-use mp4parse::TrackType;
-use mp4parse::read_mp4;
-use mp4parse::Error;
-use mp4parse::SampleEntry;
-use mp4parse::AudioCodecSpecific;
-use mp4parse::VideoCodecSpecific;
-use mp4parse::MediaTimeScale;
-use mp4parse::MediaScaledTime;
-use mp4parse::TrackTimeScale;
-use mp4parse::TrackScaledTime;
-use mp4parse::serialize_opus_header;
-use mp4parse::CodecType;
-
-// rusty-cheddar's C enum generation doesn't namespace enum members by
-// prefixing them, so we're forced to do it in our member names until
-// https://github.com/Sean1708/rusty-cheddar/pull/35 is fixed. Importing
-// the members into the module namespace avoids doubling up on the
-// namespacing on the Rust side.
-use mp4parse_error::*;
-use mp4parse_track_type::*;
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub enum mp4parse_error {
- MP4PARSE_OK = 0,
- MP4PARSE_ERROR_BADARG = 1,
- MP4PARSE_ERROR_INVALID = 2,
- MP4PARSE_ERROR_UNSUPPORTED = 3,
- MP4PARSE_ERROR_EOF = 4,
- MP4PARSE_ERROR_IO = 5,
-}
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub enum mp4parse_track_type {
- MP4PARSE_TRACK_TYPE_VIDEO = 0,
- MP4PARSE_TRACK_TYPE_AUDIO = 1,
-}
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub enum mp4parse_codec {
- MP4PARSE_CODEC_UNKNOWN,
- MP4PARSE_CODEC_AAC,
- MP4PARSE_CODEC_FLAC,
- MP4PARSE_CODEC_OPUS,
- MP4PARSE_CODEC_AVC,
- MP4PARSE_CODEC_VP9,
- MP4PARSE_CODEC_MP3,
-}
-
-#[repr(C)]
-pub struct mp4parse_track_info {
- pub track_type: mp4parse_track_type,
- pub codec: mp4parse_codec,
- pub track_id: u32,
- pub duration: u64,
- pub media_time: i64, // wants to be u64? understand how elst adjustment works
- // TODO(kinetik): include crypto guff
-}
-
-#[repr(C)]
-pub struct mp4parse_codec_specific_config {
- pub length: u32,
- pub data: *const u8,
-}
-
-impl Default for mp4parse_codec_specific_config {
- fn default() -> Self {
- mp4parse_codec_specific_config {
- length: 0,
- data: std::ptr::null_mut(),
- }
- }
-}
-
-#[derive(Default)]
-#[repr(C)]
-pub struct mp4parse_track_audio_info {
- pub channels: u16,
- pub bit_depth: u16,
- pub sample_rate: u32,
- // TODO(kinetik):
- // int32_t profile;
- // int32_t extended_profile; // check types
- codec_specific_config: mp4parse_codec_specific_config,
-}
-
-#[repr(C)]
-pub struct mp4parse_track_video_info {
- pub display_width: u32,
- pub display_height: u32,
- pub image_width: u16,
- pub image_height: u16,
- // TODO(kinetik):
- // extra_data
- // codec_specific_config
-}
-
-#[repr(C)]
-pub struct mp4parse_fragment_info {
- pub fragment_duration: u64,
- // TODO:
- // info in trex box.
-}
-
-// Even though mp4parse_parser is opaque to C, rusty-cheddar won't let us
-// use more than one member, so we introduce *another* wrapper.
-struct Wrap {
- context: MediaContext,
- io: mp4parse_io,
- poisoned: bool,
- opus_header: HashMap<u32, Vec<u8>>,
-}
-
-#[repr(C)]
-#[allow(non_camel_case_types)]
-pub struct mp4parse_parser(Wrap);
-
-impl mp4parse_parser {
- fn context(&self) -> &MediaContext {
- &self.0.context
- }
-
- fn context_mut(&mut self) -> &mut MediaContext {
- &mut self.0.context
- }
-
- fn io_mut(&mut self) -> &mut mp4parse_io {
- &mut self.0.io
- }
-
- fn poisoned(&self) -> bool {
- self.0.poisoned
- }
-
- fn set_poisoned(&mut self, poisoned: bool) {
- self.0.poisoned = poisoned;
- }
-
- fn opus_header_mut(&mut self) -> &mut HashMap<u32, Vec<u8>> {
- &mut self.0.opus_header
- }
-}
-
-#[repr(C)]
-#[derive(Clone)]
-pub struct mp4parse_io {
- pub read: extern fn(buffer: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize,
- pub userdata: *mut std::os::raw::c_void,
-}
-
-impl Read for mp4parse_io {
- fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- if buf.len() > isize::max_value() as usize {
- return Err(std::io::Error::new(std::io::ErrorKind::Other, "buf length overflow in mp4parse_io Read impl"));
- }
- let rv = (self.read)(buf.as_mut_ptr(), buf.len(), self.userdata);
- if rv >= 0 {
- Ok(rv as usize)
- } else {
- Err(std::io::Error::new(std::io::ErrorKind::Other, "I/O error in mp4parse_io Read impl"))
- }
- }
-}
-
-// C API wrapper functions.
-
-/// Allocate an `mp4parse_parser*` to read from the supplied `mp4parse_io`.
-#[no_mangle]
-pub unsafe extern fn mp4parse_new(io: *const mp4parse_io) -> *mut mp4parse_parser {
- if io.is_null() || (*io).userdata.is_null() {
- return std::ptr::null_mut();
- }
- // is_null() isn't available on a fn type because it can't be null (in
- // Rust) by definition. But since this value is coming from the C API,
- // it *could* be null. Ideally, we'd wrap it in an Option to represent
- // reality, but this causes rusty-cheddar to emit the wrong type
- // (https://github.com/Sean1708/rusty-cheddar/issues/30).
- if ((*io).read as *mut std::os::raw::c_void).is_null() {
- return std::ptr::null_mut();
- }
- let parser = Box::new(mp4parse_parser(Wrap {
- context: MediaContext::new(),
- io: (*io).clone(),
- poisoned: false,
- opus_header: HashMap::new(),
- }));
- Box::into_raw(parser)
-}
-
-/// Free an `mp4parse_parser*` allocated by `mp4parse_new()`.
-#[no_mangle]
-pub unsafe extern fn mp4parse_free(parser: *mut mp4parse_parser) {
- assert!(!parser.is_null());
- let _ = Box::from_raw(parser);
-}
-
-/// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
-#[no_mangle]
-pub unsafe extern fn mp4parse_read(parser: *mut mp4parse_parser) -> mp4parse_error {
- // Validate arguments from C.
- if parser.is_null() || (*parser).poisoned() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let mut context = (*parser).context_mut();
- let mut io = (*parser).io_mut();
-
- let r = read_mp4(io, context);
- match r {
- Ok(_) => MP4PARSE_OK,
- Err(Error::NoMoov) | Err(Error::InvalidData(_)) => {
- // Block further calls. We've probable lost sync.
- (*parser).set_poisoned(true);
- MP4PARSE_ERROR_INVALID
- }
- Err(Error::Unsupported(_)) => MP4PARSE_ERROR_UNSUPPORTED,
- Err(Error::UnexpectedEOF) => MP4PARSE_ERROR_EOF,
- Err(Error::Io(_)) => {
- // Block further calls after a read failure.
- // Getting std::io::ErrorKind::UnexpectedEof is normal
- // but our From trait implementation should have converted
- // those to our Error::UnexpectedEOF variant.
- (*parser).set_poisoned(true);
- MP4PARSE_ERROR_IO
- }
- }
-}
-
-/// Return the number of tracks parsed by previous `mp4parse_read()` call.
-#[no_mangle]
-pub unsafe extern fn mp4parse_get_track_count(parser: *const mp4parse_parser, count: *mut u32) -> mp4parse_error {
- // Validate arguments from C.
- if parser.is_null() || count.is_null() || (*parser).poisoned() {
- return MP4PARSE_ERROR_BADARG;
- }
- let context = (*parser).context();
-
- // Make sure the track count fits in a u32.
- if context.tracks.len() > u32::max_value() as usize {
- return MP4PARSE_ERROR_INVALID;
- }
- *count = context.tracks.len() as u32;
- MP4PARSE_OK
-}
-
-/// Calculate numerator * scale / denominator, if possible.
-///
-/// Applying the associativity of integer arithmetic, we divide first
-/// and add the remainder after multiplying each term separately
-/// to preserve precision while leaving more headroom. That is,
-/// (n * s) / d is split into floor(n / d) * s + (n % d) * s / d.
-///
-/// Return None on overflow or if the denominator is zero.
-fn rational_scale(numerator: u64, denominator: u64, scale: u64) -> Option<u64> {
- if denominator == 0 {
- return None;
- }
- let integer = numerator / denominator;
- let remainder = numerator % denominator;
- match integer.checked_mul(scale) {
- Some(integer) => remainder.checked_mul(scale)
- .and_then(|remainder| (remainder/denominator).checked_add(integer)),
- None => None,
- }
-}
-
-fn media_time_to_us(time: MediaScaledTime, scale: MediaTimeScale) -> Option<u64> {
- let microseconds_per_second = 1000000;
- rational_scale(time.0, scale.0, microseconds_per_second)
-}
-
-fn track_time_to_us(time: TrackScaledTime, scale: TrackTimeScale) -> Option<u64> {
- assert!(time.1 == scale.1);
- let microseconds_per_second = 1000000;
- rational_scale(time.0, scale.0, microseconds_per_second)
-}
-
-/// Fill the supplied `mp4parse_track_info` with metadata for `track`.
-#[no_mangle]
-pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track_index: u32, info: *mut mp4parse_track_info) -> mp4parse_error {
- if parser.is_null() || info.is_null() || (*parser).poisoned() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let context = (*parser).context_mut();
- let track_index: usize = track_index as usize;
- let info: &mut mp4parse_track_info = &mut *info;
-
- if track_index >= context.tracks.len() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- info.track_type = match context.tracks[track_index].track_type {
- TrackType::Video => MP4PARSE_TRACK_TYPE_VIDEO,
- TrackType::Audio => MP4PARSE_TRACK_TYPE_AUDIO,
- TrackType::Unknown => return MP4PARSE_ERROR_UNSUPPORTED,
- };
-
- info.codec = match context.tracks[track_index].data {
- Some(SampleEntry::Audio(ref audio)) => match audio.codec_specific {
- AudioCodecSpecific::OpusSpecificBox(_) =>
- mp4parse_codec::MP4PARSE_CODEC_OPUS,
- AudioCodecSpecific::FLACSpecificBox(_) =>
- mp4parse_codec::MP4PARSE_CODEC_FLAC,
- AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::AAC =>
- mp4parse_codec::MP4PARSE_CODEC_AAC,
- AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 =>
- mp4parse_codec::MP4PARSE_CODEC_MP3,
- AudioCodecSpecific::ES_Descriptor(_) =>
- mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
- },
- Some(SampleEntry::Video(ref video)) => match video.codec_specific {
- VideoCodecSpecific::VPxConfig(_) =>
- mp4parse_codec::MP4PARSE_CODEC_VP9,
- VideoCodecSpecific::AVCConfig(_) =>
- mp4parse_codec::MP4PARSE_CODEC_AVC,
- },
- _ => mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
- };
-
- let track = &context.tracks[track_index];
-
- if let (Some(track_timescale),
- Some(context_timescale)) = (track.timescale,
- context.timescale) {
- let media_time =
- match track.media_time.map_or(Some(0), |media_time| {
- track_time_to_us(media_time, track_timescale) }) {
- Some(time) => time as i64,
- None => return MP4PARSE_ERROR_INVALID,
- };
- let empty_duration =
- match track.empty_duration.map_or(Some(0), |empty_duration| {
- media_time_to_us(empty_duration, context_timescale) }) {
- Some(time) => time as i64,
- None => return MP4PARSE_ERROR_INVALID,
- };
- info.media_time = media_time - empty_duration;
-
- if let Some(track_duration) = track.duration {
- match track_time_to_us(track_duration, track_timescale) {
- Some(duration) => info.duration = duration,
- None => return MP4PARSE_ERROR_INVALID,
- }
- } else {
- // Duration unknown; stagefright returns 0 for this.
- info.duration = 0
- }
- } else {
- return MP4PARSE_ERROR_INVALID
- }
-
- info.track_id = match track.track_id {
- Some(track_id) => track_id,
- None => return MP4PARSE_ERROR_INVALID,
- };
-
- MP4PARSE_OK
-}
-
-/// Fill the supplied `mp4parse_track_audio_info` with metadata for `track`.
-#[no_mangle]
-pub unsafe extern fn mp4parse_get_track_audio_info(parser: *mut mp4parse_parser, track_index: u32, info: *mut mp4parse_track_audio_info) -> mp4parse_error {
- if parser.is_null() || info.is_null() || (*parser).poisoned() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let context = (*parser).context_mut();
-
- if track_index as usize >= context.tracks.len() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let track = &context.tracks[track_index as usize];
-
- match track.track_type {
- TrackType::Audio => {}
- _ => return MP4PARSE_ERROR_INVALID,
- };
-
- let audio = match track.data {
- Some(ref data) => data,
- None => return MP4PARSE_ERROR_INVALID,
- };
-
- let audio = match *audio {
- SampleEntry::Audio(ref x) => x,
- _ => return MP4PARSE_ERROR_INVALID,
- };
-
- (*info).channels = audio.channelcount;
- (*info).bit_depth = audio.samplesize;
- (*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point
-
- match audio.codec_specific {
- AudioCodecSpecific::ES_Descriptor(ref v) => {
- if v.codec_specific_config.len() > std::u32::MAX as usize {
- return MP4PARSE_ERROR_INVALID;
- }
- (*info).codec_specific_config.length = v.codec_specific_config.len() as u32;
- (*info).codec_specific_config.data = v.codec_specific_config.as_ptr();
- if let Some(rate) = v.audio_sample_rate {
- (*info).sample_rate = rate;
- }
- if let Some(channels) = v.audio_channel_count {
- (*info).channels = channels;
- }
- }
- AudioCodecSpecific::FLACSpecificBox(ref flac) => {
- // Return the STREAMINFO metadata block in the codec_specific.
- let streaminfo = &flac.blocks[0];
- if streaminfo.block_type != 0 || streaminfo.data.len() != 34 {
- return MP4PARSE_ERROR_INVALID;
- }
- (*info).codec_specific_config.length = streaminfo.data.len() as u32;
- (*info).codec_specific_config.data = streaminfo.data.as_ptr();
- }
- AudioCodecSpecific::OpusSpecificBox(ref opus) => {
- let mut v = Vec::new();
- match serialize_opus_header(opus, &mut v) {
- Err(_) => {
- return MP4PARSE_ERROR_INVALID;
- }
- Ok(_) => {
- let header = (*parser).opus_header_mut();
- header.insert(track_index, v);
- match header.get(&track_index) {
- None => {}
- Some(v) => {
- if v.len() > std::u32::MAX as usize {
- return MP4PARSE_ERROR_INVALID;
- }
- (*info).codec_specific_config.length = v.len() as u32;
- (*info).codec_specific_config.data = v.as_ptr();
- }
- }
- }
- }
- }
- }
-
- MP4PARSE_OK
-}
-
-/// Fill the supplied `mp4parse_track_video_info` with metadata for `track`.
-#[no_mangle]
-pub unsafe extern fn mp4parse_get_track_video_info(parser: *mut mp4parse_parser, track_index: u32, info: *mut mp4parse_track_video_info) -> mp4parse_error {
- if parser.is_null() || info.is_null() || (*parser).poisoned() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let context = (*parser).context_mut();
-
- if track_index as usize >= context.tracks.len() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let track = &context.tracks[track_index as usize];
-
- match track.track_type {
- TrackType::Video => {}
- _ => return MP4PARSE_ERROR_INVALID,
- };
-
- let video = match track.data {
- Some(ref data) => data,
- None => return MP4PARSE_ERROR_INVALID,
- };
-
- let video = match *video {
- SampleEntry::Video(ref x) => x,
- _ => return MP4PARSE_ERROR_INVALID,
- };
-
- if let Some(ref tkhd) = track.tkhd {
- (*info).display_width = tkhd.width >> 16; // 16.16 fixed point
- (*info).display_height = tkhd.height >> 16; // 16.16 fixed point
- } else {
- return MP4PARSE_ERROR_INVALID;
- }
- (*info).image_width = video.width;
- (*info).image_height = video.height;
-
- MP4PARSE_OK
-}
-
-#[no_mangle]
-pub unsafe extern fn mp4parse_get_fragment_info(parser: *mut mp4parse_parser, info: *mut mp4parse_fragment_info) -> mp4parse_error {
- if parser.is_null() || info.is_null() || (*parser).poisoned() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let context = (*parser).context();
- let info: &mut mp4parse_fragment_info = &mut *info;
-
- info.fragment_duration = 0;
-
- let duration = match context.mvex {
- Some(ref mvex) => mvex.fragment_duration,
- None => return MP4PARSE_ERROR_INVALID,
- };
-
- if let (Some(time), Some(scale)) = (duration, context.timescale) {
- info.fragment_duration = match media_time_to_us(time, scale) {
- Some(time_us) => time_us as u64,
- None => return MP4PARSE_ERROR_INVALID,
- }
- }
-
- MP4PARSE_OK
-}
-
-// A fragmented file needs mvex table and contains no data in stts, stsc, and stco boxes.
-#[no_mangle]
-pub unsafe extern fn mp4parse_is_fragmented(parser: *mut mp4parse_parser, track_id: u32, fragmented: *mut u8) -> mp4parse_error {
- if parser.is_null() || (*parser).poisoned() {
- return MP4PARSE_ERROR_BADARG;
- }
-
- let context = (*parser).context_mut();
- let tracks = &context.tracks;
- (*fragmented) = false as u8;
-
- if context.mvex.is_none() {
- return MP4PARSE_OK;
- }
-
- // check sample tables.
- let mut iter = tracks.iter();
- match iter.find(|track| track.track_id == Some(track_id)) {
- Some(track) if track.empty_sample_boxes.all_empty() => (*fragmented) = true as u8,
- Some(_) => {},
- None => return MP4PARSE_ERROR_BADARG,
- }
-
- MP4PARSE_OK
-}
-
-#[cfg(test)]
-extern fn panic_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
- panic!("panic_read shouldn't be called in these tests");
-}
-
-#[cfg(test)]
-extern fn error_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
- -1
-}
-
-#[cfg(test)]
-extern fn valid_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
- let mut input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
-
- let mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
- match input.read(&mut buf) {
- Ok(n) => n as isize,
- Err(_) => -1,
- }
-}
-
-#[test]
-fn new_parser() {
- let mut dummy_value: u32 = 42;
- let io = mp4parse_io {
- read: panic_read,
- userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
- };
- unsafe {
- let parser = mp4parse_new(&io);
- assert!(!parser.is_null());
- mp4parse_free(parser);
- }
-}
-
-#[test]
-#[should_panic(expected = "assertion failed")]
-fn free_null_parser() {
- unsafe {
- mp4parse_free(std::ptr::null_mut());
- }
-}
-
-#[test]
-fn get_track_count_null_parser() {
- unsafe {
- let mut count: u32 = 0;
- let rv = mp4parse_get_track_count(std::ptr::null(), std::ptr::null_mut());
- assert!(rv == MP4PARSE_ERROR_BADARG);
- let rv = mp4parse_get_track_count(std::ptr::null(), &mut count);
- assert!(rv == MP4PARSE_ERROR_BADARG);
- }
-}
-
-#[test]
-fn arg_validation() {
- unsafe {
- // Passing a null mp4parse_io is an error.
- let parser = mp4parse_new(std::ptr::null());
- assert!(parser.is_null());
-
- let null_mut: *mut std::os::raw::c_void = std::ptr::null_mut();
-
- // Passing an mp4parse_io with null members is an error.
- let io = mp4parse_io { read: std::mem::transmute(null_mut),
- userdata: null_mut };
- let parser = mp4parse_new(&io);
- assert!(parser.is_null());
-
- let io = mp4parse_io { read: panic_read,
- userdata: null_mut };
- let parser = mp4parse_new(&io);
- assert!(parser.is_null());
-
- let mut dummy_value = 42;
- let io = mp4parse_io {
- read: std::mem::transmute(null_mut),
- userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
- };
- let parser = mp4parse_new(&io);
- assert!(parser.is_null());
-
- // Passing a null mp4parse_parser is an error.
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_read(std::ptr::null_mut()));
-
- let mut dummy_info = mp4parse_track_info {
- track_type: MP4PARSE_TRACK_TYPE_VIDEO,
- codec: mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
- track_id: 0,
- duration: 0,
- media_time: 0,
- };
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_info(std::ptr::null_mut(), 0, &mut dummy_info));
-
- let mut dummy_video = mp4parse_track_video_info {
- display_width: 0,
- display_height: 0,
- image_width: 0,
- image_height: 0,
- };
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_video_info(std::ptr::null_mut(), 0, &mut dummy_video));
-
- let mut dummy_audio = Default::default();
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_audio_info(std::ptr::null_mut(), 0, &mut dummy_audio));
- }
-}
-
-#[test]
-fn arg_validation_with_parser() {
- unsafe {
- let mut dummy_value = 42;
- let io = mp4parse_io {
- read: error_read,
- userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
- };
- let parser = mp4parse_new(&io);
- assert!(!parser.is_null());
-
- // Our mp4parse_io read should simply fail with an error.
- assert_eq!(MP4PARSE_ERROR_IO, mp4parse_read(parser));
-
- // The parser is now poisoned and unusable.
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_read(parser));
-
- // Null info pointers are an error.
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_info(parser, 0, std::ptr::null_mut()));
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_video_info(parser, 0, std::ptr::null_mut()));
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_audio_info(parser, 0, std::ptr::null_mut()));
-
- let mut dummy_info = mp4parse_track_info {
- track_type: MP4PARSE_TRACK_TYPE_VIDEO,
- codec: mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
- track_id: 0,
- duration: 0,
- media_time: 0,
- };
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_info(parser, 0, &mut dummy_info));
-
- let mut dummy_video = mp4parse_track_video_info {
- display_width: 0,
- display_height: 0,
- image_width: 0,
- image_height: 0,
- };
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_video_info(parser, 0, &mut dummy_video));
-
- let mut dummy_audio = Default::default();
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_audio_info(parser, 0, &mut dummy_audio));
-
- mp4parse_free(parser);
- }
-}
-
-#[test]
-fn get_track_count_poisoned_parser() {
- unsafe {
- let mut dummy_value = 42;
- let io = mp4parse_io {
- read: error_read,
- userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
- };
- let parser = mp4parse_new(&io);
- assert!(!parser.is_null());
-
- // Our mp4parse_io read should simply fail with an error.
- assert_eq!(MP4PARSE_ERROR_IO, mp4parse_read(parser));
-
- let mut count: u32 = 0;
- let rv = mp4parse_get_track_count(parser, &mut count);
- assert!(rv == MP4PARSE_ERROR_BADARG);
- }
-}
-
-#[test]
-fn arg_validation_with_data() {
- unsafe {
- let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
- let io = mp4parse_io { read: valid_read,
- userdata: &mut file as *mut _ as *mut std::os::raw::c_void };
- let parser = mp4parse_new(&io);
- assert!(!parser.is_null());
-
- assert_eq!(MP4PARSE_OK, mp4parse_read(parser));
-
- let mut count: u32 = 0;
- assert_eq!(MP4PARSE_OK, mp4parse_get_track_count(parser, &mut count));
- assert_eq!(2, count);
-
- let mut info = mp4parse_track_info {
- track_type: MP4PARSE_TRACK_TYPE_VIDEO,
- codec: mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
- track_id: 0,
- duration: 0,
- media_time: 0,
- };
- assert_eq!(MP4PARSE_OK, mp4parse_get_track_info(parser, 0, &mut info));
- assert_eq!(info.track_type, MP4PARSE_TRACK_TYPE_VIDEO);
- assert_eq!(info.codec, mp4parse_codec::MP4PARSE_CODEC_AVC);
- assert_eq!(info.track_id, 1);
- assert_eq!(info.duration, 40000);
- assert_eq!(info.media_time, 0);
-
- assert_eq!(MP4PARSE_OK, mp4parse_get_track_info(parser, 1, &mut info));
- assert_eq!(info.track_type, MP4PARSE_TRACK_TYPE_AUDIO);
- assert_eq!(info.codec, mp4parse_codec::MP4PARSE_CODEC_AAC);
- assert_eq!(info.track_id, 2);
- assert_eq!(info.duration, 61333);
- assert_eq!(info.media_time, 21333);
-
- let mut video = mp4parse_track_video_info {
- display_width: 0,
- display_height: 0,
- image_width: 0,
- image_height: 0,
- };
- assert_eq!(MP4PARSE_OK, mp4parse_get_track_video_info(parser, 0, &mut video));
- assert_eq!(video.display_width, 320);
- assert_eq!(video.display_height, 240);
- assert_eq!(video.image_width, 320);
- assert_eq!(video.image_height, 240);
-
- let mut audio = Default::default();
- assert_eq!(MP4PARSE_OK, mp4parse_get_track_audio_info(parser, 1, &mut audio));
- assert_eq!(audio.channels, 1);
- assert_eq!(audio.bit_depth, 16);
- assert_eq!(audio.sample_rate, 48000);
-
- // Test with an invalid track number.
- let mut info = mp4parse_track_info {
- track_type: MP4PARSE_TRACK_TYPE_VIDEO,
- codec: mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
- track_id: 0,
- duration: 0,
- media_time: 0,
- };
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_info(parser, 3, &mut info));
- assert_eq!(info.track_type, MP4PARSE_TRACK_TYPE_VIDEO);
- assert_eq!(info.codec, mp4parse_codec::MP4PARSE_CODEC_UNKNOWN);
- assert_eq!(info.track_id, 0);
- assert_eq!(info.duration, 0);
- assert_eq!(info.media_time, 0);
-
- let mut video = mp4parse_track_video_info { display_width: 0,
- display_height: 0,
- image_width: 0,
- image_height: 0 };
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_video_info(parser, 3, &mut video));
- assert_eq!(video.display_width, 0);
- assert_eq!(video.display_height, 0);
- assert_eq!(video.image_width, 0);
- assert_eq!(video.image_height, 0);
-
- let mut audio = Default::default();
- assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_audio_info(parser, 3, &mut audio));
- assert_eq!(audio.channels, 0);
- assert_eq!(audio.bit_depth, 0);
- assert_eq!(audio.sample_rate, 0);
-
- mp4parse_free(parser);
- }
-}
-
-#[test]
-fn rational_scale_overflow() {
- assert_eq!(rational_scale(17, 3, 1000), Some(5666));
- let large = 0x4000_0000_0000_0000;
- assert_eq!(rational_scale(large, 2, 2), Some(large));
- assert_eq!(rational_scale(large, 4, 4), Some(large));
- assert_eq!(rational_scale(large, 2, 8), None);
- assert_eq!(rational_scale(large, 8, 4), Some(large/2));
- assert_eq!(rational_scale(large + 1, 4, 4), Some(large+1));
- assert_eq!(rational_scale(large, 40, 1000), None);
-}
-
-#[test]
-fn media_time_overflow() {
- let scale = MediaTimeScale(90000);
- let duration = MediaScaledTime(9007199254710000);
- assert_eq!(media_time_to_us(duration, scale), Some(100079991719000000));
-}
-
-#[test]
-fn track_time_overflow() {
- let scale = TrackTimeScale(44100, 0);
- let duration = TrackScaledTime(4413527634807900, 0);
- assert_eq!(track_time_to_us(duration, scale), Some(100079991719000000));
-}
diff --git a/media/libstagefright/binding/update-rust.sh b/media/libstagefright/binding/update-rust.sh
deleted file mode 100755
index a8a462f6d..000000000
--- a/media/libstagefright/binding/update-rust.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh -e
-# Script to update mp4parse-rust sources to latest upstream
-
-# Default version.
-VER=v0.6.0
-
-# Accept version or commit from the command line.
-if test -n "$1"; then
- VER=$1
-fi
-
-echo "Fetching sources..."
-rm -rf _upstream
-git clone https://github.com/mozilla/mp4parse-rust _upstream/mp4parse
-pushd _upstream/mp4parse
-git checkout ${VER}
-echo "Verifying sources..."
-pushd mp4parse
-cargo test
-popd
-echo "Constructing C api header..."
-pushd mp4parse_capi
-cargo build
-echo "Verifying sources..."
-cargo test
-popd
-popd
-rm -rf mp4parse
-mkdir -p mp4parse/src
-cp _upstream/mp4parse/mp4parse/Cargo.toml mp4parse/
-cp _upstream/mp4parse/mp4parse/src/*.rs mp4parse/src/
-mkdir -p mp4parse/tests
-cp _upstream/mp4parse/mp4parse/tests/*.rs mp4parse/tests/
-cp _upstream/mp4parse/mp4parse/tests/*.mp4 mp4parse/tests/
-rm -rf mp4parse_capi
-mkdir -p mp4parse_capi/src
-cp _upstream/mp4parse/mp4parse_capi/Cargo.toml mp4parse_capi/
-cp _upstream/mp4parse/mp4parse_capi/build.rs mp4parse_capi/
-cp _upstream/mp4parse/mp4parse_capi/include/mp4parse.h include/
-cp _upstream/mp4parse/mp4parse_capi/src/*.rs mp4parse_capi/src/
-
-echo "Applying patches..."
-patch -p4 < mp4parse-cargo.patch
-
-echo "Cleaning up..."
-rm -rf _upstream
-
-echo "Updating gecko Cargo.lock..."
-pushd ../../../toolkit/library/rust/
-cargo update --package mp4parse_capi
-popd
-pushd ../../../toolkit/library/gtest/rust/
-cargo update --package mp4parse_capi
-popd
-
-echo "Updated to ${VER}."