diff --git a/images/videoframe_dimensions.svg b/images/videoframe_dimensions.svg new file mode 100644 index 00000000..40fdbabf --- /dev/null +++ b/images/videoframe_dimensions.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Media resource + + + + + + + codedWidth + + codedHeight + + + + + x + width + + + + + y + height + + visibleRect: x, y, width, height + + not displayed + + + + crop, scale + + + rotation = 0 + + + + + + displayWidth + + + displayHeight + + + + rotate + + + rotation = 90 + + + + + + displayWidth + + + displayHeight + diff --git a/images/videoframe_planes.svg b/images/videoframe_planes.svg new file mode 100644 index 00000000..dcae45e9 --- /dev/null +++ b/images/videoframe_planes.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + Y plane + + + + + + + + + + + codedWidth samples + + + codedHeight + + stride (bytes) + + + U plane + + + + + + + + + + + ⌈codedWidth / 2⌉ samples + + + ⌈codedHeight / 2⌉ + + stride (bytes) + + + V plane + + + + + + + + + + + + visible rectangle + + outside of the visible rectangle + + padding + + one cell is one byte + diff --git a/index.src.html b/index.src.html index e4fadd2d..e5dc3e21 100644 --- a/index.src.html +++ b/index.src.html @@ -3520,25 +3520,23 @@ {{VideoPixelFormat}} or when {{platform object/[[Detached]]}} is `true`. : [[coded width]] -:: Width of the {{VideoFrame}} in pixels, potentially including non-visible - padding, and prior to considering potential ratio adjustments. +:: The [=coded width=] of the {{VideoFrame}}. : [[coded height]] -:: Height of the {{VideoFrame}} in pixels, potentially including non-visible - padding, and prior to considering potential ratio adjustments. +:: The [=coded height=] of the {{VideoFrame}}. : [[visible left]] -:: The number of pixels defining the left offset of the visible rectangle. +:: The number of pixels defining the left offset of the [=visible rectangle=]. : [[visible top]] -:: The number of pixels defining the top offset of the visible rectangle. +:: The number of pixels defining the top offset of the [=visible rectangle=]. : [[visible width]] -:: The width of pixels to include in visible rectangle, starting from +:: The width of pixels to include in [=visible rectangle=], starting from {{VideoFrame/[[visible left]]}}. : [[visible height]] -:: The height of pixels to include in visible rectangle, starting from +:: The height of pixels to include in [=visible rectangle=], starting from {{VideoFrame/[[visible top]]}}. : \[[rotation]] @@ -3550,12 +3548,10 @@ Flip is applied after rotation. : [[display width]] -:: Width of the {{VideoFrame}} when displayed after applying aspect ratio - adjustments. +:: The [=display width=] of the {{VideoFrame}}. : [[display height]] -:: Height of the {{VideoFrame}} when displayed after applying aspect ratio - adjustments. +:: The [=display height=] of the {{VideoFrame}}. : \[[duration]] :: The presentation duration, given in microseconds. @@ -3688,28 +3684,25 @@ to determine where in |data| the pixels for each plane reside. The User Agent MAY choose to allocate - |resource| with a larger coded size and plane strides to improve memory - alignment. Increases will be reflected by {{VideoFrame/codedWidth}} and - {{VideoFrame/codedHeight}}. Additionally, the User Agent MAY use {{VideoFrameBufferInit/visibleRect}} to - copy only the visible rectangle. It MAY also - reposition the visible rectangle within |resource|. The final position - will be reflected by {{VideoFrame/visibleRect}}. + |resource| with a larger [=coded size=] and plane [=strides=] to improve + memory alignment. Increases will be reflected by + {{VideoFrame/codedWidth}} and {{VideoFrame/codedHeight}}. Additionally, + the User Agent MAY use + {{VideoFrameBufferInit/visibleRect}} to copy only the + [=visible rectangle=]. It MAY also reposition + the [=visible rectangle=] within |resource|. The final position will be + reflected by {{VideoFrame/visibleRect}}. 16. For each |transferable| in |init|.{{VideoFrameBufferInit/transfer}}: 1. Perform [DetachArrayBuffer](https://tc39.es/ecma262/#sec-detacharraybuffer) on |transferable| -17. Let |resourceCodedWidth| be the coded width of |resource|. -18. Let |resourceCodedHeight| be the coded height of |resource|. -19. Let |resourceVisibleLeft| be the left offset for the visible rectangle of - |resource|. -20. Let |resourceVisibleTop| be the top offset for the visible rectangle of +17. Let |resourceCodedWidth| be the [=coded width=] of |resource|. +18. Let |resourceCodedHeight| be the [=coded height=] of |resource|. +19. Let |resourceVisibleLeft| be the left offset for the [=visible rectangle=] + of |resource|. +20. Let |resourceVisibleTop| be the top offset for the [=visible rectangle=] of |resource|. - ISSUE: The spec SHOULD provide definitions (and - possibly diagrams) for coded size, visible rectangle, and display size. - See [#166](https://github.com/w3c/webcodecs/issues/166). - 21. Let |frame| be a new {{VideoFrame}} object initialized as follows: 1. Assign |resourceCodedWidth|, |resourceCodedHeight|, |resourceVisibleLeft|, and |resourceVisibleTop| to @@ -3777,15 +3770,13 @@ {{VideoFrame/[[format]]}}. : codedWidth -:: Width of the {{VideoFrame}} in pixels, potentially including non-visible - padding, and prior to considering potential ratio adjustments. +:: The [=coded width=] of the {{VideoFrame}}. The {{VideoFrame/codedWidth}} getter steps are to return {{VideoFrame/[[coded width]]}}. : codedHeight -:: Height of the {{VideoFrame}} in pixels, potentially including non-visible - padding, and prior to considering potential ratio adjustments. +:: The [=coded height=] of the {{VideoFrame}}. The {{VideoFrame/codedHeight}} getter steps are to return {{VideoFrame/[[coded height]]}}. @@ -3807,8 +3798,8 @@ 3. Return |rect|. : visibleRect -:: A {{DOMRectReadOnly}} describing the visible rectangle of pixels for this - {{VideoFrame}}. +:: A {{DOMRectReadOnly}} describing the [=visible rectangle=] of pixels for + this {{VideoFrame}}. The {{VideoFrame/visibleRect}} getter steps are: 1. If {{platform object/[[Detached]]}} is `true`, return `null`. @@ -3834,15 +3825,13 @@ The {{VideoFrame/flip}} getter steps are to return {{VideoFrame/[[flip]]}}. : displayWidth -:: Width of the VideoFrame when displayed after applying rotation and aspect - ratio adjustments. +:: The [=display width=] of the {{VideoFrame}}. The {{VideoFrame/displayWidth}} getter steps are to return {{VideoFrame/[[display width]]}}. : displayHeight -:: Height of the VideoFrame when displayed after applying rotation and aspect - ratio adjustments. +:: The [=display height=] of the {{VideoFrame}}. The {{VideoFrame/displayHeight}} getter steps are to return {{VideoFrame/[[display height]]}}. @@ -3940,8 +3929,8 @@ {{VideoFrame/[[format]]}}. 3. Let |planeIndex| be `0`. 4. While |planeIndex| is less than |combinedLayout|'s |numPlanes|: - 1. Let |sourceStride| be the stride of the plane in |resource| as - identified by |planeIndex|. + 1. Let |sourceStride| be the [=stride=] of the plane in |resource| + as identified by |planeIndex|. 2. Let |computedLayout| be the [=computed plane layout=] in |combinedLayout|'s [=combined buffer layout/computedLayouts=] at the position of |planeIndex| @@ -4007,10 +3996,11 @@ 5. If |output| uses a recognized {{VideoPixelFormat}}, assign that format to {{VideoFrame/[[format]]}}. Otherwise, assign `null` to {{VideoFrame/[[format]]}}. - 6. Let |codedWidth| and |codedHeight| be the coded width and height of the - |output| in pixels. + 6. Let |codedWidth| and |codedHeight| be the [=coded width=] and + [=coded height=] of the |output|. 8. Let |visibleLeft|, |visibleTop|, |visibleWidth|, and |visibleHeight| be - the left, top, width and height for the visible rectangle of |output|. + the left, top, width and height for the [=visible rectangle=] of + |output|. 7. Let |displayWidth| and |displayHeight| be the display size of |output| in pixels. 8. If |displayAspectWidth| and |displayAspectHeight| are provided, @@ -4502,8 +4492,128 @@ The rendering of a {{VideoFrame}} is produced from the [=media resource=] by applying any necessary color space conversion, cropping to the -{{VideoFrame/visibleRect}}, rotating clockwise by {{VideoFrame/rotation}} -degrees, and flipping horizontally if {{VideoFrame/flip}} is `true`. +[=visible rectangle=], rotating clockwise by {{VideoFrame/rotation}} +degrees, flipping horizontally if {{VideoFrame/flip}} is `true`, and scaling to +the [=display size=]. + +VideoFrame Dimensions and Memory Layout {#videoframe-dimensions} +---------------------------------------------------------------- +The pixel data of a {{VideoFrame}}, and the way it is presented, are described +by the following sizes and rectangles. Unless specified otherwise, they are +measured in pixels, from the top-left corner of the pixel data held by the +[=media resource=]. + +: Coded size +:: The coded width and coded height of the pixel data + held by the [=media resource=]. Along with the {{VideoPixelFormat}}, they + determine the number of rows of each plane, and the number of samples in + each row, as described in [[#pixel-format]]. The [=coded size=] can be + larger than the [=visible rectangle=], for example because a codec operates + on blocks of pixels (such as macroblocks of 16 by 16 pixels), or because + the User Agent adds padding to improve memory alignment. The [=coded size=] + is exposed by {{VideoFrame/codedWidth}}, {{VideoFrame/codedHeight}}, and + {{VideoFrame/codedRect}}. + +: Visible rectangle +:: The rectangle of pixels, within the [=coded size=], that holds the picture + to be displayed. It is described by a left offset, a top offset, a width, + and a height. The sum of its left offset and width is less than or equal to + the [=coded width=], and the sum of its top offset and height is less than + or equal to the [=coded height=]. Pixels outside of the + [=visible rectangle=] are not displayed. The [=visible rectangle=] is + exposed by {{VideoFrame/visibleRect}}. + + NOTE: Codecs and containers often describe the [=visible rectangle=] with + cropping parameters. Constructing a {{VideoFrame}} from another + {{VideoFrame}} with a different {{VideoFrameInit/visibleRect}} crops it + without copying its pixel data. + +: Display size +:: The display width and display height at which the + {{VideoFrame}} is intended to be presented. The [=display size=] is the + size of the [=visible rectangle=] after scaling it to account for the + aspect ratio of its pixels, and then rotating it by + {{VideoFrame/rotation}}: when {{VideoFrame/rotation}} is `90` or `270`, the + [=display width=] corresponds to the scaled height of the + [=visible rectangle=], and the [=display height=] to its scaled width. + {{VideoFrame/flip}} does not change the [=display size=]. The + [=display size=] is exposed by {{VideoFrame/displayWidth}} and + {{VideoFrame/displayHeight}}. + + NOTE: The scaling is determined by the bitstream, by + {{VideoDecoderConfig/displayAspectWidth}} and + {{VideoDecoderConfig/displayAspectHeight}} when decoding, or by + {{VideoFrameInit/displayWidth}} and {{VideoFrameInit/displayHeight}} + when constructing a {{VideoFrame}}. When pixels are square, the + [=display size=] is the size of the [=visible rectangle=], with its + width and height swapped if {{VideoFrame/rotation}} is `90` or `270`. + +: Stride +:: The number of bytes from the start of a row of a plane to the start of the + next row of the same plane. The [=stride=] of a plane is greater than or + equal to the number of bytes occupied by the samples of one of its rows. + The remaining bytes of each row, if any, are padding. Unlike the + [=coded size=], that is measured in pixels and applies to the whole frame, + a [=stride=] is measured in bytes and applies to a single plane. + + The [=stride=] of the planes of the [=media resource=] is not exposed. A + {{PlaneLayout}} describes the [=stride=] of a plane in a buffer provided by + the author: the buffer that pixel data is read from when constructing a + {{VideoFrame}} with {{VideoFrameBufferInit/layout}}, or the buffer that + pixel data is written to by {{VideoFrame/copyTo()}} with + {{VideoFrameCopyToOptions/layout}}. + +
+NOTE: The following diagram illustrates the [=coded size=], the + [=visible rectangle=], and the [=display size=] of a {{VideoFrame}} whose + pixels are wider than they are tall, with a {{VideoFrame/rotation}} of `0` + and of `90`. + +On the left, a rectangle of codedWidth by codedHeight pixels, in
+    which the visible rectangle is placed at offset x, y, with a size of width
+    by height. The area outside of the visible rectangle is not displayed. In
+    the middle, with a rotation of 0, the visible rectangle is scaled
+    horizontally, to a size of displayWidth by displayHeight. On the right,
+    with a rotation of 90, the scaled picture is rotated clockwise, and its
+    displayWidth and displayHeight are swapped compared to the middle. +
+ +
+NOTE: The following diagram illustrates the memory layout of the planes of an + {{I420}} {{VideoFrame}} with a [=coded size=] of 12 by 8 pixels, and a + [=visible rectangle=] of 10 by 6 pixels at offset (0, 0). The planes have + a [=stride=] larger than the number of bytes of samples in their rows. + +The Y plane has codedHeight rows of codedWidth samples, followed by
+    padding bytes that complete each row up to the stride of the plane. The U
+    and V planes are sub-sampled by a factor of 2 in both directions: they have
+    codedHeight divided by 2 rows of codedWidth divided by 2 samples, rounded
+    up, followed by padding bytes up to the stride of the plane. The visible
+    rectangle covers the top-left samples of each plane. +
+ +
+ An H.264 bitstream has pictures of 1440 by 1080 pixels, and signals that its + pixels are a third wider than they are tall, so that its pictures are + intended to be displayed at 1920 by 1080 pixels. H.264 encodes pictures in + macroblocks of 16 by 16 pixels, so its pictures are encoded with a height of + 1088 pixels, and the bitstream signals that the bottom 8 rows of pixels are + to be cropped. A {{VideoFrame}} decoded from this bitstream can have: + * a [=coded size=] of 1440 by 1088 pixels ({{VideoFrame/codedWidth}} and + {{VideoFrame/codedHeight}}), + * a [=visible rectangle=] of 1440 by 1080 pixels at offset (0, 0) + ({{VideoFrame/visibleRect}}), + * a [=display size=] of 1920 by 1080 pixels ({{VideoFrame/displayWidth}} and + {{VideoFrame/displayHeight}}). With a {{VideoFrame/rotation}} of `90`, the + [=display size=] would be 1080 by 1920 pixels. + + If its format is {{I420}}, its Y plane has 1088 rows of 1440 samples, and its + U and V planes have 544 rows of 720 samples. A User Agent that aligns rows of + pixel data to multiples of 64 bytes would use a [=stride=] of 1472 bytes for + the Y plane, and of 768 bytes for the U and V planes. +
VideoFrame CopyTo() Options {#videoframe-copyto-options} ------------------------------------------------------------ @@ -4563,7 +4673,7 @@ {{VideoFrame/copyTo()}} and {{VideoFrame/allocationSize()}} to describe the dimensions of the source rectangle. {{VideoFrame}} defines {{VideoFrame/codedRect}} and {{VideoFrame/visibleRect}} for convenient copying -of the coded size and visible region respectively. +of the [=coded size=] and [=visible rectangle=] respectively. NOTE: VideoFrame pixels are only addressable by integer numbers. All floating point values provided to {{DOMRectInit}} will be truncated. @@ -4589,8 +4699,8 @@ :: The offset in bytes where the given plane begins within a {{BufferSource}}. : stride -:: The number of bytes, including padding, used by each row of the plane within - a {{BufferSource}}. +:: The [=stride=] of the plane within a {{BufferSource}}, i.e. the number of + bytes, including padding, used by each row of the plane. Pixel Format{#pixel-format} ---------------------------