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:
Andrew Osmond
2024-10-22 13:45:36 +00:00
parent 00e0a758fc
commit 509fefbffd
7 changed files with 115 additions and 13 deletions

View File

@@ -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.
//

View File

@@ -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();

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

View File

@@ -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"

View 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>

View File

@@ -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;
}

View File

@@ -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);