Bug 1926249 - Implement support for desired width/height with WebCodecs ImageDecoder. r=media-playback-reviewers,padenot
Differential Revision: https://phabricator.services.mozilla.com/D226498
This commit is contained in:
@@ -45,11 +45,14 @@ class ImageDecoder::ControlMessage {
|
||||
class ImageDecoder::ConfigureMessage final
|
||||
: public ImageDecoder::ControlMessage {
|
||||
public:
|
||||
explicit ConfigureMessage(ColorSpaceConversion aColorSpaceConversion)
|
||||
: mColorSpaceConversion(aColorSpaceConversion) {}
|
||||
explicit ConfigureMessage(const Maybe<gfx::IntSize>& aOutputSize,
|
||||
ColorSpaceConversion aColorSpaceConversion)
|
||||
: mOutputSize(aOutputSize),
|
||||
mColorSpaceConversion(aColorSpaceConversion) {}
|
||||
|
||||
ConfigureMessage* AsConfigureMessage() override { return this; }
|
||||
|
||||
const Maybe<gfx::IntSize> mOutputSize;
|
||||
const ColorSpaceConversion mColorSpaceConversion;
|
||||
};
|
||||
|
||||
@@ -152,9 +155,10 @@ void ImageDecoder::Destroy() {
|
||||
}
|
||||
|
||||
void ImageDecoder::QueueConfigureMessage(
|
||||
const Maybe<gfx::IntSize>& aOutputSize,
|
||||
ColorSpaceConversion aColorSpaceConversion) {
|
||||
mControlMessageQueue.push(
|
||||
MakeUnique<ConfigureMessage>(aColorSpaceConversion));
|
||||
MakeUnique<ConfigureMessage>(aOutputSize, aColorSpaceConversion));
|
||||
}
|
||||
|
||||
void ImageDecoder::QueueDecodeMetadataMessage() {
|
||||
@@ -239,8 +243,8 @@ MessageProcessedResult ImageDecoder::ProcessConfigureMessage(
|
||||
|
||||
// 3. Otherwise, assign the [[codec implementation]] internal slot with an
|
||||
// implementation supporting init.type
|
||||
mDecoder =
|
||||
image::ImageUtils::CreateDecoder(mSourceBuffer, type, surfaceFlags);
|
||||
mDecoder = image::ImageUtils::CreateDecoder(mSourceBuffer, type,
|
||||
aMsg->mOutputSize, surfaceFlags);
|
||||
if (NS_WARN_IF(!mDecoder)) {
|
||||
MOZ_LOG(gWebCodecsLog, LogLevel::Error,
|
||||
("ImageDecoder %p Initialize -- failed to create platform decoder",
|
||||
@@ -680,9 +684,17 @@ void ImageDecoder::Initialize(const GlobalObject& aGlobal,
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<gfx::IntSize> desiredSize;
|
||||
if (aInit.mDesiredWidth.WasPassed() && aInit.mDesiredHeight.WasPassed()) {
|
||||
desiredSize.emplace(
|
||||
std::min(aInit.mDesiredWidth.Value(), static_cast<uint32_t>(INT32_MAX)),
|
||||
std::min(aInit.mDesiredHeight.Value(),
|
||||
static_cast<uint32_t>(INT32_MAX)));
|
||||
}
|
||||
|
||||
// 10.2.2.17.3 / 10.2.2.18.6.
|
||||
// Queue a control message to configure the image decoder with init.
|
||||
QueueConfigureMessage(aInit.mColorSpaceConversion);
|
||||
QueueConfigureMessage(desiredSize, aInit.mColorSpaceConversion);
|
||||
|
||||
// 10.2.10.2.2.18.7. Queue a control message to decode track metadata.
|
||||
//
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/ImageDecoderBinding.h"
|
||||
#include "mozilla/dom/WebCodecsUtils.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
@@ -113,7 +114,8 @@ class ImageDecoder final : public nsISupports, public nsWrapperCache {
|
||||
void Reset(const MediaResult& aResult);
|
||||
void Close(const MediaResult& aResult);
|
||||
|
||||
void QueueConfigureMessage(ColorSpaceConversion aColorSpaceConversion);
|
||||
void QueueConfigureMessage(const Maybe<gfx::IntSize>& aOutputSize,
|
||||
ColorSpaceConversion aColorSpaceConversion);
|
||||
void QueueDecodeMetadataMessage();
|
||||
void QueueDecodeFrameMessage();
|
||||
|
||||
|
||||
BIN
dom/media/webcodecs/test/green.png
Normal file
BIN
dom/media/webcodecs/test/green.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 255 B |
@@ -5,9 +5,15 @@ prefs = [
|
||||
"dom.media.webcodecs.enabled=true",
|
||||
"dom.media.webcodecs.image-decoder.enabled=true",
|
||||
]
|
||||
support-files = ["bug1921817.jpg"]
|
||||
support-files = [
|
||||
"bug1921817.jpg",
|
||||
"green.png",
|
||||
]
|
||||
|
||||
["test_videoFrame_mismatched_codedSize.html"]
|
||||
|
||||
["test_bug1921817.html"]
|
||||
scheme = "https"
|
||||
|
||||
["test_imageDecoder_desiredSize.html"]
|
||||
scheme = "https"
|
||||
|
||||
57
dom/media/webcodecs/test/test_imageDecoder_desiredSize.html
Normal file
57
dom/media/webcodecs/test/test_imageDecoder_desiredSize.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// Bug 1924775 - ESLint doesn't yet know about `ImageDecoder`.
|
||||
/* globals ImageDecoder:false */
|
||||
|
||||
async function test(desiredWidth, desiredHeight, expectedWidth, expectedHeight) {
|
||||
const imgResponse = await fetch("green.png");
|
||||
const decoder = new ImageDecoder({
|
||||
data: imgResponse.body,
|
||||
type: "image/png",
|
||||
desiredWidth,
|
||||
desiredHeight,
|
||||
});
|
||||
|
||||
// Should download all the data and decode metadata just fine.
|
||||
await decoder.completed;
|
||||
await decoder.tracks.ready;
|
||||
is(decoder.tracks.length, 1, "Should have one track");
|
||||
is(decoder.tracks[0].frameCount, 1, "Should have a single frame");
|
||||
|
||||
try {
|
||||
const result = await decoder.decode();
|
||||
ok(result.complete, "Should have complete image");
|
||||
is(result.image.codedWidth, expectedWidth, "Should have expected width");
|
||||
is(result.image.codedHeight, expectedHeight, "Should have expected height");
|
||||
} catch (e) {
|
||||
ok(false, "Decode image failed with " + e)
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async function initTest() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
try {
|
||||
await test(10, 20, 10, 20);
|
||||
await test(100, 300, 100, 100);
|
||||
await test(500, 40, 100, 100);
|
||||
await test(500, 300, 100, 100);
|
||||
} catch (e) {
|
||||
ok(false, "Unexpected error " + e);
|
||||
} finally {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
initTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -171,6 +171,12 @@ class AnonymousFramesDecoderTask final : public AnonymousDecoderTask {
|
||||
ThreadSafeWeakPtr<AnonymousDecoder>&& aOwner)
|
||||
: AnonymousDecoderTask(std::move(aDecoder), std::move(aOwner)) {}
|
||||
|
||||
void SetOutputSize(const OrientedIntSize& aSize) {
|
||||
if (mDecoder) {
|
||||
mDecoder->SetOutputSize(aSize);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool OnFrameAvailable(RefPtr<imgFrame>&& aFrame,
|
||||
RefPtr<gfx::SourceSurface>&& aSurface) override {
|
||||
@@ -194,8 +200,9 @@ class AnonymousFramesDecoderTask final : public AnonymousDecoderTask {
|
||||
|
||||
class AnonymousDecoderImpl final : public AnonymousDecoder {
|
||||
public:
|
||||
AnonymousDecoderImpl()
|
||||
: mMutex("mozilla::image::AnonymousDecoderImpl::mMutex") {}
|
||||
explicit AnonymousDecoderImpl(const Maybe<gfx::IntSize>& aOutputSize)
|
||||
: mMutex("mozilla::image::AnonymousDecoderImpl::mMutex"),
|
||||
mOutputSize(aOutputSize) {}
|
||||
|
||||
~AnonymousDecoderImpl() override { Destroy(); }
|
||||
|
||||
@@ -298,6 +305,23 @@ class AnonymousDecoderImpl final : public AnonymousDecoder {
|
||||
this, size.width, size.height, mMetadataResult.mRepetitions,
|
||||
mMetadataResult.mAnimated));
|
||||
|
||||
if (mOutputSize && !mMetadataResult.mAnimated && mFramesTask) {
|
||||
if (mOutputSize->width <= size.width &&
|
||||
mOutputSize->height <= size.height) {
|
||||
MOZ_LOG(
|
||||
sLog, LogLevel::Debug,
|
||||
("[%p] AnonymousDecoderImpl::OnMetadata -- use output size %dx%d",
|
||||
this, mOutputSize->width, mOutputSize->height));
|
||||
mFramesTask->SetOutputSize(
|
||||
OrientedIntSize::FromUnknownSize(*mOutputSize));
|
||||
} else {
|
||||
MOZ_LOG(sLog, LogLevel::Debug,
|
||||
("[%p] AnonymousDecoderImpl::OnMetadata -- cannot use output "
|
||||
"size %dx%d, exceeds metadata size",
|
||||
this, mOutputSize->width, mOutputSize->height));
|
||||
}
|
||||
}
|
||||
|
||||
if (!mMetadataResult.mAnimated) {
|
||||
mMetadataResult.mFrameCount = 1;
|
||||
mMetadataResult.mFrameCountComplete = true;
|
||||
@@ -526,6 +550,7 @@ class AnonymousDecoderImpl final : public AnonymousDecoder {
|
||||
RefPtr<imgFrame> mLastFrame MOZ_GUARDED_BY(mMutex);
|
||||
DecodeMetadataResult mMetadataResult MOZ_GUARDED_BY(mMutex);
|
||||
DecodeFramesResult mPendingFramesResult MOZ_GUARDED_BY(mMutex);
|
||||
Maybe<gfx::IntSize> mOutputSize MOZ_GUARDED_BY(mMutex);
|
||||
size_t mFramesToDecode MOZ_GUARDED_BY(mMutex) = 1;
|
||||
uint32_t mFrameCount MOZ_GUARDED_BY(mMutex) = 0;
|
||||
bool mMetadataTaskRunning MOZ_GUARDED_BY(mMutex) = false;
|
||||
@@ -535,7 +560,7 @@ class AnonymousDecoderImpl final : public AnonymousDecoder {
|
||||
|
||||
/* static */ already_AddRefed<AnonymousDecoder> ImageUtils::CreateDecoder(
|
||||
SourceBuffer* aSourceBuffer, DecoderType aType,
|
||||
SurfaceFlags aSurfaceFlags) {
|
||||
const Maybe<gfx::IntSize>& aOutputSize, SurfaceFlags aSurfaceFlags) {
|
||||
if (NS_WARN_IF(!aSourceBuffer)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -551,7 +576,7 @@ class AnonymousDecoderImpl final : public AnonymousDecoder {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto anonymousDecoder = MakeRefPtr<AnonymousDecoderImpl>();
|
||||
auto anonymousDecoder = MakeRefPtr<AnonymousDecoderImpl>(aOutputSize);
|
||||
if (NS_WARN_IF(!anonymousDecoder->Initialize(std::move(decoder)))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ class ImageUtils {
|
||||
public:
|
||||
static already_AddRefed<AnonymousDecoder> CreateDecoder(
|
||||
SourceBuffer* aSourceBuffer, DecoderType aType,
|
||||
SurfaceFlags aSurfaceFlags);
|
||||
const Maybe<gfx::IntSize>& aOutputSize, SurfaceFlags aSurfaceFlags);
|
||||
|
||||
static DecoderType GetDecoderType(const nsACString& aMimeType);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user