Bug 1839391 - Switch WebM demuxer to use mOriginalPresentationWindow to trim packets. r=alwu

The AudioTrimmer change is to properly implement a behaviour Gecko has about
the DiscardPadding WebM element. If it's invalid (negative, present more than
once, spanning multiple packets), the decoder is supposed to reject the file.

This is tested by the files:

  invalid-discard_on_multi_blocks.webm
  invalid-excess_discard.webm
  invalid-excess_neg_discard.webm
  invalid-neg_discard.webm

in test_invalid_reject.html.

Since the demuxer now handles those trimming concerns, we simply flag the packet
has needing to be rejected, by making it have an duration that's a
TimeUnit::Invalid(), and letting the AudioTrimmer reject it.

The rest is straightforward.

Differential Revision: https://phabricator.services.mozilla.com/D181523
This commit is contained in:
Paul Adenot 2023-08-08 12:12:47 +00:00
Родитель d2caeb9b64
Коммит 5f6c5765b7
3 изменённых файлов: 31 добавлений и 14 удалений

Просмотреть файл

@ -116,6 +116,11 @@ RefPtr<MediaDataDecoder::DecodePromise> AudioTrimmer::HandleDecodedResult(
for (uint32_t i = 0; i < results.Length();) {
const RefPtr<MediaData>& data = results[i];
MOZ_ASSERT(data->mType == MediaData::Type::AUDIO_DATA);
if (!data->mDuration.IsValid()) {
return DecodePromise::CreateAndReject(std::move(aValue.RejectValue()),
__func__);
}
TimeInterval sampleInterval(data->mTime, data->GetEndTime());
if (mTrimmers.IsEmpty()) {
// mTrimmers being empty can only occurs if the decoder returned more

Просмотреть файл

@ -235,6 +235,7 @@ already_AddRefed<MediaTrackDemuxer> WebMDemuxer::GetTrackDemuxer(
}
void WebMDemuxer::Reset(TrackInfo::TrackType aType) {
mProcessedDiscardPadding = false;
if (aType == TrackInfo::kVideoTrack) {
mVideoPackets.Reset();
} else {
@ -416,11 +417,12 @@ nsresult WebMDemuxer::ReadMetadata() {
uint64_t codecDelayUs = params.codec_delay / 1000;
mInfo.mAudio.mMimeType = "audio/opus";
OpusCodecSpecificData opusCodecSpecificData;
opusCodecSpecificData.mContainerCodecDelayMicroSeconds =
AssertedCast<int64_t>(codecDelayUs);
opusCodecSpecificData.mContainerCodecDelayFrames =
AssertedCast<int64_t>(USECS_PER_S * codecDelayUs / 48000);
mInfo.mAudio.mCodecSpecificConfig =
AudioCodecSpecificVariant{std::move(opusCodecSpecificData)};
WEBM_DEBUG("Preroll for Opus: %" PRIu64, codecDelayUs);
WEBM_DEBUG("Preroll for Opus: %" PRIu64 " frames",
opusCodecSpecificData.mContainerCodecDelayFrames);
}
mSeekPreroll = params.seek_preroll;
mInfo.mAudio.mRate = AssertedCast<uint32_t>(params.rate);
@ -739,20 +741,25 @@ nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType,
sample->mOffset = holder->Offset();
sample->mKeyframe = isKeyframe;
if (discardPadding && i == count - 1) {
CheckedInt64 discardFrames;
sample->mOriginalPresentationWindow =
Some(media::TimeInterval{sample->mTime, sample->GetEndTime()});
if (discardPadding < 0) {
// This is an invalid value as discard padding should never be negative.
// Set to maximum value so that the decoder will reject it as it's
// greater than the number of frames available.
discardFrames = INT32_MAX;
WEBM_DEBUG("Invalid negative discard padding");
// This will ensure decoding will error out, and the file is rejected.
sample->mDuration = TimeUnit::Invalid();
} else {
discardFrames = TimeUnitToFrames(
TimeUnit::FromNanoseconds(discardPadding), mInfo.mAudio.mRate);
}
if (discardFrames.isValid()) {
sample->mDiscardPadding = discardFrames.value();
TimeUnit padding = TimeUnit::FromNanoseconds(discardPadding);
if (padding > sample->mDuration || mProcessedDiscardPadding) {
WEBM_DEBUG(
"Padding frames larger than packet size, flagging the packet for "
"error (padding: %s, duration: %s, already processed: %s)",
padding.ToString().get(), sample->mDuration.ToString().get(),
mProcessedDiscardPadding ? "true" : "false");
sample->mDuration = TimeUnit::Invalid();
} else {
sample->mDuration -= padding;
}
}
mProcessedDiscardPadding = true;
}
if (packetEncryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED ||

Просмотреть файл

@ -238,6 +238,11 @@ class WebMDemuxer : public MediaDataDemuxer,
// as nestegg only performs 1-byte read at a time.
int64_t mLastWebMBlockOffset;
const bool mIsMediaSource;
// Discard padding in WebM cannot occur more than once. This is set to true if
// a discard padding element has been found and processed, and the decoding is
// expected to error out if another discard padding element is found
// subsequently in the byte stream.
bool mProcessedDiscardPadding = false;
EncryptionInfo mCrypto;
};