Skip to content

Commit 4db0e53

Browse files
committed
Clarify VideoFrame.copyTo() parallel steps and buffer handling
Avoid accessing or mutating JS objects from background parallel steps in VideoFrame.copyTo(): - Check if destination is detached before starting the copy. - Capture [[resource reference]], options, and PlaneLayout results synchronously on the event loop thread (fixing PlaneLayout.stride to use destinationStride). - Perform RGB pixel format and color space conversion on the media resource in parallel instead of synchronously constructing a temporary VideoFrame and recursing. - Write directly to shared memory in parallel when destination is backed by a SharedArrayBuffer; otherwise, copy into destination on a queued event loop task after re-verifying detachment and byteLength (while allowing UAs to copy synchronously when the resource is already in CPU memory). - Set the default value of VideoFrameCopyToOptions.colorSpace to "srgb" in IDL. Fixes #955
1 parent 8f7384f commit 4db0e53

1 file changed

Lines changed: 86 additions & 80 deletions

File tree

‎index.src.html‎

Lines changed: 86 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3893,60 +3893,66 @@
38933893
VideoFrameCopyToOptions=] algorithm with |options|.
38943894
4. If |combinedLayout| is an exception, return a promise rejected with
38953895
|combinedLayout|.
3896-
5. If `destination.byteLength` is less than |combinedLayout|'s [=combined
3896+
5. If |destination| is [=BufferSource/detached=], return a promise rejected
3897+
with a {{TypeError}}.
3898+
6. If `destination.byteLength` is less than |combinedLayout|'s [=combined
38973899
buffer layout/allocationSize=], return a promise rejected with a
38983900
{{TypeError}}.
3899-
6. If |options|.{{VideoFrameCopyToOptions/format}} is equal to one of
3900-
{{RGBA}}, {{RGBX}}, {{BGRA}}, {{BGRX}} then:
3901-
1. Let |newOptions| be the result of running the <a>Clone Configuration</a>
3902-
algorithm with |options|.
3903-
2. Assign `undefined` to |newOptions|.{{VideoFrameCopyToOptions/format}}.
3904-
3. Let |rgbFrame| be the result of running the [=VideoFrame/Convert to RGB frame=]
3905-
algorithm with [=this=], |options|.{{VideoFrameCopyToOptions/format}},
3906-
and |options|.{{VideoFrameCopyToOptions/colorSpace}}.
3907-
4. Return the result of calling {{VideoFrame/copyTo()}} on |rgbFrame| with
3908-
|destination| and |newOptions|.
3909-
7. Let |p| be a new {{Promise}}.
3910-
8. Let |copyStepsQueue| be the result of starting a new [=parallel queue=].
3911-
9. Let |planeLayouts| be a new [=list=].
3912-
10. Enqueue the following steps to |copyStepsQueue|:
3913-
1. Let resource be the [=media resource=] referenced by
3914-
{{VideoFrame/[[resource reference]]}}.
3915-
2. Let |numPlanes| be the number of planes as defined by
3916-
{{VideoFrame/[[format]]}}.
3917-
3. Let |planeIndex| be `0`.
3918-
4. While |planeIndex| is less than |combinedLayout|'s |numPlanes|:
3919-
1. Let |sourceStride| be the stride of the plane in |resource| as
3920-
identified by |planeIndex|.
3921-
2. Let |computedLayout| be the [=computed plane layout=] in
3922-
|combinedLayout|'s [=combined buffer layout/computedLayouts=] at
3923-
the position of |planeIndex|
3924-
3. Let |sourceOffset| be the product of multiplying
3925-
|computedLayout|'s [=computed plane layout/sourceTop=] by
3926-
|sourceStride|
3927-
4. Add |computedLayout|'s [=computed plane layout/sourceLeftBytes=]
3928-
to |sourceOffset|.
3929-
5. Let |destinationOffset| be |computedLayout|'s
3930-
[=computed plane layout/destinationOffset=].
3931-
6. Let |rowBytes| be |computedLayout|'s
3932-
[=computed plane layout/sourceWidthBytes=].
3933-
7. Let |layout| be a new {{PlaneLayout}}, with
3934-
{{PlaneLayout/offset}} set to |destinationOffset| and
3935-
{{PlaneLayout/stride}} set to |rowBytes|.
3936-
8. Let |row| be `0`.
3937-
9. While |row| is less than |computedLayout|'s
3938-
[=computed plane layout/sourceHeight=]:
3939-
1. Copy |rowBytes| bytes from |resource| starting at
3940-
|sourceOffset| to |destination| starting at
3941-
|destinationOffset|.
3942-
2. Increment |sourceOffset| by |sourceStride|.
3943-
3. Increment |destinationOffset| by |computedLayout|'s
3944-
[=computed plane layout/destinationStride=].
3945-
4. Increment |row| by `1`.
3946-
10. Increment |planeIndex| by `1`.
3947-
11. Append |layout| to |planeLayouts|.
3948-
5. [=Queue a task=] to [=resolve=] |p| with |planeLayouts|.
3949-
11. Return |p|.
3901+
7. Let |resource| be the [=media resource=] referenced by
3902+
{{VideoFrame/[[resource reference]]}}.
3903+
8. Let |planeLayouts| be a new [=list=].
3904+
9. For each |computedLayout| of |combinedLayout|'s
3905+
[=combined buffer layout/computedLayouts=]:
3906+
1. Let |layout| be a new {{PlaneLayout}}, with
3907+
{{PlaneLayout/offset}} set to |computedLayout|'s
3908+
[=computed plane layout/destinationOffset=] and
3909+
{{PlaneLayout/stride}} set to |computedLayout|'s
3910+
[=computed plane layout/destinationStride=].
3911+
2. Append |layout| to |planeLayouts|.
3912+
10. Let |targetFormat| be |options|.{{VideoFrameCopyToOptions/format}} if it
3913+
[=map/exists=], and `undefined` otherwise.
3914+
11. Let |targetColorSpace| be the result of running the <a>Convert
3915+
PredefinedColorSpace to VideoColorSpace</a> algorithm with
3916+
|options|.{{VideoFrameCopyToOptions/colorSpace}}.
3917+
12. Let |sharedMemory| be `null`.
3918+
13. If |destination| is a {{SharedArrayBuffer}}, set |sharedMemory| to a
3919+
reference to the `destination.byteLength` bytes of |destination|'s
3920+
`[[ArrayBufferData]]` starting at byte offset `0`.
3921+
14. Otherwise, if |destination| is an {{ArrayBufferView}} whose
3922+
[=BufferSource/underlying buffer=] is a {{SharedArrayBuffer}}, set
3923+
|sharedMemory| to a reference to the `destination.byteLength` bytes of
3924+
|destination|'s [=BufferSource/underlying buffer=]'s
3925+
`[[ArrayBufferData]]` starting at `destination.byteOffset`.
3926+
15. Let |p| be a new {{Promise}}.
3927+
16. Run the following steps [=in parallel=]:
3928+
1. If |targetFormat| is equal to one of {{RGBA}}, {{RGBX}}, {{BGRA}},
3929+
{{BGRX}}, then:
3930+
1. Set |resource| to a new [=media resource=] with the same coded
3931+
width and coded height as |resource|, containing the result of
3932+
converting its pixels into pixel format |targetFormat| and
3933+
color space |targetColorSpace|.
3934+
3935+
NOTE: User Agents only need to convert the pixel region covered
3936+
by |combinedLayout|.
3937+
2. If |sharedMemory| is not `null`:
3938+
1. Run the [=VideoFrame/Copy Planes=] algorithm with |resource|,
3939+
|combinedLayout|, and |sharedMemory|.
3940+
2. [=Queue a task=] to [=resolve=] |p| with |planeLayouts|.
3941+
3. Otherwise:
3942+
1. Wait until |resource| is available in CPU memory.
3943+
2. [=Queue a task=] to run the following steps:
3944+
1. If |destination| is [=BufferSource/detached=] or
3945+
`destination.byteLength` is less than |combinedLayout|'s
3946+
[=combined buffer layout/allocationSize=], [=reject=] |p|
3947+
with a {{TypeError}} and abort these steps.
3948+
2. Run the [=VideoFrame/Copy Planes=] algorithm with |resource|,
3949+
|combinedLayout|, and |destination|.
3950+
3. [=Resolve=] |p| with |planeLayouts|.
3951+
3952+
NOTE: When |sharedMemory| is `null` and |resource| is already accessible
3953+
in CPU memory, User Agents can run [=VideoFrame/Copy Planes=]
3954+
synchronously before returning |p| to avoid an extra copy.
3955+
17. Return |p|.
39503956

39513957
: <dfn method for=VideoFrame>clone()</dfn>
39523958
:: Creates a new {{VideoFrame}} with a reference to the same
@@ -4390,32 +4396,33 @@
43904396
3. If |colorSpace| is equal to {{display-p3}} return a new instance of the
43914397
[=Display P3 Color Space=]
43924398

4393-
: <dfn for=VideoFrame>Convert to RGB frame</dfn> (with |frame|, |format| and |colorSpace|)
4394-
:: 1. This algorithm <em class="rfc2119">MUST</em> be called only if |format|
4395-
is equal to one of {{RGBA}}, {{RGBX}}, {{BGRA}}, {{BGRX}}.
4396-
2. Let |convertedFrame| be a new {{VideoFrame}}, constructed as follows:
4397-
1. Assign `false` to {{platform object/[[Detached]]}}.
4398-
2. Assign |format| to {{VideoFrame/[[format]]}}.
4399-
3. Let |width| be |frame|'s {{VideoFrame/[[visible width]]}}.
4400-
4. Let |height| be |frame|'s {{VideoFrame/[[visible height]]}}.
4401-
5. Assign |width|, |height|, 0, 0, |width|, |height|, |width|, and
4402-
|height| to {{VideoFrame/[[coded width]]}},
4403-
{{VideoFrame/[[coded height]]}}, {{VideoFrame/[[visible left]]}},
4404-
{{VideoFrame/[[visible top]]}}, {{VideoFrame/[[visible width]]}},
4405-
and {{VideoFrame/[[visible height]]}} respectively.
4406-
6. Assign |frame|'s {{VideoFrame/[[duration]]}} and |frame|'s
4407-
{{VideoFrame/[[timestamp]]}} to {{VideoFrame/[[duration]]}} and
4408-
{{VideoFrame/[[timestamp]]}} respectively.
4409-
7. Assign the result of running the <a>Convert
4410-
PredefinedColorSpace to VideoColorSpace</a> algorithm with
4411-
|colorSpace| to {{VideoFrame/[[color space]]}}.
4412-
8. Let |resource| be a new [=media resource=] containing the result of
4413-
conversion of [=media resource=] referenced by |frame|'s
4414-
{{VideoFrame/[[resource reference]]}} into a color space and pixel
4415-
format specified by {{VideoFrame/[[color space]]}} and
4416-
{{VideoFrame/[[format]]}} respectively.
4417-
9. Assign the reference to |resource| to {{VideoFrame/[[resource reference]]}}
4418-
3. Return |convertedFrame|.
4399+
: <dfn for=VideoFrame>Copy Planes</dfn> (with |resource|, |combinedLayout|, and |destination|)
4400+
:: 1. Let |planeIndex| be `0`.
4401+
2. While |planeIndex| is less than |combinedLayout|'s [=combined buffer layout/computedLayouts=]'s [=list/size=]:
4402+
1. Let |sourceStride| be the stride of the plane in |resource| as
4403+
identified by |planeIndex|.
4404+
2. Let |computedLayout| be |combinedLayout|'s
4405+
[=combined buffer layout/computedLayouts=][|planeIndex|].
4406+
3. Let |sourceOffset| be the product of multiplying
4407+
|computedLayout|'s [=computed plane layout/sourceTop=] by
4408+
|sourceStride|.
4409+
4. Add |computedLayout|'s [=computed plane layout/sourceLeftBytes=]
4410+
to |sourceOffset|.
4411+
5. Let |destinationOffset| be |computedLayout|'s
4412+
[=computed plane layout/destinationOffset=].
4413+
6. Let |rowBytes| be |computedLayout|'s
4414+
[=computed plane layout/sourceWidthBytes=].
4415+
7. Let |row| be `0`.
4416+
8. While |row| is less than |computedLayout|'s
4417+
[=computed plane layout/sourceHeight=]:
4418+
1. Copy |rowBytes| bytes from |resource| starting at
4419+
|sourceOffset| to |destination| starting at
4420+
|destinationOffset|.
4421+
2. Increment |sourceOffset| by |sourceStride|.
4422+
3. Increment |destinationOffset| by |computedLayout|'s
4423+
[=computed plane layout/destinationStride=].
4424+
4. Increment |row| by `1`.
4425+
9. Increment |planeIndex| by `1`.
44194426

44204427
: <dfn for=VideoFrame>Copy VideoFrame metadata</dfn> (with |metadata|)
44214428
:: 1. Let |metadataCopySerialized| be [$StructuredSerialize$](|metadata|).
@@ -4486,7 +4493,7 @@
44864493
DOMRectInit rect;
44874494
sequence<PlaneLayout> layout;
44884495
VideoPixelFormat format;
4489-
PredefinedColorSpace colorSpace;
4496+
PredefinedColorSpace colorSpace = "srgb";
44904497
};
44914498
</xmp>
44924499

@@ -4524,7 +4531,6 @@
45244531
a target color space for the pixel data in the destination
45254532
{{BufferSource}}, but only if {{VideoFrameCopyToOptions/format}} is one of
45264533
{{RGBA}}, {{RGBX}}, {{BGRA}}, {{BGRX}}, otherwise it is ignored.
4527-
If it does not [=map/exist=], {{srgb}} is used.
45284534

45294535

45304536
DOMRects in VideoFrame {#videoframe-domrect}

0 commit comments

Comments
 (0)