Bug 1788557 - Return MediaResult from WebMBufferedParser::Append to expose more details on error. r=alwu

Differential Revision: https://phabricator.services.mozilla.com/D156678
This commit is contained in:
Andreas Pehrson 2022-09-15 22:17:26 +00:00
Родитель 5414a94fa3
Коммит 2325f95234
4 изменённых файлов: 86 добавлений и 46 удалений

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

@ -10,6 +10,20 @@
using namespace mozilla;
std::ostream& operator<<(std::ostream& aStream, nsresult aResult) {
return aStream << GetStaticErrorName(aResult);
}
namespace mozilla {
std::ostream& operator<<(std::ostream& aStream, const MediaResult& aResult) {
aStream << aResult.Code();
if (!aResult.Message().IsEmpty()) {
aStream << " (" << aResult.Message() << ")";
}
return aStream;
}
} // namespace mozilla
// "test.webm" contains 8 SimpleBlocks in a single Cluster. The blocks with
// timecodes 100000000 and are 133000000 skipped by WebMBufferedParser
// because they occur after a block with timecode 160000000 and the parser
@ -24,13 +38,13 @@ TEST(WebMBuffered, BasicTests)
WebMBufferedParser parser(0);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_TRUE(parser.Append(nullptr, 0, mapping));
EXPECT_EQ(parser.Append(nullptr, 0, mapping), NS_OK);
EXPECT_TRUE(mapping.IsEmpty());
EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, 0);
unsigned char buf[] = {0x1a, 0x45, 0xdf, 0xa3};
EXPECT_TRUE(parser.Append(buf, ArrayLength(buf), mapping));
EXPECT_EQ(parser.Append(buf, ArrayLength(buf), mapping), NS_OK);
EXPECT_TRUE(mapping.IsEmpty());
EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, 4);
@ -65,7 +79,8 @@ TEST(WebMBuffered, RealData)
ReadFile("test.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_TRUE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_OK);
EXPECT_EQ(mapping.Length(), 6u);
EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, int64_t(webmData.Length()));
@ -89,7 +104,7 @@ TEST(WebMBuffered, RealDataAppend)
uint32_t arrayEntries = mapping.Length();
size_t offset = 0;
while (offset < webmData.Length()) {
EXPECT_TRUE(parser.Append(webmData.Elements() + offset, 1, mapping));
EXPECT_EQ(parser.Append(webmData.Elements() + offset, 1, mapping), NS_OK);
offset += 1;
EXPECT_EQ(parser.mCurrentOffset, int64_t(offset));
if (mapping.Length() != arrayEntries) {
@ -124,7 +139,8 @@ TEST(WebMBuffered, InvalidEBMLMaxIdLength)
ReadFile("test_InvalidElementId.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_FALSE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_ERROR_FAILURE);
}
TEST(WebMBuffered, InvalidLargeElementIdLength)
@ -137,7 +153,8 @@ TEST(WebMBuffered, InvalidLargeElementIdLength)
ReadFile("test_InvalidLargeElementId.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_FALSE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_ERROR_FAILURE);
}
TEST(WebMBuffered, InvalidSmallEBMLMaxIdLength)
@ -152,7 +169,8 @@ TEST(WebMBuffered, InvalidSmallEBMLMaxIdLength)
ReadFile("test_InvalidSmallEBMLMaxIdLength.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_FALSE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_ERROR_FAILURE);
}
TEST(WebMBuffered, ValidLargeEBMLMaxIdLength)
@ -167,7 +185,8 @@ TEST(WebMBuffered, ValidLargeEBMLMaxIdLength)
ReadFile("test_ValidLargeEBMLMaxIdLength.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_TRUE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_OK);
}
TEST(WebMBuffered, InvalidLargeEBMLMaxIdLength)
@ -182,7 +201,8 @@ TEST(WebMBuffered, InvalidLargeEBMLMaxIdLength)
ReadFile("test_InvalidLargeEBMLMaxIdLength.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_FALSE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_ERROR_FAILURE);
}
TEST(WebMBuffered, ValidSmallEBMLMaxSizeLength)
@ -195,7 +215,8 @@ TEST(WebMBuffered, ValidSmallEBMLMaxSizeLength)
ReadFile("test_ValidSmallEBMLMaxSizeLength.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_TRUE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_OK);
}
TEST(WebMBuffered, InvalidEBMLMaxSizeLength)
@ -208,5 +229,6 @@ TEST(WebMBuffered, InvalidEBMLMaxSizeLength)
ReadFile("test_InvalidElementSize.webm", webmData);
nsTArray<WebMTimeDataOffset> mapping;
EXPECT_FALSE(parser.Append(webmData.Elements(), webmData.Length(), mapping));
EXPECT_EQ(parser.Append(webmData.Elements(), webmData.Length(), mapping),
NS_ERROR_FAILURE);
}

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

@ -116,10 +116,9 @@ class WebMContainerParser
WebMBufferedParser parser(0);
nsTArray<WebMTimeDataOffset> mapping;
bool result = parser.Append(aData.Elements(), aData.Length(), mapping);
if (!result) {
return MediaResult(NS_ERROR_FAILURE,
RESULT_DETAIL("Invalid webm content"));
if (auto result = parser.Append(aData.Elements(), aData.Length(), mapping);
NS_FAILED(result)) {
return result;
}
return parser.mInitEndOffset > 0 ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
@ -133,10 +132,9 @@ class WebMContainerParser
WebMBufferedParser parser(0);
nsTArray<WebMTimeDataOffset> mapping;
parser.AppendMediaSegmentOnly();
bool result = parser.Append(aData.Elements(), aData.Length(), mapping);
if (!result) {
return MediaResult(NS_ERROR_FAILURE,
RESULT_DETAIL("Invalid webm content"));
if (auto result = parser.Append(aData.Elements(), aData.Length(), mapping);
NS_FAILED(result)) {
return result;
}
return parser.GetClusterOffset() >= 0 ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
@ -178,7 +176,10 @@ class WebMContainerParser
nsTArray<WebMTimeDataOffset> mapping;
mapping.AppendElements(mOverlappedMapping);
mOverlappedMapping.Clear();
mParser.Append(aData.Elements(), aData.Length(), mapping);
if (auto result = mParser.Append(aData.Elements(), aData.Length(), mapping);
NS_FAILED(result)) {
return result;
}
if (mResource) {
mResource->AppendData(aData);
}

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

@ -69,8 +69,9 @@ WebMBufferedParser::WebMBufferedParser(int64_t aOffset)
}
}
bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping) {
MediaResult WebMBufferedParser::Append(const unsigned char* aBuffer,
uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping) {
static const uint32_t EBML_ID = 0x1a45dfa3;
static const uint32_t SEGMENT_ID = 0x18538067;
static const uint32_t SEGINFO_ID = 0x1549a966;
@ -102,8 +103,10 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
break;
case READ_ELEMENT_SIZE:
if (mVInt.mLength > mEBMLMaxIdLength) {
WEBM_DEBUG("Invalid element id of length %" PRIu64, mVInt.mLength);
return false;
nsPrintfCString detail("Invalid element id of length %" PRIu64,
mVInt.mLength);
WEBM_DEBUG("%s", detail.get());
return MediaResult(NS_ERROR_FAILURE, detail);
}
mVIntRaw = false;
mElement.mID = mVInt;
@ -124,8 +127,10 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
break;
case PARSE_ELEMENT:
if (mVInt.mLength > mEBMLMaxSizeLength) {
WEBM_DEBUG("Invalid element size of length %" PRIu64, mVInt.mLength);
return false;
nsPrintfCString detail("Invalid element size of length %" PRIu64,
mVInt.mLength);
WEBM_DEBUG("%s", detail.get());
return MediaResult(NS_ERROR_FAILURE, detail);
}
mElement.mSize = mVInt;
switch (mElement.mID.mValue) {
@ -173,7 +178,10 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
WEBM_DEBUG(
"The Timecode element must appear before any Block or "
"SimpleBlock elements in a Cluster");
return false;
return MediaResult(
NS_ERROR_FAILURE,
"The Timecode element must appear before any Block or "
"SimpleBlock elements in a Cluster");
}
mBlockSize = mElement.mSize.mValue;
mBlockTimecode = 0;
@ -192,21 +200,23 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
if (int64_t currentOffset = mCurrentOffset + (p - aBuffer);
currentOffset < mLastInitStartOffset ||
currentOffset >= mLastInitStartOffset + mLastInitSize) {
WEBM_DEBUG("Unexpected %s outside init segment",
mElement.mID.mValue == EBML_MAX_ID_LENGTH_ID
? "EBMLMaxIdLength"
: "EBMLMaxSizeLength");
return false;
nsPrintfCString str("Unexpected %s outside init segment",
mElement.mID.mValue == EBML_MAX_ID_LENGTH_ID
? "EBMLMaxIdLength"
: "EBMLMaxSizeLength");
WEBM_DEBUG("%s", str.get());
return MediaResult(NS_ERROR_FAILURE, str);
}
if (mElement.mSize.mValue > 8) {
// https://www.rfc-editor.org/rfc/rfc8794.html (EBML):
// An Unsigned Integer Element MUST declare a length from zero
// to eight octets.
WEBM_DEBUG("Bad length of %s size",
mElement.mID.mValue == EBML_MAX_ID_LENGTH_ID
? "EBMLMaxIdLength"
: "EBMLMaxSizeLength");
return false;
nsPrintfCString str("Bad length of %s size",
mElement.mID.mValue == EBML_MAX_ID_LENGTH_ID
? "EBMLMaxIdLength"
: "EBMLMaxSizeLength");
WEBM_DEBUG("%s", str.get());
return MediaResult(NS_ERROR_FAILURE, str);
}
mVInt = VInt();
mVIntLeft = mElement.mSize.mValue;
@ -252,7 +262,8 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
case READ_TIMECODESCALE:
if (!mGotTimecodeScale) {
WEBM_DEBUG("Should get the SegmentInfo first");
return false;
return MediaResult(NS_ERROR_FAILURE,
"TimecodeScale appeared before SegmentInfo");
}
mTimecodeScale = mVInt.mValue;
mState = READ_ELEMENT_ID;
@ -280,7 +291,8 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
mClusterTimecode >= uint16_t(abs(mBlockTimecode))) {
if (!mGotTimecodeScale) {
WEBM_DEBUG("Should get the TimecodeScale first");
return false;
return MediaResult(NS_ERROR_FAILURE,
"Timecode appeared before SegmentInfo");
}
uint64_t absTimecode = mClusterTimecode + mBlockTimecode;
absTimecode *= mTimecodeScale;
@ -329,8 +341,10 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
// Section 4 of [RFC8794] and can be between one and five octets
// long. Five-octet-long Element IDs are possible only if declared
// in the EBML header.
WEBM_DEBUG("Invalid EMBLMaxIdLength %" PRIu64, mVInt.mValue);
return false;
nsPrintfCString detail("Invalid EMBLMaxIdLength %" PRIu64,
mVInt.mValue);
WEBM_DEBUG("%s", detail.get());
return MediaResult(NS_ERROR_FAILURE, detail);
}
mEBMLMaxIdLength = mVInt.mValue;
mState = READ_ELEMENT_ID;
@ -348,8 +362,10 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
// (Matroska):
// The EBMLMaxSizeLength of the EBML Header MUST be between "1" and
// "8" inclusive.
WEBM_DEBUG("Invalid EMBLMaxSizeLength %" PRIu64, mVInt.mValue);
return false;
nsPrintfCString detail("Invalid EMBLMaxSizeLength %" PRIu64,
mVInt.mValue);
WEBM_DEBUG("%s", detail.get());
return MediaResult(NS_ERROR_FAILURE, detail);
}
mEBMLMaxSizeLength = mVInt.mValue;
mState = READ_ELEMENT_ID;
@ -387,7 +403,7 @@ bool WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
NS_ASSERTION(p == aBuffer + aLength, "Must have parsed to end of data.");
mCurrentOffset += aLength;
return true;
return NS_OK;
}
int64_t WebMBufferedParser::EndSegmentOffset(int64_t aOffset) {

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

@ -10,6 +10,7 @@
# include "nsTArray.h"
# include "mozilla/Mutex.h"
# include "MediaResource.h"
# include "MediaResult.h"
namespace mozilla {
@ -65,8 +66,8 @@ struct WebMBufferedParser {
// Steps the parser through aLength bytes of data. Always consumes
// aLength bytes. Updates mCurrentOffset before returning.
// Returns false if an error was encountered.
bool Append(const unsigned char* aBuffer, uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping);
MediaResult Append(const unsigned char* aBuffer, uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping);
bool operator==(int64_t aOffset) const { return mCurrentOffset == aOffset; }