diff --git a/.github/workflows/auto-publish.yml b/.github/workflows/auto-publish.yml index 03e93932..5d7bc63b 100644 --- a/.github/workflows/auto-publish.yml +++ b/.github/workflows/auto-publish.yml @@ -93,6 +93,16 @@ jobs: echidna_token: ECHIDNA_TOKEN_ULAW_REGISTRATION build_override: | status: NOTE-WD + - source: hevc_codec_registration.src.html + destination: hevc_codec_registration.html + echidna_token: ECHIDNA_TOKEN_HEVC_REGISTRATION + build_override: | + status: NOTE-WD + - source: video_frame_metadata_registry.src.html + destination: video_frame_metadata_registry.html + echidna_token: ECHIDNA_TOKEN_VIDEOFRAMEMETADATA_REGISTRY + build_override: | + status: DRY steps: # See doc at https://github.com/actions/checkout#checkout-v2 - name: Checkout repository diff --git a/.gitignore b/.gitignore index 8007bba1..1755a8a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,19 @@ /index.html +aac_codec_registration.html +alaw_codec_registration.html alaw_codec_registration.html av1_codec_registration.html avc_codec_registration.html codec_registry.html flac_codec_registration.html +hevc_codec_registration.html mp3_codec_registration.html -aac_codec_registration.html opus_codec_registration.html out/ +pcm_codec_registration.html ulaw_codec_registration.html +ulaw_codec_registration.html +video_frame_metadata_registry.html vorbis_codec_registration.html vp8_codec_registration.html vp9_codec_registration.html -pcm_codec_registration.html -alaw_codec_registration.html -ulaw_codec_registration.html diff --git a/README.md b/README.md index 9f332743..56e0f335 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ Many Web APIs use media codecs internally to support APIs for particular uses: - MediaRecorder - WebRTC -But there’s no general way to flexibly configure and use these media codecs. -Because of this, many web applications have resorted to implementing +But there’s no general way to flexibly configure and use these media codecs. +Because of this, many web applications have resorted to implementing media codecs in JavaScript or WebAssembly, despite the disadvantages: - Increased bandwidth to download codecs already in the browser. - Reduced performance -- Reduced power efficiency +- Reduced power efficiency It's great for: - Live streaming @@ -27,6 +27,20 @@ See the [explainer](https://github.com/w3c/webcodecs/blob/main/explainer.md) for Please see https://w3c.github.io/webcodecs/samples/ -## WebCodecs Codec Registry +## WebCodecs registries -This repository also contains the [WebCodecs Codec Registry](https://w3c.github.com/webcodecs/codec_registry.html), which provides the means to identify and avoid collisions among codec strings used in WebCodecs and provides a mechanism to define codec-specific members of WebCodecs codec configuration dictionaries. Codec-specific registrations entered in the registry are also maintained in the repository, please refer to the registry for a comprehensive list. +This repository also contains two registries: + +* The [WebCodecs Codec Registry](https://w3c.github.io/webcodecs/codec_registry.html) +provides the means to identify and avoid collisions among codec strings +used in WebCodecs and provides a mechanism to define codec-specific members of +WebCodecs codec configuration dictionaries. Codec-specific registrations entered +in the registry are also maintained in the repository, please refer to the +registry for a comprehensive list. + +* The [WebCodecs VideoFrame Metadata Registry](https://w3c.github.io/webcodecs/video_frame_metadata_registry.html) +enumerates the metadata fields that can be attached to +[VideoFrame](https://w3c.github.io/webcodecs/#videoframe-interface) objects via the +[VideoFrameMetadata](https://w3c.github.io/webcodecs/#dictdef-videoframemetadata) dictionary. +Metadata registrations entered in the registry may be maintained in this repository +or elsewhere. Please refer to the registry for a comprehensive list. diff --git a/aac_codec_registration.src.html b/aac_codec_registration.src.html index 07557ff9..7ce7f676 100644 --- a/aac_codec_registration.src.html +++ b/aac_codec_registration.src.html @@ -7,16 +7,16 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/aac_codec_registration.html TR: https://www.w3.org/TR/webcodecs-aac-codec-registration/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This registration is entered into the [[webcodecs-codec-registry]]. It describes, for AAC, the (1) fully qualified codec strings, (2) the - codec-specific {{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] - bytes, (3) the {{AudioDecoderConfig.description}} bytes, (4) the values of - {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=], and (5) the - codec-specific extensions to {{AudioEncoderConfig}} + codec-specific {{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}} + bytes, (3) the {{AudioDecoderConfig/description|AudioDecoderConfig.description}} + bytes, (4) the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}}, + and (5) the codec-specific extensions to {{AudioEncoderConfig}} The registration is not intended to include any information on whether a codec format is encumbered by intellectual property claims. Implementers and @@ -32,23 +32,6 @@ !Version History: https://github.com/w3c/webcodecs/commits -
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-        text: AudioDecoderConfig.sampleRate; url: dom-audiodecoderconfig-samplerate
-        text: AudioDecoderConfig.numberOfChannels; url: dom-audiodecoderconfig-numberofchannels
-    type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-        text: AudioEncoderConfig; url: dictdef-audioencoderconfig
-
-
 {
   "iso14496-3": {
@@ -76,32 +59,32 @@
 ================================================
 
 If the bitstream is in {{AacBitstreamFormat/adts}} format, the
-[=EncodedAudioChunk/[[internal data]]=] of {{EncodedAudioChunk}}s are expected
+{{EncodedAudioChunk/[[internal data]]}} of {{EncodedAudioChunk}}s are expected
 to be an ADTS frame, as described in section 1.A.3.2 of [[iso14496-3]].
 
 If the bitstream is in {{AacBitstreamFormat/aac}} format, the
-[=EncodedAudioChunk/[[internal data]]=] of {{EncodedAudioChunk}}s are expected
+{{EncodedAudioChunk/[[internal data]]}} of {{EncodedAudioChunk}}s are expected
 to be a raw AAC frame (syntax element `raw_data_block()`), as described in
 section 4.4.2.1 of [[iso14496-3]].
 
 AudioDecoderConfig description {#audiodecoderconfig-description}
 ================================================================
 
-If {{AudioDecoderConfig.description}} is present, it is assumed to a
+If {{AudioDecoderConfig/description}} is present, it is assumed to a
 `AudioSpecificConfig` as defined in [[iso14496-3]] section 1.6.2.1, Table 1.15,
 and the bitstream is assumed to be in {{AacBitstreamFormat/aac}}.
 
-If the {{AudioDecoderConfig.description}} is not present, the bitstream is
+If the {{AudioDecoderConfig/description}} is not present, the bitstream is
 assumed to be in {{AacBitstreamFormat/adts}} format.
 
-The {{AudioDecoderConfig.sampleRate}} and {{AudioDecoderConfig.numberOfChannels}}
+The {{AudioDecoderConfig/sampleRate}} and {{AudioDecoderConfig/numberOfChannels}}
 members are ignored.
 
 EncodedAudioChunk type {#encodedaudiochunk-type}
 ================================================
 
-The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing
-AAC is always "[=EncodedAudioChunkType/key=]".
+The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing
+AAC is always "{{EncodedAudioChunkType/key}}".
 
 NOTE: Once the initialization has succeeded, any AAC packet can be decoded at
     any time without error, but this might not result in the expected audio
@@ -161,17 +144,22 @@
       
aac
The metadata of the encoded audio stream are provided at configuration via - {{AudioDecoderConfig.description}}. + {{AudioDecoderConfig/description|AudioDecoderConfig.description}}.
adts
The metadata of the encoded audio stream are provided in each ADTS frame, - and therefore no {{AudioDecoderConfig.description}} is necessary. + and therefore no {{AudioDecoderConfig/description|AudioDecoderConfig.description}} is necessary. -Privacy and Security Considerations {#privacy-and-security-considerations} +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/alaw_codec_registration.src.html b/alaw_codec_registration.src.html index 1d9b3192..1242f054 100644 --- a/alaw_codec_registration.src.html +++ b/alaw_codec_registration.src.html @@ -7,16 +7,16 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/alaw_codec_registration.html TR: https://www.w3.org/TR/webcodecs-alaw-codec-registration/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This registration is entered into the [[webcodecs-codec-registry]]. It describes, for A-law encoded PCM, the (1) fully qualified codec strings, (2) the codec-specific {{EncodedAudioChunk}} - [=EncodedAudioChunk/[[internal data]]=] bytes, (3) the - {{AudioDecoderConfig.description}}, and (4) the values of - {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=]. + {{EncodedAudioChunk/[[internal data]]}} bytes, (3) the + {{AudioDecoderConfig/description|AudioDecoderConfig.description}}, + and (4) the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}}. The registration is not intended to include any information on whether a codec format is encumbered by intellectual property claims. Implementers and @@ -32,21 +32,6 @@ !Version History: https://github.com/w3c/webcodecs/commits
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-    type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-        text: AudioEncoderConfig; url: dictdef-audioencoderconfig
-
-
 {
   "ITU-G.711": {
@@ -66,25 +51,30 @@
 EncodedAudioChunk data {#encodedaudiochunk-data}
 ================================================
 
-{{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] is expected to be
+{{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}} is expected to be
 a sequence of bytes of arbitrary length, where each byte is an A-law
 encoded PCM sample as defined by Tables 1a and 1b in [[ITU-G.711]].
 
 AudioDecoderConfig description {#audiodecoderconfig-description}
 ================================================================
 
-An {{AudioDecoderConfig.description}} is expected to be omitted from the
+The {{AudioDecoderConfig/description}} is expected to be omitted from the
 {{AudioDecoderConfig}}.
 
 EncodedAudioChunk type {#encodedaudiochunk-type}
 ================================================
 
-The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing
-A-law PCM is always "[=EncodedAudioChunkType/key=]".
+The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing
+A-law PCM is always "{{EncodedAudioChunkType/key}}".
+
+Privacy Considerations {#privacy-considerations}
+==========================================================================
+
+Please refer to the section [[WEBCODECS#privacy-considerations|Privacy
+Considerations]] in [[WEBCODECS]].
 
-Privacy and Security Considerations {#privacy-and-security-considerations}
+Security Considerations {#security-considerations}
 ==========================================================================
 
-Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]]
-and [[WEBCODECS#security-considerations|Security Considerations]] sections in
-[[WEBCODECS]].
+Please refer to the section [[WEBCODECS#security-considerations|Security
+Considerations]] in [[WEBCODECS]].
diff --git a/av1_codec_registration.src.html b/av1_codec_registration.src.html
index 83b0299a..7b3be04f 100644
--- a/av1_codec_registration.src.html
+++ b/av1_codec_registration.src.html
@@ -7,16 +7,18 @@
 Group: mediawg
 ED: https://w3c.github.io/webcodecs/av1_codec_registration.html
 TR: https://www.w3.org/TR/webcodecs-av1-codec-registration/
-Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/
 Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/
+Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 
 Abstract: This registration is entered into the [[webcodecs-codec-registry]].
     It describes, for AV1, the (1) fully qualified codec strings,
     (2) the codec-specific {{EncodedVideoChunk}}
-    [=EncodedVideoChunk/[[internal data]]=] bytes, (3) the
-    {{VideoDecoderConfig.description}} bytes, and (4) the values of
-    {{EncodedVideoChunk}} [=EncodedVideoChunk/[[type]]=].
+    {{EncodedVideoChunk/[[internal data]]}} bytes, (3) the codec-specific
+    extensions to {{VideoEncoderConfig}}, (4) the
+    {{VideoDecoderConfig/description|VideoDecoderConfig.description}} bytes,
+    (5) the values of {{EncodedVideoChunk}} {{EncodedVideoChunk/[[type]]}}, and
+    (6) the codec-specific extensions to {{VideoEncoderEncodeOptions}}.
 
     The registration is not intended to include any information on whether a
     codec format is encumbered by intellectual property claims. Implementers and
@@ -32,24 +34,6 @@
 !Version History: https://github.com/w3c/webcodecs/commits
 
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: EncodedVideoChunkMetadata.decoderConfig; url: dom-encodedvideochunkmetadata-decoderconfig
-        for: EncodedVideoChunkType; text: key; url: dom-encodedvideochunktype-key
-        text: VideoDecoderConfig.description; url: dom-videodecoderconfig-description
-    type: dfn
-        for: EncodedVideoChunk; text: [[internal data]]; url: dom-encodedvideochunk-internal-data-slot
-        for: EncodedVideoChunk; text: [[type]]; url: dom-encodedvideochunk-type-slot
-        for: VideoEncoder; text: [[output callback]]; url: dom-videoencoder-output-callback-slot
-    type: interface
-        text: EncodedVideoChunk; url: encodedvideochunk
-        text: VideoEncoder; url: videoencoder
-    type: dictionary
-        text: VideoEncoderConfig; url: dictdef-videoencoderconfig
-        text: VideoDecoderConfig; url: dictdef-videodecoderconfig
-
-
 {
   "AV1": {
@@ -74,26 +58,108 @@
 EncodedVideoChunk data {#encodedvideochunk-data}
 ================================================
 
-{{EncodedVideoChunk}} [=EncodedVideoChunk/[[internal data]]=] is expected to be
+{{EncodedVideoChunk}} {{EncodedVideoChunk/[[internal data]]}} is expected to be
 data compliant to the "low-overhead bitstream format" as described in Section 5
 of [[AV1]].
 
 VideoDecoderConfig description {#videodecoderconfig-description}
 ================================================================
 
-{{VideoDecoderConfig.description}} is not used for this codec.
+{{VideoDecoderConfig/description}} is not used for this codec.
 
 EncodedVideoChunk type {#encodedvideochunk-type}
 ================================================
 
-If an {{EncodedVideoChunk}}'s [=EncodedVideoChunk/[[type]]=] is
+If an {{EncodedVideoChunk}}'s {{EncodedVideoChunk/[[type]]}} is
 {{EncodedVideoChunkType/key}}, then the {{EncodedVideoChunk}} is expected to
 contain a frame with a `frame_type` of `KEY_FRAME` as defined in Section
 6.8.2 of [[AV1]].
 
-Privacy and Security Considerations {#privacy-and-security-considerations}
+VideoEncoderConfig extensions {#videoencoderconfig-extensions}
+==============================================================
+
+
+
+partial dictionary VideoEncoderConfig {
+  AV1EncoderConfig av1;
+};
+
+
+ +
+
av1
+
+ Contains codec specific configuration options for the AV1 codec. +
+
+ +AV1EncoderConfig {#av1-encoder-config} +-------------------------------------- +
+
+dictionary AV1EncoderConfig {
+  boolean forceScreenContentTools = false;
+};
+
+
+ +
+
forceScreenContentTools
+
+ Indicates whether the encoder should force use of screen content + coding tools. The default value (false) indicates that use of + screen content coding tools is not forced. A value of true + (corresponding to setting seq_force_screen_content_tools + to SELECT_SCREEN_CONTENT_TOOLS in Section 5.5.1 + of [[AV1]]) indicates that use of screen content coding tools + is forced. +
+
+ +VideoEncoderEncodeOptions extensions {#videoencoderencodeoptions-extensions} +============================================================== + +
+
+partial dictionary VideoEncoderEncodeOptions {
+  VideoEncoderEncodeOptionsForAv1 av1;
+};
+
+
+ +
+
av1
+
+ Contains codec specific encode options for the [[AV1]] codec. +
+
+ +VideoEncoderEncodeOptionsForAv1 {#av1-encode-options} +-------------------------------------- +
+
+dictionary VideoEncoderEncodeOptionsForAv1 {
+  unsigned short? quantizer;
+};
+
+
+ +
+
quantizer
+
+ Sets per-frame quantizer value. + In [[AV1]] the quantizer threshold can be varied from 0 to 63 +
+
+ +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/avc_codec_registration.src.html b/avc_codec_registration.src.html index 024bfd2f..0dfcaa5f 100644 --- a/avc_codec_registration.src.html +++ b/avc_codec_registration.src.html @@ -7,17 +7,18 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/avc_codec_registration.html TR: https://www.w3.org/TR/webcodecs-avc-codec-registration/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This registration is entered into the [[webcodecs-codec-registry]]. It describes, for AVC (H.264), the (1) fully qualified codec strings, (2) the codec-specific {{EncodedVideoChunk}} - [=EncodedVideoChunk/[[internal data]]=] bytes, (3) the - {{VideoDecoderConfig.description}} bytes, (4) the values of - {{EncodedVideoChunk}} [=EncodedVideoChunk/[[type]]=], and (5) the - codec-specific extensions to {{VideoEncoderConfig}} + {{EncodedVideoChunk/[[internal data]]}} bytes, (3) the + {{VideoDecoderConfig/description|VideoDecoderConfig.description}} bytes, + (4) the values of {{EncodedVideoChunk}} {{EncodedVideoChunk/[[type]]}}, + (5) the codec-specific extensions to {{VideoEncoderConfig}}, and + (6) the codec-specific extensions to {{VideoEncoderEncodeOptions}}. The registration is not intended to include any information on whether a codec format is encumbered by intellectual property claims. Implementers and @@ -33,24 +34,6 @@ !Version History: https://github.com/w3c/webcodecs/commits
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: EncodedVideoChunkMetadata.decoderConfig; url: dom-encodedvideochunkmetadata-decoderconfig
-        for: EncodedVideoChunkType; text: key; url: dom-encodedvideochunktype-key
-        text: VideoDecoderConfig.description; url: dom-videodecoderconfig-description
-    type: dfn
-        for: EncodedVideoChunk; text: [[internal data]]; url: dom-encodedvideochunk-internal-data-slot
-        for: EncodedVideoChunk; text: [[type]]; url: dom-encodedvideochunk-type-slot
-        for: VideoEncoder; text: [[output callback]]; url: dom-videoencoder-output-callback-slot
-    type: interface
-        text: EncodedVideoChunk; url: encodedvideochunk
-        text: VideoEncoder; url: videoencoder
-    type: dictionary
-        text: VideoEncoderConfig; url: dictdef-videoencoderconfig
-        text: VideoDecoderConfig; url: dictdef-videodecoderconfig
-
-
 {
   "ITU-T-REC-H.264": {
@@ -78,26 +61,26 @@
 EncodedVideoChunk data {#encodedvideochunk-data}
 ================================================
 
-{{EncodedVideoChunk}} [=EncodedVideoChunk/[[internal data]]=] is expected to be
+{{EncodedVideoChunk}} {{EncodedVideoChunk/[[internal data]]}} is expected to be
 an access unit as defined in [[ITU-T-REC-H.264]] section 7.4.1.2.
 
 NOTE: An access unit contains exactly one primary coded picture.
 
 If the bitstream is in {{AvcBitstreamFormat/avc}} format,
-[=EncodedVideoChunk/[[internal data]]=] is assumed to be in canonical format, as
+{{EncodedVideoChunk/[[internal data]]}} is assumed to be in canonical format, as
 defined in [[iso14496-15]] section 5.3.2.
 
 If the bitstream is in {{AvcBitstreamFormat/annexb}} format,
-[=EncodedVideoChunk/[[internal data]]=] is assumed to be in in Annex B format,
+{{EncodedVideoChunk/[[internal data]]}} is assumed to be in in Annex B format,
 as defined in [[ITU-T-REC-H.264]] Annex B.
 
-NOTE: Since [=EncodedVideoChunk/[[internal data]]=] is inherently byte-aligned,
+NOTE: Since {{EncodedVideoChunk/[[internal data]]}} is inherently byte-aligned,
     implementations are not required to recover byte-alignment.
 
 VideoDecoderConfig description {#videodecoderconfig-description}
 ================================================================
 
-If the {{VideoDecoderConfig.description}} is present, it is assumed to be an
+If the {{VideoDecoderConfig/description}} is present, it is assumed to be an
 `AVCDecoderConfigurationRecord`, as defined by [[iso14496-15]], section
 5.3.3.1, and the bitstream is assumed to be in {{AvcBitstreamFormat/avc}}
 format.
@@ -105,7 +88,7 @@
 NOTE: This format is commonly used in .MP4 files, where the player generally
     has random access to the media data.
 
-If the {{VideoDecoderConfig.description}} is not present, the bitstream is
+If the {{VideoDecoderConfig/description}} is not present, the bitstream is
 assumed to be in {{AvcBitstreamFormat/annexb}} format.
 
 NOTE: "annexb" format is described in greater detail by [[ITU-T-REC-H.264]],
@@ -116,16 +99,17 @@
 EncodedVideoChunk type {#encodedvideochunk-type}
 ================================================
 
-If an {{EncodedVideoChunk}}'s [=EncodedVideoChunk/[[type]]=] is
+If an {{EncodedVideoChunk}}'s {{EncodedVideoChunk/[[type]]}} is
 {{EncodedVideoChunkType/key}}, and the bitstream is in
 {{AvcBitstreamFormat/avc}} format, then the {{EncodedVideoChunk}} is expected to
 contain a primary coded picture that is an instantaneous decoding refresh (IDR)
 picture.
 
 NOTE: If the bitstream is in {{AvcBitstreamFormat/avc}} format, parameter sets
-    necessary for decoding are included in {{VideoDecoderConfig.description}}.
+    necessary for decoding are included in
+    {{VideoDecoderConfig/description|VideoDecoderConfig.description}}.
 
-If an {{EncodedVideoChunk}}'s [=EncodedVideoChunk/[[type]]=] is
+If an {{EncodedVideoChunk}}'s {{EncodedVideoChunk/[[type]]}} is
 {{EncodedVideoChunkType/key}}, and the bitstream is in
 {{AvcBitstreamFormat/annexb}} format, then the {{EncodedVideoChunk}} is expected
 to contain both a primary coded picture that is an instantaneous decoding
@@ -179,12 +163,8 @@
 
 
-The {{AvcBitstreamFormat}} determines the location of AVC Sequence Parameter -Set (SPS) and Picture Parameter Set (PPS) data, and mechanisms for packaging -the bitstream. - -SPS and PPS are described in greater detail in sections G.3.41 and G.3.55 of -[[ITU-T-REC-H.264]]. +The {{AvcBitstreamFormat}} determines the location of AVC parameter sets, and +mechanisms for packaging the bitstream.
annexb
@@ -199,18 +179,59 @@
avc
SPS and PPS data are not included in the bitstream and are instead emitted - via the [=VideoEncoder/[[output callback]]=] as the - {{VideoDecoderConfig.description}} of the - {{EncodedVideoChunkMetadata.decoderConfig}}. + via the {{VideoEncoder/[[output callback]]}} as the + {{VideoDecoderConfig/description|VideoDecoderConfig.description}} of the + {{EncodedVideoChunkMetadata/decoderConfig|EncodedVideoChunkMetadata.decoderConfig}}. NOTE: This format is described in greater detail by [[iso14496-15]], - section 5.3.3.1. This format is commonly used in .MP4 files, where the + section 5.3. This format is commonly used in .MP4 files, where the player generally has random access to the media data.
-Privacy and Security Considerations {#privacy-and-security-considerations} +VideoEncoderEncodeOptions extensions {#videoencoderencodeoptions-extensions} +============================================================== + +
+
+partial dictionary VideoEncoderEncodeOptions {
+  VideoEncoderEncodeOptionsForAvc avc;
+};
+
+
+ +
+
avc
+
+ Contains codec specific encode options for the [[ITU-T-REC-H.264]] codec. +
+
+ +VideoEncoderEncodeOptionsForAvc {#avc-encode-options} +-------------------------------------- +
+
+dictionary VideoEncoderEncodeOptionsForAvc {
+  unsigned short? quantizer;
+};
+
+
+ +
+
quantizer
+
+ Sets per-frame quantizer value. + In [[ITU-T-REC-H.264]] the quantizer threshold can be varied from 0 to 51. +
+
+ +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/codec_registry.src.html b/codec_registry.src.html index 83faef75..780a510b 100644 --- a/codec_registry.src.html +++ b/codec_registry.src.html @@ -7,9 +7,9 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/codec_registry.html TR: https://www.w3.org/TR/webcodecs-codec-registry/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Boilerplate: omit conformance @@ -34,23 +34,6 @@ !Version History: https://github.com/w3c/webcodecs/commits -
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-        text: VideoDecoderConfig.description; url: dom-videodecoderconfig-description
-    type: dfn
-        for: EncodedVideoChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-        text: EncodedVideoChunk; url: encodedvideochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-        text: AudioEncoderConfig; url: dictdef-audioencoderconfig
-        text: VideoDecoderConfig; url: dictdef-videodecoderconfig
-        text: VideoEncoderConfig; url: dictdef-videoencoderconfig
-
- Organization {#organization} ============================ @@ -78,17 +61,25 @@ 2. {{EncodedAudioChunk}} or {{EncodedVideoChunk}} internal data 3. {{AudioDecoderConfig}} or {{VideoDecoderConfig}} description bytes 4. Expectations for {{EncodedAudioChunk}} or {{EncodedVideoChunk}} - [=EncodedVideoChunk/[[type]]=] -3. Where applicable, a registration specification may include a section + {{EncodedVideoChunk/[[type]]}} +4. Where applicable, a registration specification may include a section describing extensions to {{VideoEncoderConfig}} or {{AudioEncoderConfig}} dictionaries. -4. Candidate entries must be announced by filing an issue in the +5. Candidate entries must be announced by filing an issue in the [WebCodecs GitHub issue tracker](https://github.com/w3c/webcodecs/issues/) so they can be discussed and evaluated for compliance before being added to - the registry. If registry editors reach consensus to accept the candidate, - a pull request should be drafted (either by editors or by the party - requesting the candidate registration) to register the candidate. The - registry editors will review and merge the pull request. + the registry. The Media Working Group may seek expertise from outside the + Working Group as part of its evaluation, e.g., from the codec specification + editors or relevant standards group. If the Working Group reaches consensus + to accept the candidate, a pull request should be drafted (either by editors + or by the party requesting the candidate registration) to register the + candidate. The registry editors will review and merge the pull request. +6. Existing entries cannot be deleted or deprecated. They may be changed after + being published through the same process as candidate entries. Possible + changes include expansion of the codec string to better qualify the codec, + adjustments to the codec name string, and modification of the link to the + public specification. + Audio Codec Registry {#audio-codec-registry} ============================================ @@ -112,7 +103,7 @@ [[WEBCODECS-MP3-CODEC-REGISTRATION]] - mp4a.* + mp4a.\* AAC [AAC WebCodecs Registration](https://www.w3.org/TR/webcodecs-aac-codec-registration/) @@ -147,7 +138,7 @@ [[WEBCODECS-ALAW-CODEC-REGISTRATION]] - pcm-* + pcm-\* Linear PCM [Linear PCM WebCodecs Registration](https://www.w3.org/TR/webcodecs-pcm-codec-registration/) @@ -165,30 +156,40 @@ **specification** - av01.* + av01.\* AV1 [AV1 codec registration](https://www.w3.org/TR/webcodecs-av1-codec-registration/) [[WEBCODECS-AV1-CODEC-REGISTRATION]] - avc1.* + avc1.\*, avc3.\* AVC / H.264 [AVC (H.264) WebCodecs Registration](https://www.w3.org/TR/webcodecs-avc-codec-registration/) [[WEBCODECS-AVC-CODEC-REGISTRATION]] + + hev1.\*, hvc1.\* + HEVC / H.265 + [HEVC (H.265) WebCodecs Registration](https://www.w3.org/TR/webcodecs-hevc-codec-registration/) [[WEBCODECS-HEVC-CODEC-REGISTRATION]] + vp8 VP8 [VP8 codec registration](https://www.w3.org/TR/webcodecs-vp8-codec-registration/) [[WEBCODECS-VP8-CODEC-REGISTRATION]] - vp09.* + vp09.\* VP9 [VP9 codec registration](https://www.w3.org/TR/webcodecs-vp9-codec-registration/) [[WEBCODECS-VP9-CODEC-REGISTRATION]] -Privacy and Security Considerations {#privacy-and-security-considerations} +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/flac_codec_registration.src.html b/flac_codec_registration.src.html index 8b770136..9c87bbc4 100644 --- a/flac_codec_registration.src.html +++ b/flac_codec_registration.src.html @@ -7,16 +7,17 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/flac_codec_registration.html TR: https://www.w3.org/TR/webcodecs-flac-codec-registration/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This registration is entered into the [[webcodecs-codec-registry]]. It describes, for FLAC, the (1) fully qualified codec strings, (2) the codec-specific {{EncodedAudioChunk}} - [=EncodedAudioChunk/[[internal data]]=] bytes, (3) the - {{AudioDecoderConfig.description}} bytes, and (4) the values of - {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=]. + {{EncodedAudioChunk/[[internal data]]}} bytes, (3) the + {{AudioDecoderConfig/description|AudioDecoderConfig.description}} bytes, + (4) the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}}, + and (5) the codec-specific extensions to {{AudioEncoderConfig}}. The registration is not intended to include any information on whether a codec format is encumbered by intellectual property claims. Implementers and @@ -32,28 +33,12 @@ !Version History: https://github.com/w3c/webcodecs/commits -
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-        text: AudioDecoderConfig.sampleRate; url: dom-audiodecoderconfig-samplerate
-        text: AudioDecoderConfig.numberOfChannels; url: dom-audiodecoderconfig-numberofchannels
-    type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-
-
 {
   "FLAC": {
-    "href": "https://xiph.org/flac/format.html",
-    "title": "FLAC - format",
-    "publisher": "Xiph.Org Foundation"
+    "href": "https://datatracker.ietf.org/doc/draft-ietf-cellar-flac",
+    "title": "Free Lossless Audio Codec",
+    "publisher": "IETF"
   }
 }
 
@@ -66,21 +51,21 @@ EncodedAudioChunk data {#encodedaudiochunk-data} ================================================ -{{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] is expected to be +{{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}} is expected to be a "FRAME" as described in [[FLAC]]. AudioDecoderConfig description {#audiodecoderconfig-description} ================================================================ -{{AudioDecoderConfig.description}} is required, and has to be the following: +{{AudioDecoderConfig/description}} is required, and has to be the following: - The bytes `0x66 0x4C 0x61 0x43` ("`fLaC`" in ASCII) -- A `METADATA_BLOCK` of type `STEAMINFO` as described in [[FLAC]] -- Optionaly other `METADATA_BLOCK`, that are not used by the specification +- A `metadata block` (called the STREAMINFO block) as described in section 7 of [[FLAC]] +- Optionaly other metadata blocks, that are not used by the specification -The {{AudioDecoderConfig.sampleRate}} and {{AudioDecoderConfig.numberOfChannels}} +The {{AudioDecoderConfig/sampleRate}} and {{AudioDecoderConfig/numberOfChannels}} members are overridden by what the decoder finds in the -{{AudioDecoderConfig.description}}. +{{AudioDecoderConfig/description}}. NOTE: This corresponds to the beginning of a FLAC bitstream, before the audio frames. @@ -88,15 +73,73 @@ EncodedAudioChunk type {#encodedaudiochunk-type} ================================================ -The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing -FLAC is always "[=EncodedAudioChunkType/key=]". +The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing +FLAC is always "{{EncodedAudioChunkType/key}}". NOTE: Once the initialization has succeeded, any FLAC packet can be decoded at any time without error, but this might not result in the expected audio output. -Privacy and Security Considerations {#privacy-and-security-considerations} +AudioEncoderConfig extensions {#audioencoderconfig-extensions} +============================================================= + +
+
+partial dictionary AudioEncoderConfig {
+  FlacEncoderConfig flac;
+};
+
+
+ +
+
flac
+
+ Contains codec specific configuration options for the FLAC codec. +
+
+ + +FlacEncoderConfig {#flac-encoder-config} +-------------------------------------- + +
+
+dictionary FlacEncoderConfig {
+  [EnforceRange] unsigned long blockSize = 0;
+  [EnforceRange] unsigned long compressLevel = 5;
+};
+
+
+ +To check if an {{FlacEncoderConfig}} is valid, run these steps: +1. If {{FlacEncoderConfig/blockSize}} is not a valid block size, + which is described section 5.1 of [[FLAC]], return `false`. +1. If {{FlacEncoderConfig/compressLevel}} is specified and not within the range of + `0` (fastest, least compression) and `8` (slowest, most compression) inclusively, return `false`. +2. Return `true`. + +
+
blockSize
+
+ Configures the number of samples to use per frame, of output {{EncodedAudioChunk}}s. + + NOTE: Use 0 to let the encoder estimate a blocksize by default. +
+ +
compressLevel
+
+ Configures the compression level to use while encoding. +
+ +
+ +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/hevc_codec_registration.src.html b/hevc_codec_registration.src.html new file mode 100644 index 00000000..ee184f55 --- /dev/null +++ b/hevc_codec_registration.src.html @@ -0,0 +1,201 @@ +
+Title: HEVC (H.265) WebCodecs Registration
+Repository: w3c/webcodecs
+Status: NOTE-ED
+Shortname: webcodecs-hevc-codec-registration
+Level: none
+Group: mediawg
+ED: https://w3c.github.io/webcodecs/hevc_codec_registration.html
+TR: https://www.w3.org/TR/webcodecs-hevc-codec-registration/
+Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/
+Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/
+Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
+
+Abstract: This registration is entered into the [[webcodecs-codec-registry]].
+    It describes, for HEVC (H.265), the (1) fully qualified codec strings,
+    (2) the codec-specific {{EncodedVideoChunk}}
+    {{EncodedVideoChunk/[[internal data]]}} bytes, (3) the
+    {{VideoDecoderConfig/description|VideoDecoderConfig.description}} bytes,
+    (4) the values of {{EncodedVideoChunk}} {{EncodedVideoChunk/[[type]]}}, and
+    (5) the codec-specific extensions to {{VideoEncoderConfig}}
+
+    The registration is not intended to include any information on whether a
+    codec format is encumbered by intellectual property claims. Implementers and
+    authors are advised to seek appropriate legal counsel in this matter if they
+    intend to implement or use a specific codec format. Implementers of
+    WebCodecs are not required to support the HEVC / H.265 codec.
+
+    This registration is non-normative.
+
+Markup Shorthands:css no, markdown yes, dfn yes
+!Participate: Git Repository.
+!Participate: File an issue.
+!Version History: https://github.com/w3c/webcodecs/commits
+
+ + +
+{
+  "ITU-T-REC-H.265": {
+    "href": "https://www.itu.int/rec/T-REC-H.265",
+    "title": "H.265 : High efficiency video coding",
+    "publisher": "ITU",
+    "date": "August 2021"
+  },
+  "iso14496-15": {
+    "href": "https://www.iso.org/standard/74429.html",
+    "title": "ISO/IEC 14496-15:2019 Information technology — Coding of audio-visual objects — Part 15: Carriage of network abstraction layer (NAL) unit structured video in the ISO base media file format",
+    "publisher": "ISO",
+    "date": "September 2019"
+  }
+}
+
+ +Fully qualified codec strings {#fully-qualified-codec-strings} +============================================================== + +The codec string begins with the prefix "hev1." or "hvc1.", with a suffix of +four dot-separated fields as described in Section E.3 of [[iso14496-15]]. + +EncodedVideoChunk data {#encodedvideochunk-data} +================================================ + +{{EncodedVideoChunk}} {{EncodedVideoChunk/[[internal data]]}} is expected to be +an access unit as defined in [[ITU-T-REC-H.265]] section 7.4.2.4. + +NOTE: An access unit contains exactly one base layer coded picture. + +If the bitstream is in {{HevcBitstreamFormat/hevc}} format, +{{EncodedVideoChunk/[[internal data]]}} is assumed to be in canonical format, as +defined in [[iso14496-15]] section 8.3.2. + +If the bitstream is in {{HevcBitstreamFormat/annexb}} format, +{{EncodedVideoChunk/[[internal data]]}} is assumed to be in Annex B format, +as defined in [[ITU-T-REC-H.265]] Annex B. + +NOTE: Since {{EncodedVideoChunk/[[internal data]]}} is inherently byte-aligned, + implementations are not required to recover byte-alignment. + +VideoDecoderConfig description {#videodecoderconfig-description} +================================================================ + +If the {{VideoDecoderConfig/description}} is present, it is assumed to be an +`HEVCDecoderConfigurationRecord`, as defined by [[iso14496-15]], section +8.3.3.1, and the bitstream is assumed to be in {{HevcBitstreamFormat/hevc}} +format. + +NOTE: This format is commonly used in .MP4 files, where the player generally + has random access to the media data. + +If the {{VideoDecoderConfig/description}} is not present, the bitstream is +assumed to be in {{HevcBitstreamFormat/annexb}} format. + +NOTE: "annexb" format is described in greater detail by [[ITU-T-REC-H.265]], + Annex B. This format is commonly used in live-streaming applications, where + including the VPS, SPS, and PPS data periodically allows users to easily + start from the middle of the stream. + +EncodedVideoChunk type {#encodedvideochunk-type} +================================================ + +If an {{EncodedVideoChunk}}'s {{EncodedVideoChunk/[[type]]}} is +{{EncodedVideoChunkType/key}}, and the bitstream is in +{{HevcBitstreamFormat/hevc}} format, then the {{EncodedVideoChunk}} is expected +to contain a base layer primary coded picture that is an instantaneous decoding +refresh (IDR), clean random access (CRA), or broken link access (BLA) picture. + +NOTE: If the bitstream is in {{HevcBitstreamFormat/hevc}} format, parameter sets + necessary for decoding are included in + {{VideoDecoderConfig/description|VideoDecoderConfig.description}}. + +If an {{EncodedVideoChunk}}'s {{EncodedVideoChunk/[[type]]}} is +{{EncodedVideoChunkType/key}}, and the bitstream is in +{{HevcBitstreamFormat/annexb}} format, then the {{EncodedVideoChunk}} is +expected to contain both a base layer coded picture that is an instantaneous +decoding refresh (IDR), clean random access (CRA), or broken link access (BLA) +picture, and all parameter sets necessary to decode all video data +NAL units in the {{EncodedVideoChunk}}. + +VideoEncoderConfig extensions {#videoencoderconfig-extensions} +============================================================== + +
+
+partial dictionary VideoEncoderConfig {
+  HevcEncoderConfig hevc;
+};
+
+
+ +
+
hevc
+
+ Contains codec specific configuration options for the HEVC (H.265) codec. +
+
+ +HevcEncoderConfig {#hevc-encoder-config} +-------------------------------------- +
+
+dictionary HevcEncoderConfig {
+  HevcBitstreamFormat format = "hevc";
+};
+
+
+ +
+
format
+
+ Configures the format of output {{EncodedVideoChunk}}s. See + {{HevcBitstreamFormat}}. +
+
+ +HevcBitstreamFormat {#hevc-bitstream-format} +------------------------------------------ +
+
+enum HevcBitstreamFormat {
+  "annexb",
+  "hevc",
+};
+
+
+ +The {{HevcBitstreamFormat}} determines the location of HEVC parameter sets, and +mechanisms for packaging the bitstream. + +
+
annexb
+
+ Parameter sets are included periodically throughout the bitstream. + + NOTE: This format is described in greater detail by [[ITU-T-REC-H.265]], + Annex B. This format is commonly used in live-streaming applications, + where including the parameter set data periodically allows users to + easily start from the middle of the stream. +
+
hevc
+
+ Parameter sets are not included in the bitstream and are instead emitted + via the {{VideoEncoder/[[output callback]]}} as the + {{VideoDecoderConfig/description}} of the + {{EncodedVideoChunkMetadata/decoderConfig|EncodedVideoChunkMetadata.decoderConfig}}. + + NOTE: This format is described in greater detail by [[iso14496-15]], + section 8.3. This format is commonly used in .MP4 files, where the + player generally has random access to the media data. +
+ +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/index.src.html b/index.src.html index 3e5fe053..d7c6952c 100644 --- a/index.src.html +++ b/index.src.html @@ -7,9 +7,10 @@ Shortname: webcodecs Level: None Group: mediawg -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Editor: Eugene Zemtsov, w3cid 139375, Google LLC https://www.google.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This specification defines interfaces to codecs for encoding and decoding of audio, video, and images. @@ -28,77 +29,29 @@
-spec: media-source; urlPrefix: https://www.w3.org/TR/media-source/
-    type: method
-        for: MediaSource; text: isTypeSupported(); url: #dom-mediasource-istypesupported
-
 spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/;
-    for: HTMLMediaElement;
-        type: method; text: canPlayType(); url: #dom-navigator-canplaytype
-    for: PlatformObject;
-        type: attribute; text: [[Detached]]; url: structured-data.html#detached
     for: ImageBitmap;
-        type: attribute; text: resizeWidth; url:#dom-imagebitmapoptions-resizewidth
-        type: attribute; text: resizeHeight; url:#dom-imagebitmapoptions-resizeheight
-        type: dfn; text: cropped to the source rectangle with formatting; url: imagebitmap-and-animations.html#cropped-to-the-source-rectangle-with-formatting
         type: dfn; text: bitmap data; url: imagebitmap-and-animations.html#concept-imagebitmap-bitmap-data
     for: Canvas;
         type: dfn; text: Check the usability of the image argument; url: canvas.html#check-the-usability-of-the-image-argument
-    for: origin;
-        type: dfn; text: origin; url: origin.html#concept-origin
+        type: dfn; text: is not origin-clean; url: canvas.html#the-image-argument-is-not-origin-clean
     for: webappapis;
-        type: dfn; text: global object; url: webappapis.html#global-object
         type: dfn; text: entry settings object; url: webappapis.html#entry-settings-object
     for: media;
         type: dfn; text: current playback position; url: media.html#current-playback-position
     type: dfn; text: live; url: infrastructure.html#live
 
-spec: mediacapture-streams; urlPrefix: https://www.w3.org/TR/mediacapture-streams/
-    for: mediaDevices;
-        type: method; text: getUserMedia(); url: #dom-mediadevices-getusermedia
-
-spec: mediacapture-screen-share; urlPrefix: https://w3c.github.io/mediacapture-screen-share/
-    for: mediaDevices; type: method; text: getDisplayMedia(); url: #dom-mediadevices-getdisplaymedia
-
-spec: mediacapture-main; urlPrefix: https://w3c.github.io/mediacapture-main/
-    for:MediaStreamTrackState;
-        type: enum-value; text: live; url: #idl-def-MediaStreamTrackState.live
-        type: enum-value; text: ended; url: #idl-def-MediaStreamTrackState.ended
-
-spec: mimesniff; urlPrefix: https://mimesniff.spec.whatwg.org/#
-    type: dfn; text: MIME type; url: mime-type
-    type: dfn; text: valid MIME type string; url:valid-mime-type
-
-spec: infra; urlPrefix: https://infra.spec.whatwg.org/#
-    type: dfn; text: queue; url: queues
-    type: dfn; text: enqueuing; url: queue-enqueue;
-    type: dfn; text: dequeued; url: queue-dequeue;
-    type: dfn; text: empty; url: list-is-empty;
-    type: dfn; text: list; url: lists;
-
-spec: mediastream-recording; urlPrefix: https://www.w3.org/TR/mediastream-recording/#
-    type: interface; text: MediaRecorder; url: mediarecorder
-    type: interface; text: BitrateMode; url: bitratemode
-    for: BitrateMode;
-        type: enum-value; text: constant; url: dom-bitratemode-constant
-        type: enum-value; text: variable; url: dom-bitratemode-variable
-
-spec: media-capabilities; urlPrefix: https://w3c.github.io/media-capabilities/#
-    type: method; text: decodingInfo(); url: dom-mediacapabilities-decodinginfo
-    type: attribute; text: powerEfficient; url: dom-mediacapabilitiesinfo-powerefficient
-
-spec: css-images-3; urlPrefix: https://www.w3.org/TR/css-images-3/
-    type: dfn; text: natural dimensions; url: #natural-dimensions
-    type: dfn; text: natural width; url: #natural-width
-    type: dfn; text: natural height; url: #natural-height
-
 spec: webrtc-svc; urlPrefix: https://w3c.github.io/webrtc-svc/
     type: dfn; text: scalability mode identifier; url:#scalabilitymodes*
+
+spec: ECMASCRIPT; urlPrefix: https://tc39.es/ecma262/
+    type: dfn; text: the current Realm; url: #current-realm
 
@@ -108,6 +61,15 @@
     "title": "Coding-independent code points for video signal type identification",
     "publisher": "ITU",
     "date": "December 2016"
+  },
+  "WEBCODECS-VIDEO-FRAME-METADATA-REGISTRY": {
+    "href": "https://w3c.github.io/webcodecs/video_frame_metadata_registry.html",
+    "title": "WebCodecs VideoFrame Metadata Registry",
+    "publisher": "W3C",
+    "authors": [
+      "Youenn Fablet"
+    ],
+    "status": "ED"
   }
 }
 
@@ -142,8 +104,8 @@ ========================== : Codec -:: Refers generically to an instance of AudioDecoder, AudioEncoder, - VideoDecoder, or VideoEncoder. +:: Refers generically to an instance of {{AudioDecoder}}, {{AudioEncoder}}, + {{VideoDecoder}}, or {{VideoEncoder}}. : Key Chunk :: An encoded chunk that does not depend on any other frames for decoding. Also @@ -200,6 +162,17 @@ "matrix" → {{VideoMatrixCoefficients/bt709}}, "fullRange" → `false`]». +: Codec Saturation +:: The state of an underlying codec implementation where the number of active + decoding or encoding requests has reached an implementation specific + maximum such that it is temporarily unable to accept more work. The maximum + may be any value greater than 1, including infinity (no maximum). While + saturated, additional calls to `decode()` or `encode()` will be buffered + in the [=control message queue=], and will increment the respective + `decodeQueuSize` and `encodeQueueSize` attributes. The codec implementation + will become unsaturated after making sufficient progress on the current + workload. + Codec Processing Model {#codec-processing-model-section} =================================================================== @@ -213,68 +186,84 @@ codec tasks can be scheduled while previous tasks are still pending. For example, web authors can call `decode()` without waiting for a previous `decode()` to complete. This is achieved by offloading underlying codec tasks - to a separate thread for parallel execution. + to a separate [=parallel queue=] for parallel execution. This section describes threading behaviors as they are visible from the - perspective of web authors. Implementers can choose to use more or less - threads as long as the exernally visible behaviors of blocking and sequencing - are maintained as follows. + perspective of web authors. Implementers can choose to use more threads, as + long as the externally visible behaviors of blocking and sequencing are + maintained as follows. -Control Thread and Codec Thread {#control-thread-and-codec-thread} ------------------------------------------------------------------- - -All steps in this specification will run on either a [=control thread=] or -a [=codec thread=]. - -The control thread is the thread from which authors will construct -a [=codec=] and invoke its methods. Invoking a codec's methods will typically -result in the creation of [=control messages=] which are later executed on the -[=codec thread=]. Each [=webappapis/global object=] has a separate control -thread. +Control Messages {#control-messages} +------------------------------------ -The codec thread is the thread from which a [=codec=] will -[=dequeue=] [=control messages=] and execute their steps. Each [=codec=] -instance has a separate codec thread. The lifetime of a codec thread matches -that of its associated [=codec=] instance. +A control message defines a sequence of steps corresponding to a +method invocation on a [=codec=] instance (e.g. `encode()`). -The [=control thread=] uses a traditional event loop, as described in -[[!HTML]]. - -The [=codec thread=] uses a specialized [=codec processing loop=]. - -Communication from the [=control thread=] to the [=codec thread=] is done using -[=control message=] passing. Communication in the other direction is done using -regular event loop tasks. - -Each [=codec=] instance has a single control message queue that is -a [=queue=] of control messages. +A control message queue is a [=queue=] of +[=control messages=]. Each [=codec=] instance has a control message queue +stored in an internal slot named +[[control message queue]]. Queuing a control -message means [=enqueuing=] the message to a [=codec=]’s [=control -message queue=]. Invoking codec methods will often queue a control message +message means [=enqueuing=] the message to a [=codec=]’s [=[[control +message queue]]=]. Invoking codec methods will generally queue a control message to schedule work. Running a control message means performing a sequence of steps specified by the method that enqueued the message. -The codec processing loop MUST run these steps: -1. While true: - 1. If the [=control message queue=] is empty, [=continue=]. - 2. Dequeue |front message| from the [=control message queue=]. - 3. Run [=control message steps=] described by |front message|. +The steps of a given control message can block processing later messages in the +control message queue. Each [=codec=] instance has a boolean internal slot named +[[message queue blocked]] that is set to `true` when this occurs. A +blocking message will conclude by setting [=[[message queue blocked]]=] to +`false` and rerunning the [=Process the control message queue=] steps. + +All control messages will return either `"processed"` or `"not processed"`. +Returning `"processed"` indicates the message steps are being (or have been) +executed and the message may be removed from the [=control message queue=]. +`"not processed"` indicates the message must not be processed at this time +and should remain in the [=control message queue=] to be retried later. + +To Process the control message queue, run these steps: +1. While [=[[message queue blocked]]=] is `false` and + [=[[control message queue]]=] is not empty: + 1. Let |front message| be the first message in + [=[[control message queue]]=]. + 2. Let |outcome| be the result of running the [=control message steps=] + described by |front message|. + 3. If |outcome| equals `"not processed"`, break. + 4. Otherwise, dequeue |front message| from the + [=[[control message queue]]=]. + +Codec Work Parallel Queue {#codec-work-parallel-queue} +------------------------------------------------------ + +Each [=codec=] instance has an internal slot named +[[codec work queue]] that is a [=parallel queue=]. + +Each [=codec=] instance has an internal slot named +[[codec implementation]] that refers to the underlying platform +encoder or decoder. Except for assignment, any steps that reference +[=[[codec implementation]]=] will be enqueued to the [=[[codec work queue]]=]. + +Each [=codec=] instance has a unique codec task source. Tasks +[=queue a task|queued=] from the [=[[codec work queue]]=] to the [=/event loop=] +will use the [=codec task source=]. + AudioDecoder Interface {#audiodecoder-interface} ================================================ [Exposed=(Window,DedicatedWorker), SecureContext] -interface AudioDecoder { +interface AudioDecoder : EventTarget { constructor(AudioDecoderInit init); readonly attribute CodecState state; readonly attribute unsigned long decodeQueueSize; + attribute EventHandler ondequeue; undefined configure(AudioDecoderConfig config); undefined decode(EncodedAudioChunk chunk); @@ -295,8 +284,22 @@ Internal Slots {#audiodecoder-internal-slots} --------------------------------------------- +: <dfn attribute for=AudioDecoder>[[control message queue]]</dfn> +:: A [=queue=] of [=control messages=] to be performed upon this [=codec=] + instance. See [=[[control message queue]]=]. +: <dfn attribute for=AudioDecoder>[[message queue blocked]]</dfn> +:: A boolean indicating when processing the + {{AudioDecoder/[[control message queue]]}} is blocked by a pending + [=control message=]. See [=[[message queue blocked]]=]. : <dfn attribute for=AudioDecoder>[[codec implementation]]</dfn> -:: Underlying decoder implementation provided by the User Agent. +:: Underlying decoder implementation provided by the User Agent. See + [=[[codec implementation]]=]. +: <dfn attribute for=AudioDecoder>[[codec work queue]]</dfn> +:: A [=parallel queue=] used for running parallel steps that reference the + {{AudioDecoder/[[codec implementation]]}}. See [=[[codec work queue]]=]. +: <dfn attribute for=AudioDecoder>[[codec saturated]]</dfn> +:: A boolean indicating when the {{AudioDecoder/[[codec implementation]]}} is + unable to accept additional decoding work. : <dfn attribute for=AudioDecoder>[[output callback]]</dfn> :: Callback given at construction for decoded outputs. : <dfn attribute for=AudioDecoder>[[error callback]]</dfn> @@ -312,6 +315,9 @@ underlying codec is ready to accept new input. : <dfn attribute for=AudioDecoder>[[pending flush promises]]</dfn> :: A list of unresolved promises returned by calls to {{AudioDecoder/flush()}}. +: <dfn attribute for=AudioDecoder>[[dequeue event scheduled]]</dfn> +:: A boolean indicating whether a {{AudioDecoder/dequeue}} event is already + scheduled to fire. Used to avoid event spam. Constructors {#audiodecoder-constructors} ----------------------------------------- @@ -319,26 +325,37 @@ AudioDecoder(init) </dfn> 1. Let d be a new {{AudioDecoder}} object. -2. Assign init.output to {{AudioDecoder/[[output callback]]}}. -3. Assign init.error to {{AudioDecoder/[[error callback]]}}. -4. Assign `true` to {{AudioDecoder/[[key chunk required]]}}. -5. Assign `"unconfigured"` to {{AudioDecoder/[[state]]}} -6. Return d. +2. Assign a new [=queue=] to {{AudioDecoder/[[control message queue]]}}. +3. Assign `false` to {{AudioDecoder/[[message queue blocked]]}}. +4. Assign `null` to {{AudioDecoder/[[codec implementation]]}}. +5. Assign the result of starting a new [=parallel queue=] to + {{AudioDecoder/[[codec work queue]]}}. +6. Assign `false` to {{AudioDecoder/[[codec saturated]]}}. +7. Assign init.output to {{AudioDecoder/[[output callback]]}}. +8. Assign init.error to {{AudioDecoder/[[error callback]]}}. +9. Assign `true` to {{AudioDecoder/[[key chunk required]]}}. +10. Assign `"unconfigured"` to {{AudioDecoder/[[state]]}} +11. Assign `0` to {{AudioDecoder/[[decodeQueueSize]]}}. +12. Assign a new [=list=] to {{AudioDecoder/[[pending flush promises]]}}. +13. Assign `false` to {{AudioDecoder/[[dequeue event scheduled]]}}. +13. Return d. Attributes {#audiodecoder-attributes} ------------------------------------- -<dl> - <dt> - <dfn attribute for=AudioDecoder>state</dfn> - </dt> - <dd>Returns the value of {{AudioDecoder/[[state]]}}.</dd> - <dt> - <dfn attribute for=AudioDecoder>decodeQueueSize</dfn> - </dt> - <dd> - Returns the value of {{AudioDecoder/[[decodeQueueSize]]}}. - </dd> -</dl> +: <dfn attribute for=AudioDecoder>state</dfn> +:: Returns the value of {{AudioDecoder/[[state]]}}. +: <dfn attribute for=AudioDecoder>decodeQueueSize</dfn> +:: Returns the value of {{AudioDecoder/[[decodeQueueSize]]}}. +: <dfn attribute for=AudioDecoder>ondequeue</dfn> +:: An [=event handler IDL attribute=] whose [=event handler event type=] is + {{AudioDecoder/dequeue}}. + +Event Summary {#audiodecoder-event-summary} +------------------------------------------- +: <dfn event for=AudioDecoder>dequeue</dfn> +:: Fired at the {{AudioDecoder}} when the {{AudioDecoder/decodeQueueSize}} has + decreased. + Methods {#audiodecoder-methods} ------------------------------- @@ -360,6 +377,7 @@ 3. Set {{AudioDecoder/[[state]]}} to `"configured"`. 4. Set {{AudioDecoder/[[key chunk required]]}} to `true`. 5. [=Queue a control message=] to configure the decoder with |config|. + 6. [=Process the control message queue=]. [=Running a control message=] to configure the decoder means running these steps: @@ -369,7 +387,13 @@ {{AudioDecoder/[[codec implementation]]}} with an implementation supporting |config|. 3. Otherwise, run the <a>Close AudioDecoder</a> algorithm with - {{NotSupportedError}}. + {{NotSupportedError}} and return `"processed"`. + 4. Assign `true` to {{AudioDecoder/[[message queue blocked]]}}. + 5. Enqueue the following steps to {{AudioDecoder/[[codec work queue]]}}: + 1. Configure {{AudioDecoder/[[codec implementation]]}} with |config|. + 2. Assign `false` to {{AudioDecoder/[[message queue blocked]]}}. + 3. [=Queue a task=] to [=Process the control message queue=]. + 6. Return `"processed"`. </dd> <dt><dfn method for=AudioDecoder>decode(chunk)</dfn></dt> @@ -390,21 +414,32 @@ {{AudioDecoder/[[key chunk required]]}}. 3. Increment {{AudioDecoder/[[decodeQueueSize]]}}. 4. [=Queue a control message=] to decode the |chunk|. + 5. [=Process the control message queue=]. [=Running a control message=] to decode the chunk means performing these steps: - 1. Attempt to use {{AudioDecoder/[[codec implementation]]}} to decode the - chunk. - 2. If decoding results in an error, queue a task on the [=control thread=] - event loop to run the [=Close AudioDecoder=] algorithm with - {{EncodingError}}. - 3. Queue a task on the [=control thread=] event loop to decrement - {{AudioDecoder/[[decodeQueueSize]]}}. - 4. Let |decoded outputs| be a [=list=] of decoded audio data outputs emitted - by {{AudioDecoder/[[codec implementation]]}}. - 5. If |decoded outputs| is not empty, queue a task on the [=control thread=] - event loop to run the [=Output AudioData=] algorithm with - |decoded outputs|. + 1. If {{AudioDecoder/[[codec saturated]]}} equals `true`, return `"not + processed"`. + 2. If decoding chunk will cause the + {{AudioDecoder/[[codec implementation]]}} to become [=saturated=], + assign `true` to {{AudioDecoder/[[codec saturated]]}}. + 3. Decrement {{AudioDecoder/[[decodeQueueSize]]}} and run the + [=AudioDecoder/Schedule Dequeue Event=] algorithm. + 4. Enqueue the following steps to the {{AudioDecoder/[[codec work queue]]}}: + 1. Attempt to use {{AudioDecoder/[[codec implementation]]}} to decode + the chunk. + 2. If decoding results in an error, [=queue a task=] to run the + [=Close AudioDecoder=] algorithm with {{EncodingError}} and return. + 3. If {{AudioDecoder/[[codec saturated]]}} equals `true` and + {{AudioDecoder/[[codec implementation]]}} is no longer + [=saturated=], [=queue a task=] to perform the following steps: + 1. Assign `false` to {{AudioDecoder/[[codec saturated]]}}. + 2. [=Process the control message queue=]. + 4. Let |decoded outputs| be a [=list=] of decoded audio data outputs + emitted by {{AudioDecoder/[[codec implementation]]}}. + 5. If |decoded outputs| is not empty, [=queue a task=] to run the + [=Output AudioData=] algorithm with |decoded outputs|. + 5. Return `"processed"`. </dd> <dt><dfn method for=AudioDecoder>flush()</dfn></dt> @@ -417,22 +452,24 @@ [=a promise rejected with=] {{InvalidStateError}} {{DOMException}}. 2. Set {{AudioDecoder/[[key chunk required]]}} to `true`. 3. Let |promise| be a new Promise. - 4. [=Queue a control message=] to flush the codec with |promise|. - 5. Append |promise| to {{AudioDecoder/[[pending flush promises]]}}. - 6. Return |promise|. + 4. Append |promise| to {{AudioDecoder/[[pending flush promises]]}}. + 5. [=Queue a control message=] to flush the codec with |promise|. + 6. [=Process the control message queue=]. + 7. Return |promise|. - [=Running a control message=] to flush the codec means performing these steps - with |promise|. - 1. Signal {{AudioDecoder/[[codec implementation]]}} to emit all [=internal - pending outputs=]. - 2. Let |decoded outputs| be a [=list=] of decoded audio data outputs emitted - by {{AudioDecoder/[[codec implementation]]}}. - 3. If |decoded outputs| is not empty, queue a task on the [=control thread=] - event loop to run the [=Output AudioData=] algorithm with - |decoded outputs|. - 4. Queue a task on the [=control thread=] event loop to run these steps: - 1. Remove |promise| from {{AudioDecoder/[[pending flush promises]]}}. - 2. Resolve |promise|. + [=Running a control message=] to flush the codec means performing these + steps with |promise|. + 1. Enqueue the following steps to the {{AudioDecoder/[[codec work queue]]}}: + 1. Signal {{AudioDecoder/[[codec implementation]]}} to emit all + [=internal pending outputs=]. + 2. Let |decoded outputs| be a [=list=] of decoded audio data outputs + emitted by {{AudioDecoder/[[codec implementation]]}}. + 3. [=Queue a task=] to perform these steps: + 1. If |decoded outputs| is not empty, run the [=Output AudioData=] + algorithm with |decoded outputs|. + 2. Remove |promise| from + {{AudioDecoder/[[pending flush promises]]}}. + 3. Resolve |promise|. </dd> <dt><dfn method for=AudioDecoder>reset()</dfn></dt> @@ -486,6 +523,14 @@ Algorithms {#audiodecoder-algorithms} ------------------------------------- <dl> + <dt><dfn for=AudioDecoder>Schedule Dequeue Event</dfn> + <dd> + 1. If {{AudioDecoder/[[dequeue event scheduled]]}} equals `true`, return. + 2. Assign `true` to {{AudioDecoder/[[dequeue event scheduled]]}}. + 3. [=Queue a task=] to run the following steps: + 1. Fire a simple event named {{AudioDecoder/dequeue}} at [=this=]. + 2. Assign `false` to {{AudioDecoder/[[dequeue event scheduled]]}}. + </dd> <dt><dfn>Output AudioData</dfn> (with |outputs|)</dt> <dd> Run these steps: @@ -514,8 +559,11 @@ 2. Set {{AudioDecoder/[[state]]}} to `"unconfigured"`. 3. Signal {{AudioDecoder/[[codec implementation]]}} to cease producing output for the previous configuration. - 4. Remove all [=control messages=] from the [=control message queue=]. - 5. Set {{AudioDecoder/[[decodeQueueSize]]}} to zero. + 4. Remove all [=control messages=] from the + {{AudioDecoder/[[control message queue]]}}. + 5. If {{AudioDecoder/[[decodeQueueSize]]}} is greater than zero: + 1. Set {{AudioDecoder/[[decodeQueueSize]]}} to zero. + 2. Run the [=AudioDecoder/Schedule Dequeue Event=] algorithm. 6. For each |promise| in {{AudioDecoder/[[pending flush promises]]}}: 1. Reject |promise| with |exception|. 2. Remove |promise| from {{AudioDecoder/[[pending flush promises]]}}. @@ -527,8 +575,8 @@ 2. Set {{AudioDecoder/[[state]]}} to `"closed"`. 3. Clear {{AudioDecoder/[[codec implementation]]}} and release associated [=system resources=]. - 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on - the [=control thread=] event loop to invoke the {{AudioDecoder/[[error callback]]}} with |exception|. + 4. If |exception| is not an {{AbortError}} {{DOMException}}, + [=queue a task=] to invoke the {{AudioDecoder/[[error callback]]}} with |exception|. </dd> </dl> @@ -537,11 +585,12 @@ <xmp class='idl'> [Exposed=(Window,DedicatedWorker), SecureContext] -interface VideoDecoder { +interface VideoDecoder : EventTarget { constructor(VideoDecoderInit init); readonly attribute CodecState state; readonly attribute unsigned long decodeQueueSize; + attribute EventHandler ondequeue; undefined configure(VideoDecoderConfig config); undefined decode(EncodedVideoChunk chunk); @@ -562,8 +611,22 @@ Internal Slots {#videodecoder-internal-slots} --------------------------------------------- +: <dfn attribute for=VideoDecoder>[[control message queue]]</dfn> +:: A [=queue=] of [=control messages=] to be performed upon this [=codec=] + instance. See [=[[control message queue]]=]. +: <dfn attribute for=VideoDecoder>[[message queue blocked]]</dfn> +:: A boolean indicating when processing the + {{VideoDecoder/[[control message queue]]}} is blocked by a pending + [=control message=]. See [=[[message queue blocked]]=]. : <dfn attribute for=VideoDecoder>[[codec implementation]]</dfn> -:: Underlying decoder implementation provided by the User Agent. +:: Underlying decoder implementation provided by the User Agent. See + [=[[codec implementation]]=]. +: <dfn attribute for=VideoDecoder>[[codec work queue]]</dfn> +:: A [=parallel queue=] used for running parallel steps that reference the + {{VideoDecoder/[[codec implementation]]}}. See [=[[codec work queue]]=]. +: <dfn attribute for=VideoDecoder>[[codec saturated]]</dfn> +:: A boolean indicating when the {{VideoDecoder/[[codec implementation]]}} is + unable to accept additional decoding work. : <dfn attribute for=VideoDecoder>[[output callback]]</dfn> :: Callback given at construction for decoded outputs. : <dfn attribute for=VideoDecoder>[[error callback]]</dfn> @@ -581,6 +644,9 @@ underlying codec is ready to accept new input. : <dfn attribute for=VideoDecoder>[[pending flush promises]]</dfn> :: A list of unresolved promises returned by calls to {{VideoDecoder/flush()}}. +: <dfn attribute for=VideoDecoder>[[dequeue event scheduled]]</dfn> +:: A boolean indicating whether a {{VideoDecoder/dequeue}} event is already + scheduled to fire. Used to avoid event spam. Constructors {#videodecoder-constructors} @@ -588,29 +654,38 @@ <dfn constructor for=VideoDecoder title="VideoDecoder(init)"> VideoDecoder(init) </dfn> -1. Let d be a new VideoDecoder object. -2. Assign `init.output` to the {{VideoDecoder/[[output callback]]}} internal slot. -3. Assign `init.error` to the {{VideoDecoder/[[error callback]]}} internal slot. -4. Assign `true` to {{VideoDecoder/[[key chunk required]]}}. -5. Assign `"unconfigured"` to {{VideoDecoder/[[state]]}}. -5. Return d. +1. Let d be a new {{VideoDecoder}} object. +2. Assign a new [=queue=] to {{VideoDecoder/[[control message queue]]}}. +3. Assign `false` to {{VideoDecoder/[[message queue blocked]]}}. +4. Assign `null` to {{VideoDecoder/[[codec implementation]]}}. +5. Assign the result of starting a new [=parallel queue=] to + {{VideoDecoder/[[codec work queue]]}}. +6. Assign `false` to {{VideoDecoder/[[codec saturated]]}}. +7. Assign init.output to {{VideoDecoder/[[output callback]]}}. +8. Assign init.error to {{VideoDecoder/[[error callback]]}}. +9. Assign `null` to {{VideoDecoder/[[active decoder config]]}}. +10. Assign `true` to {{VideoDecoder/[[key chunk required]]}}. +11. Assign `"unconfigured"` to {{VideoDecoder/[[state]]}} +12. Assign `0` to {{VideoDecoder/[[decodeQueueSize]]}}. +13. Assign a new [=list=] to {{VideoDecoder/[[pending flush promises]]}}. +14. Assign `false` to {{VideoDecoder/[[dequeue event scheduled]]}}. +15. Return d. Attributes {#videodecoder-attributes} ------------------------------------- -<dl> - <dt> - <dfn attribute for=VideoDecoder>state</dfn> - </dt> - <dd> - Returns the value of {{VideoDecoder/[[state]]}}. - </dd> - <dt> - <dfn attribute for=VideoDecoder>decodeQueueSize</dfn> - </dt> - <dd> - Returns the value of {{VideoDecoder/[[decodeQueueSize]]}}. - </dd> -</dl> +: <dfn attribute for=VideoDecoder>state</dfn> +:: Returns the value of {{VideoDecoder/[[state]]}}. +: <dfn attribute for=VideoDecoder>decodeQueueSize</dfn> +:: Returns the value of {{VideoDecoder/[[decodeQueueSize]]}}. +: <dfn attribute for=VideoDecoder>ondequeue</dfn> +:: An [=event handler IDL attribute=] whose [=event handler event type=] is + {{VideoDecoder/dequeue}}. + +Event Summary {#videodecoder-event-summary} +------------------------------------------- +: <dfn event for=VideoDecoder>dequeue</dfn> +:: Fired at the {{VideoDecoder}} when the {{VideoDecoder/decodeQueueSize}} has + decreased. Methods {#videodecoder-methods} ------------------------------- @@ -621,17 +696,19 @@ chunks as described by |config|. NOTE: This method will trigger a {{NotSupportedError}} if the User Agent - does not support |config|. Authors are encouraged to first check support by - calling {{VideoDecoder/isConfigSupported()}} with |config|. User Agents + does not support |config|. Authors are encouraged to first check support + by calling {{VideoDecoder/isConfigSupported()}} with |config|. User Agents don't have to support any particular codec type or configuration. When invoked, run these steps: 1. If |config| is not a [=valid VideoDecoderConfig=], throw a {{TypeError}}. - 2. If {{VideoDecoder/[[state]]}} is `“closed”`, throw an {{InvalidStateError}}. + 2. If {{VideoDecoder/[[state]]}} is `“closed”`, throw an + {{InvalidStateError}}. 3. Set {{VideoDecoder/[[state]]}} to `"configured"`. 4. Set {{VideoDecoder/[[key chunk required]]}} to `true`. 5. [=Queue a control message=] to configure the decoder with |config|. + 6. [=Process the control message queue=]. [=Running a control message=] to configure the decoder means running these steps: @@ -641,8 +718,14 @@ {{VideoDecoder/[[codec implementation]]}} with an implementation supporting |config|. 3. Otherwise, run the <a>Close VideoDecoder</a> algorithm with - {{NotSupportedError}} and abort these steps. - 4. Set {{VideoDecoder/[[active decoder config]]}} to `config`. + {{NotSupportedError}} and return `"processed"`. + 4. Assign `true` to {{VideoDecoder/[[message queue blocked]]}}. + 5. Enqueue the following steps to {{VideoDecoder/[[codec work queue]]}}: + 1. Configure {{VideoDecoder/[[codec implementation]]}} with |config|. + 2. Set {{VideoDecoder/[[active decoder config]]}} to `config`. + 3. Assign `false` to {{VideoDecoder/[[message queue blocked]]}}. + 4. [=Queue a task=] to [=Process the control message queue=]. + 6. Return `"processed"`. </dd> <dt><dfn method for=VideoDecoder>decode(chunk)</dfn></dt> @@ -657,7 +740,7 @@ NOTE: {{VideoDecoder}} requires that frames are output in the order they expect to be presented, commonly known as presentation order. When using - some {{VideoDecoder/[[codec implementation]]}}s the User Agent will have to + some {{VideoDecoder/[[codec implementation]]}}s the User Agent will have to reorder outputs into presentation order. When invoked, run these steps: @@ -674,20 +757,32 @@ {{VideoDecoder/[[key chunk required]]}}. 3. Increment {{VideoDecoder/[[decodeQueueSize]]}}. 4. [=Queue a control message=] to decode the |chunk|. + 5. [=Process the control message queue=]. [=Running a control message=] to decode the chunk means performing these steps: - 1. Attempt to use {{VideoDecoder/[[codec implementation]]}} to decode the - chunk. - 2. If decoding results in an error, queue a task on the [=control thread=] - event loop to run the [=Close VideoDecoder=] algorithm with - {{EncodingError}}. - 3. Queue a task on the [=control thread=] event loop to decrement - {{VideoDecoder/[[decodeQueueSize]]}} - 4. Let |decoded outputs| be a [=list=] of decoded video data outputs emitted - by {{VideoDecoder/[[codec implementation]]}} in presentation order. - 5. If |decoded outputs| is not empty, queue a task on the [=control thread=] - event loop to run the [=Output VideoFrames=] algorithm with - |decoded outputs|. + 1. If {{VideoDecoder/[[codec saturated]]}} equals `true`, return `"not + processed"`. + 2. If decoding chunk will cause the + {{VideoDecoder/[[codec implementation]]}} to become [=saturated=], + assign `true` to {{VideoDecoder/[[codec saturated]]}}. + 3. Decrement {{VideoDecoder/[[decodeQueueSize]]}} and run the + [=VideoDecoder/Schedule Dequeue Event=] algorithm. + 4. Enqueue the following steps to the {{VideoDecoder/[[codec work queue]]}}: + 1. Attempt to use {{VideoDecoder/[[codec implementation]]}} to decode + the chunk. + 2. If decoding results in an error, [=queue a task=] to run the + [=Close VideoDecoder=] algorithm with {{EncodingError}} and return. + 3. If {{VideoDecoder/[[codec saturated]]}} equals `true` and + {{VideoDecoder/[[codec implementation]]}} is no longer + [=saturated=], [=queue a task=] to perform the following steps: + 1. Assign `false` to {{VideoDecoder/[[codec saturated]]}}. + 2. [=Process the control message queue=]. + 4. Let |decoded outputs| be a [=list=] of decoded video data outputs + emitted by {{VideoDecoder/[[codec implementation]]}} in + presentation order. + 5. If |decoded outputs| is not empty, [=queue a task=] to run the + [=Output VideoFrame=] algorithm with |decoded outputs|. + 5. Return `"processed"`. </dd> <dt><dfn method for=VideoDecoder>flush()</dfn></dt> @@ -700,22 +795,24 @@ [=a promise rejected with=] {{InvalidStateError}} {{DOMException}}. 2. Set {{VideoDecoder/[[key chunk required]]}} to `true`. 3. Let |promise| be a new Promise. - 4. [=Queue a control message=] to flush the codec with |promise|. - 5. Append |promise| to {{VideoDecoder/[[pending flush promises]]}}. - 6. Return |promise|. + 4. Append |promise| to {{VideoDecoder/[[pending flush promises]]}}. + 5. [=Queue a control message=] to flush the codec with |promise|. + 6. [=Process the control message queue=]. + 7. Return |promise|. - [=Running a control message=] to flush the codec means performing these steps - with |promise|. - 1. Signal {{VideoDecoder/[[codec implementation]]}} to emit all [=internal - pending outputs=]. - 2. Let |decoded outputs| be a [=list=] of decoded video data outputs emitted - by {{VideoDecoder/[[codec implementation]]}}. - 3. If |decoded outputs| is not empty, queue a task on the [=control thread=] - event loop to run the [=Output VideoFrames=] algorithm with - |decoded outputs|. - 4. Queue a task on the [=control thread=] event loop to run these steps: - 1. Remove |promise| from {{VideoDecoder/[[pending flush promises]]}}. - 2. Resolve |promise|. + [=Running a control message=] to flush the codec means performing these + steps with |promise|. + 1. Enqueue the following steps to the {{VideoDecoder/[[codec work queue]]}}: + 1. Signal {{VideoDecoder/[[codec implementation]]}} to emit all + [=internal pending outputs=]. + 2. Let |decoded outputs| be a [=list=] of decoded video data outputs + emitted by {{VideoDecoder/[[codec implementation]]}}. + 3. [=Queue a task=] to perform these steps: + 1. If |decoded outputs| is not empty, run the [=Output VideoFrame=] + algorithm with |decoded outputs|. + 2. Remove |promise| from + {{VideoDecoder/[[pending flush promises]]}}. + 3. Resolve |promise|. </dd> <dt><dfn method for=VideoDecoder>reset()</dfn></dt> @@ -769,6 +866,14 @@ Algorithms {#videodecoder-algorithms} ------------------------------------- <dl> + <dt><dfn for=VideoDecoder>Schedule Dequeue Event</dfn> + <dd> + 1. If {{VideoDecoder/[[dequeue event scheduled]]}} equals `true`, return. + 2. Assign `true` to {{VideoDecoder/[[dequeue event scheduled]]}}. + 3. [=Queue a task=] to run the following steps: + 1. Fire a simple event named {{VideoDecoder/dequeue}} at [=this=]. + 2. Assign `false` to {{VideoDecoder/[[dequeue event scheduled]]}}. + </dd> <dt><dfn>Output VideoFrames</dfn> (with |outputs|)</dt> <dd> Run these steps: @@ -807,8 +912,11 @@ 2. Set {{VideoDecoder/state}} to `"unconfigured"`. 3. Signal {{VideoDecoder/[[codec implementation]]}} to cease producing output for the previous configuration. - 4. Remove all [=control messages=] from the [=control message queue=]. - 5. Set {{VideoDecoder/[[decodeQueueSize]]}} to zero. + 4. Remove all [=control messages=] from the + {{VideoDecoder/[[control message queue]]}}. + 5. If {{VideoDecoder/[[decodeQueueSize]]}} is greater than zero: + 1. Set {{VideoDecoder/[[decodeQueueSize]]}} to zero. + 2. Run the [=VideoDecoder/Schedule Dequeue Event=] algorithm. 6. For each |promise| in {{VideoDecoder/[[pending flush promises]]}}: 1. Reject |promise| with |exception|. 2. Remove |promise| from {{VideoDecoder/[[pending flush promises]]}}. @@ -820,9 +928,8 @@ 2. Set {{VideoDecoder/state}} to `"closed"`. 3. Clear {{VideoDecoder/[[codec implementation]]}} and release associated [=system resources=]. - 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on - the [=control thread=] event loop to invoke the - {{VideoDecoder/[[error callback]]}} with |exception|. + 4. If |exception| is not an {{AbortError}} {{DOMException}}, + [=queue a task=] to invoke the {{VideoDecoder/[[error callback]]}} with |exception|. </dd> </dl> @@ -832,11 +939,12 @@ <xmp class='idl'> [Exposed=(Window,DedicatedWorker), SecureContext] -interface AudioEncoder { +interface AudioEncoder : EventTarget { constructor(AudioEncoderInit init); readonly attribute CodecState state; readonly attribute unsigned long encodeQueueSize; + attribute EventHandler ondequeue; undefined configure(AudioEncoderConfig config); undefined encode(AudioData data); @@ -859,62 +967,79 @@ Internal Slots {#audioencoder-internal-slots} --------------------------------------------- -<dl> -<dt><dfn attribute for=AudioEncoder>[[codec implementation]]</dfn></dt> -<dd>Underlying encoder implementation provided by the User Agent.</dd> -<dt><dfn attribute for=AudioEncoder>[[output callback]]</dfn></dt> -<dd>Callback given at construction for encoded outputs.</dd> -<dt><dfn attribute for=AudioEncoder>[[error callback]]</dfn></dt> -<dd>Callback given at construction for encode errors.</dd> -<dt><dfn attribute for=AudioEncoder>[[active encoder config]]</dfn></dt> -<dd>The {{AudioEncoderConfig}} that is actively applied.</dd> -<dt><dfn attribute for=AudioEncoder>[[active output config]]</dfn></dt> -<dd> - The {{AudioDecoderConfig}} that describes how to decode the most recently - emitted {{EncodedAudioChunk}}. -</dd> -<dt><dfn attribute for=AudioEncoder>\[[state]]</dfn></dt> -<dd> - The current {{CodecState}} of this {{AudioEncoder}}. -</dd> -<dt><dfn attribute for=AudioEncoder>\[[encodeQueueSize]]</dfn></dt> -<dd> - The number of pending encode requests. This number will decrease as the - underlying codec is ready to accept new input. -</dd> -<dt><dfn attribute for=AudioEncoder>[[pending flush promises]]</dfn></dt> -<dd> - A list of unresolved promises returned by calls to {{AudioEncoder/flush()}}. -</dd> -</dl> +: <dfn attribute for=AudioEncoder>[[control message queue]]</dfn> +:: A [=queue=] of [=control messages=] to be performed upon this [=codec=] + instance. See [=[[control message queue]]=]. +: <dfn attribute for=AudioEncoder>[[message queue blocked]]</dfn> +:: A boolean indicating when processing the + {{AudioEncoder/[[control message queue]]}} is blocked by a pending + [=control message=]. See [=[[message queue blocked]]=]. +: <dfn attribute for=AudioEncoder>[[codec implementation]]</dfn> +:: Underlying encoder implementation provided by the User Agent. See + [=[[codec implementation]]=]. +: <dfn attribute for=AudioEncoder>[[codec work queue]]</dfn> +:: A [=parallel queue=] used for running parallel steps that reference the + {{AudioEncoder/[[codec implementation]]}}. See [=[[codec work queue]]=]. +: <dfn attribute for=AudioEncoder>[[codec saturated]]</dfn> +:: A boolean indicating when the {{AudioEncoder/[[codec implementation]]}} is + unable to accept additional encoding work. +: <dfn attribute for=AudioEncoder>[[output callback]]</dfn> +:: Callback given at construction for encoded outputs. +: <dfn attribute for=AudioEncoder>[[error callback]]</dfn> +:: Callback given at construction for encode errors. +: <dfn attribute for=AudioEncoder>[[active encoder config]]</dfn> +:: The {{AudioEncoderConfig}} that is actively applied. +: <dfn attribute for=AudioEncoder>[[active output config]]</dfn> +:: The {{AudioDecoderConfig}} that describes how to decode the most recently + emitted {{EncodedAudioChunk}}. +: <dfn attribute for=AudioEncoder>\[[state]]</dfn> +:: The current {{CodecState}} of this {{AudioEncoder}}. +: <dfn attribute for=AudioEncoder>\[[encodeQueueSize]]</dfn> +:: The number of pending encode requests. This number will decrease as the + underlying codec is ready to accept new input. +: <dfn attribute for=AudioEncoder>[[pending flush promises]]</dfn> +:: A list of unresolved promises returned by calls to {{AudioEncoder/flush()}}. +: <dfn attribute for=AudioEncoder>[[dequeue event scheduled]]</dfn> +:: A boolean indicating whether a {{AudioEncoder/dequeue}} event is already + scheduled to fire. Used to avoid event spam. Constructors {#audioencoder-constructors} ----------------------------------------- <dfn constructor for=AudioEncoder title="AudioEncoder(init)"> AudioEncoder(init) </dfn> -1. Let e be a new AudioEncoder object. -2. Assign `init.output` to the {{AudioEncoder/[[output callback]]}} internal slot. -3. Assign `init.error` to the {{AudioEncoder/[[error callback]]}} internal slot. -4. Assign `"unconfigured"` to {{AudioEncoder/[[state]]}}. -5. Assign `null` to {{AudioEncoder/[[active encoder config]]}}. -6. Assign `null` to {{AudioEncoder/[[active output config]]}}. -7. Return e. +1. Let e be a new {{AudioEncoder}} object. +2. Assign a new [=queue=] to {{AudioEncoder/[[control message queue]]}}. +3. Assign `false` to {{AudioEncoder/[[message queue blocked]]}}. +4. Assign `null` to {{AudioEncoder/[[codec implementation]]}}. +5. Assign the result of starting a new [=parallel queue=] to + {{AudioEncoder/[[codec work queue]]}}. +6. Assign `false` to {{AudioEncoder/[[codec saturated]]}}. +7. Assign init.output to {{AudioEncoder/[[output callback]]}}. +8. Assign init.error to {{AudioEncoder/[[error callback]]}}. +9. Assign `null` to {{AudioEncoder/[[active encoder config]]}}. +10. Assign `null` to {{AudioEncoder/[[active output config]]}}. +11. Assign `"unconfigured"` to {{AudioEncoder/[[state]]}} +12. Assign `0` to {{AudioEncoder/[[encodeQueueSize]]}}. +13. Assign a new [=list=] to {{AudioEncoder/[[pending flush promises]]}}. +14. Assign `false` to {{AudioEncoder/[[dequeue event scheduled]]}}. +15. Return e. Attributes {#audioencoder-attributes} ------------------------------------- -<dl> - <dt> - <dfn attribute for=AudioEncoder>state</dfn> - </dt> - <dd>Returns the value of {{AudioEncoder/[[state]]}}.</dd> - <dt> - <dfn attribute for=AudioEncoder>encodeQueueSize</dfn> - </dt> - <dd> - Returns the value of {{AudioEncoder/[[encodeQueueSize]]}}. - </dd> -</dl> +: <dfn attribute for=AudioEncoder>state</dfn> +:: Returns the value of {{AudioEncoder/[[state]]}}. +: <dfn attribute for=AudioEncoder>encodeQueueSize</dfn> +:: Returns the value of {{AudioEncoder/[[encodeQueueSize]]}}. +: <dfn attribute for=AudioEncoder>ondequeue</dfn> +:: An [=event handler IDL attribute=] whose [=event handler event type=] is + {{AudioEncoder/dequeue}}. + +Event Summary {#audioencoder-event-summary} +------------------------------------------- +: <dfn event for=AudioEncoder>dequeue</dfn> +:: Fired at the {{AudioEncoder}} when the {{AudioEncoder/encodeQueueSize}} has + decreased. Methods {#audioencoder-methods} ------------------------------- @@ -932,20 +1057,28 @@ When invoked, run these steps: 1. If |config| is not a [=valid AudioEncoderConfig=], throw a {{TypeError}}. - 2. If {{AudioEncoder/[[state]]}} is `"closed"`, throw an {{InvalidStateError}}. + 2. If {{AudioEncoder/[[state]]}} is `"closed"`, throw an + {{InvalidStateError}}. 3. Set {{AudioEncoder/[[state]]}} to `"configured"`. 4. [=Queue a control message=] to configure the encoder using |config|. + 5. [=Process the control message queue=]. - [=Running a control message=] to configure the encoder means performing these - steps: + [=Running a control message=] to configure the encoder means performing + these steps: 1. Let |supported| be the result of running the <a>Check Configuration Support</a> algorithm with |config|. 2. If |supported| is `true`, assign {{AudioEncoder/[[codec implementation]]}} with an implementation supporting |config|. 3. Otherwise, run the <a>Close AudioEncoder</a> algorithm with - {{NotSupportedError}} and abort these steps. - 4. Assign |config| to {{AudioEncoder/[[active encoder config]]}} + {{NotSupportedError}} and return `"processed"`. + 4. Assign `true` to {{AudioEncoder/[[message queue blocked]]}}. + 5. Enqueue the following steps to {{AudioEncoder/[[codec work queue]]}}: + 1. Configure {{AudioEncoder/[[codec implementation]]}} with |config|. + 2. Set {{AudioEncoder/[[active encoder config]]}} to `config`. + 3. Assign `false` to {{AudioEncoder/[[message queue blocked]]}}. + 4. [=Queue a task=] to [=Process the control message queue=]. + 6. Return `"processed"`. </dd> <dt><dfn method for=AudioEncoder>encode(data)</dfn></dt> @@ -953,27 +1086,40 @@ [=Enqueues a control message=] to encode the given |data|. When invoked, run these steps: - 1. If the value of |data|'s {{platform object/[[Detached]]}} internal slot is - `true`, throw a {{TypeError}}. + 1. If the value of |data|'s {{platform object/[[Detached]]}} internal slot + is `true`, throw a {{TypeError}}. 2. If {{AudioEncoder/[[state]]}} is not `"configured"`, throw an {{InvalidStateError}}. 3. Let |dataClone| hold the result of running the [=Clone AudioData=] algorithm with |data|. 4. Increment {{AudioEncoder/[[encodeQueueSize]]}}. 5. [=Queue a control message=] to encode |dataClone|. + 6. [=Process the control message queue=]. - [=Running a control message=] to encode the data means performing these steps. - 1. Attempt to use {{AudioEncoder/[[codec implementation]]}} to encode - the [=media resource=] described by |dataClone|. - 2. If encoding results in an error, queue a task on the [=control thread=] - event loop to run the [=Close AudioEncoder=] algorithm with - {{EncodingError}}. - 3. Queue a task on the [=control thread=] event loop to decrement - {{AudioEncoder/[[encodeQueueSize]]}}. - 4. Let |encoded outputs| be a [=list=] of encoded audio data outputs - emitted by {{AudioEncoder/[[codec implementation]]}}. - 5. If |encoded outputs| is not empty, queue a task on the - [=control thread=] event loop to run the [=Output EncodedAudioChunks=] algorithm with |encoded outputs|. + [=Running a control message=] to encode the data means performing these + steps: + 1. If {{AudioEncoder/[[codec saturated]]}} equals `true`, return `"not + processed"`. + 2. If encoding |data| will cause the + {{AudioEncoder/[[codec implementation]]}} to become [=saturated=], + assign `true` to {{AudioEncoder/[[codec saturated]]}}. + 3. Decrement {{AudioEncoder/[[encodeQueueSize]]}} and run the + [=AudioEncoder/Schedule Dequeue Event=] algorithm. + 4. Enqueue the following steps to the {{AudioEncoder/[[codec work queue]]}}: + 1. Attempt to use {{AudioEncoder/[[codec implementation]]}} to encode + the [=media resource=] described by |dataClone|. + 2. If encoding results in an error, [=queue a task=] to run the + [=Close AudioEncoder=] algorithm with {{EncodingError}} and return. + 3. If {{AudioEncoder/[[codec saturated]]}} equals `true` and + {{AudioEncoder/[[codec implementation]]}} is no longer + [=saturated=], [=queue a task=] to perform the following steps: + 1. Assign `false` to {{AudioEncoder/[[codec saturated]]}}. + 2. [=Process the control message queue=]. + 4. Let |encoded outputs| be a [=list=] of encoded audio data outputs + emitted by {{AudioEncoder/[[codec implementation]]}}. + 5. If |encoded outputs| is not empty, [=queue a task=] to run the + [=Output EncodedAudioChunks=] algorithm with |encoded outputs|. + 5. Return `"processed"`. </dd> <dt><dfn method for=AudioEncoder>flush()</dfn></dt> @@ -985,22 +1131,24 @@ 1. If {{AudioEncoder/[[state]]}} is not `"configured"`, return [=a promise rejected with=] {{InvalidStateError}} {{DOMException}}. 2. Let |promise| be a new Promise. - 3. [=Queue a control message=] to flush the codec with |promise|. - 4. Append |promise| to {{AudioEncoder/[[pending flush promises]]}}. - 5. Return |promise|. - - [=Running a control message=] to flush the codec means performing these steps - with |promise|. - 1. Signal {{AudioEncoder/[[codec implementation]]}} to emit all [=internal - pending outputs=]. - 2. Let |encoded outputs| be a [=list=] of encoded audio data outputs - emitted by {{AudioEncoder/[[codec implementation]]}}. - 3. If |encoded outputs| is not empty, queue a task on the [=control thread=] - event loop to run the [=Output EncodedAudioChunks=] algorithm with - |encoded outputs|. - 4. Queue a task on the [=control thread=] event loop to run these steps: - 1. Remove |promise| from {{AudioEncoder/[[pending flush promises]]}}. - 2. Resolve |promise|. + 3. Append |promise| to {{AudioEncoder/[[pending flush promises]]}}. + 4. [=Queue a control message=] to flush the codec with |promise|. + 5. [=Process the control message queue=]. + 6. Return |promise|. + + [=Running a control message=] to flush the codec means performing these + steps with |promise|. + 1. Enqueue the following steps to the {{AudioEncoder/[[codec work queue]]}}: + 1. Signal {{AudioEncoder/[[codec implementation]]}} to emit all + [=internal pending outputs=]. + 2. Let |encoded outputs| be a [=list=] of encoded audio data outputs + emitted by {{AudioEncoder/[[codec implementation]]}}. + 3. [=Queue a task=] to perform these steps: + 1. If |encoded outputs| is not empty, run the + [=Output EncodedAudioChunks=] algorithm with |encoded outputs|. + 2. Remove |promise| from + {{AudioEncoder/[[pending flush promises]]}}. + 3. Resolve |promise|. </dd> <dt><dfn method for=AudioEncoder>reset()</dfn></dt> @@ -1054,6 +1202,14 @@ Algorithms {#audioencoder-algorithms} ------------------------------------- <dl> + <dt><dfn for=AudioEncoder>Schedule Dequeue Event</dfn> + <dd> + 1. If {{AudioEncoder/[[dequeue event scheduled]]}} equals `true`, return. + 2. Assign `true` to {{AudioEncoder/[[dequeue event scheduled]]}}. + 3. [=Queue a task=] to run the following steps: + 1. Fire a simple event named {{AudioEncoder/dequeue}} at [=this=]. + 2. Assign `false` to {{AudioEncoder/[[dequeue event scheduled]]}}. + </dd> <dt><dfn>Output EncodedAudioChunks</dfn> (with |outputs|)</dt> <dd> Run these steps: @@ -1112,8 +1268,11 @@ 4. Set {{AudioEncoder/[[active output config]]}} to `null`. 5. Signal {{AudioEncoder/[[codec implementation]]}} to cease producing output for the previous configuration. - 6. Remove all [=control messages=] from the [=control message queue=]. - 7. Set {{AudioEncoder/[[encodeQueueSize]]}} to zero. + 6. Remove all [=control messages=] from the + {{AudioEncoder/[[control message queue]]}}. + 7. If {{AudioEncoder/[[encodeQueueSize]]}} is greater than zero: + 1. Set {{AudioEncoder/[[encodeQueueSize]]}} to zero. + 2. Run the [=AudioEncoder/Schedule Dequeue Event=] algorithm. 8. For each |promise| in {{AudioEncoder/[[pending flush promises]]}}: 1. Reject |promise| with |exception|. 2. Remove |promise| from {{AudioEncoder/[[pending flush promises]]}}. @@ -1125,9 +1284,9 @@ 2. Set {{AudioEncoder/[[state]]}} to `"closed"`. 3. Clear {{AudioEncoder/[[codec implementation]]}} and release associated [=system resources=]. - 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on - the [=control thread=] event loop to invoke the - {{AudioDecoder/[[error callback]]}} with |exception|. + 4. If |exception| is not an {{AbortError}} {{DOMException}}, + [=queue a task=] to invoke the + {{AudioEncoder/[[error callback]]}} with |exception|. </dd> </dl> @@ -1153,11 +1312,12 @@ <xmp class='idl'> [Exposed=(Window,DedicatedWorker), SecureContext] -interface VideoEncoder { +interface VideoEncoder : EventTarget { constructor(VideoEncoderInit init); readonly attribute CodecState state; readonly attribute unsigned long encodeQueueSize; + attribute EventHandler ondequeue; undefined configure(VideoEncoderConfig config); undefined encode(VideoFrame frame, optional VideoEncoderEncodeOptions options = {}); @@ -1180,60 +1340,79 @@ Internal Slots {#videoencoder-internal-slots} --------------------------------------------- -<dl> -<dt><dfn attribute for=VideoEncoder>[[codec implementation]]</dfn></dt> -<dd>Underlying encoder implementation provided by the User Agent.</dd> -<dt><dfn attribute for=VideoEncoder>[[output callback]]</dfn></dt> -<dd>Callback given at construction for encoded outputs.</dd> -<dt><dfn attribute for=VideoEncoder>[[error callback]]</dfn></dt> -<dd>Callback given at construction for encode errors.</dd> -<dt><dfn attribute for=VideoEncoder>[[active encoder config]]</dfn></dt> -<dd>The {{VideoEncoderConfig}} that is actively applied.</dd> -<dt><dfn attribute for=VideoEncoder>[[active output config]]</dfn></dt> -<dd> - The {{VideoDecoderConfig}} that describes how to decode the most recently - emitted {{EncodedVideoChunk}}. -</dd> -<dt><dfn attribute for=VideoEncoder>\[[state]]</dfn></dt> -<dd> - The current {{CodecState}} of this {{VideoEncoder}}. -</dd> -<dt><dfn attribute for=VideoEncoder>\[[encodeQueueSize]]</dfn></dt> -<dd> - The number of pending encode requests. This number will decrease as the - underlying codec is ready to accept new input. -</dd> -<dt><dfn attribute for=VideoEncoder>[[pending flush promises]]</dfn></dt> -<dd> - A list of unresolved promises returned by calls to {{VideoEncoder/flush()}}. -</dd> -</dl> +: <dfn attribute for=VideoEncoder>[[control message queue]]</dfn> +:: A [=queue=] of [=control messages=] to be performed upon this [=codec=] + instance. See [=[[control message queue]]=]. +: <dfn attribute for=VideoEncoder>[[message queue blocked]]</dfn> +:: A boolean indicating when processing the + {{VideoEncoder/[[control message queue]]}} is blocked by a pending + [=control message=]. See [=[[message queue blocked]]=]. +: <dfn attribute for=VideoEncoder>[[codec implementation]]</dfn> +:: Underlying encoder implementation provided by the User Agent. See + [=[[codec implementation]]=]. +: <dfn attribute for=VideoEncoder>[[codec work queue]]</dfn> +:: A [=parallel queue=] used for running parallel steps that reference the + {{VideoEncoder/[[codec implementation]]}}. See [=[[codec work queue]]=]. +: <dfn attribute for=VideoEncoder>[[codec saturated]]</dfn> +:: A boolean indicating when the {{VideoEncoder/[[codec implementation]]}} is + unable to accept additional encoding work. +: <dfn attribute for=VideoEncoder>[[output callback]]</dfn> +:: Callback given at construction for encoded outputs. +: <dfn attribute for=VideoEncoder>[[error callback]]</dfn> +:: Callback given at construction for encode errors. +: <dfn attribute for=VideoEncoder>[[active encoder config]]</dfn> +:: The {{VideoEncoderConfig}} that is actively applied. +: <dfn attribute for=VideoEncoder>[[active output config]]</dfn> +:: The {{VideoDecoderConfig}} that describes how to decode the most recently + emitted {{EncodedVideoChunk}}. +: <dfn attribute for=VideoEncoder>\[[state]]</dfn> +:: The current {{CodecState}} of this {{VideoEncoder}}. +: <dfn attribute for=VideoEncoder>\[[encodeQueueSize]]</dfn> +:: The number of pending encode requests. This number will decrease as the + underlying codec is ready to accept new input. +: <dfn attribute for=VideoEncoder>[[pending flush promises]]</dfn> +:: A list of unresolved promises returned by calls to {{VideoEncoder/flush()}}. +: <dfn attribute for=VideoEncoder>[[dequeue event scheduled]]</dfn> +:: A boolean indicating whether a {{VideoEncoder/dequeue}} event is already + scheduled to fire. Used to avoid event spam. Constructors {#videoencoder-constructors} ----------------------------------------- <dfn constructor for=VideoEncoder title="VideoEncoder(init)"> VideoEncoder(init) </dfn> -1. Let e be a new VideoEncoder object. -2. Assign `init.output` to the {{VideoEncoder/[[output callback]]}} internal slot. -3. Assign `init.error` to the {{VideoEncoder/[[error callback]]}} internal slot. -4. Assign "unconfigured" to {{VideoEncoder/[[state]]}}. -5. Return e. +1. Let e be a new {{VideoEncoder}} object. +2. Assign a new [=queue=] to {{VideoEncoder/[[control message queue]]}}. +3. Assign `false` to {{VideoEncoder/[[message queue blocked]]}}. +4. Assign `null` to {{VideoEncoder/[[codec implementation]]}}. +5. Assign the result of starting a new [=parallel queue=] to + {{VideoEncoder/[[codec work queue]]}}. +6. Assign `false` to {{VideoEncoder/[[codec saturated]]}}. +7. Assign init.output to {{VideoEncoder/[[output callback]]}}. +8. Assign init.error to {{VideoEncoder/[[error callback]]}}. +9. Assign `null` to {{VideoEncoder/[[active encoder config]]}}. +10. Assign `null` to {{VideoEncoder/[[active output config]]}}. +11. Assign `"unconfigured"` to {{VideoEncoder/[[state]]}} +12. Assign `0` to {{VideoEncoder/[[encodeQueueSize]]}}. +13. Assign a new [=list=] to {{VideoEncoder/[[pending flush promises]]}}. +14. Assign `false` to {{VideoEncoder/[[dequeue event scheduled]]}}. +15. Return e. Attributes {#videoencoder-attributes} ------------------------------------- -<dl> - <dt> - <dfn attribute for=VideoEncoder>state</dfn> - </dt> - <dd>Returns the value of {{VideoEncoder/[[state]]}}.</dd> - <dt> - <dfn attribute for=VideoEncoder>encodeQueueSize</dfn> - </dt> - <dd> - Returns the value of {{VideoEncoder/[[encodeQueueSize]]}}. - </dd> -</dl> +: <dfn attribute for=VideoEncoder>state</dfn> +:: Returns the value of {{VideoEncoder/[[state]]}}. +: <dfn attribute for=VideoEncoder>encodeQueueSize</dfn> +:: Returns the value of {{VideoEncoder/[[encodeQueueSize]]}}. +: <dfn attribute for=VideoEncoder>ondequeue</dfn> +:: An [=event handler IDL attribute=] whose [=event handler event type=] is + {{VideoEncoder/dequeue}}. + +Event Summary {#videoencoder-event-summary} +------------------------------------------- +: <dfn event for=VideoEncoder>dequeue</dfn> +:: Fired at the {{VideoEncoder}} when the {{VideoEncoder/encodeQueueSize}} has + decreased. Methods {#videoencoder-methods} ------------------------------- @@ -1252,20 +1431,28 @@ When invoked, run these steps: 1. If |config| is not a [=valid VideoEncoderConfig=], throw a {{TypeError}}. - 2. If {{VideoEncoder/[[state]]}} is `"closed"`, throw an {{InvalidStateError}}. + 2. If {{VideoEncoder/[[state]]}} is `"closed"`, throw an + {{InvalidStateError}}. 3. Set {{VideoEncoder/[[state]]}} to `"configured"`. 4. [=Queue a control message=] to configure the encoder using |config|. + 5. [=Process the control message queue=]. - [=Running a control message=] to configure the encoder means performing these - steps: + [=Running a control message=] to configure the encoder means performing + these steps: 1. Let |supported| be the result of running the <a>Check Configuration Support</a> algorithm with |config|. 2. If |supported| is `true`, assign {{VideoEncoder/[[codec implementation]]}} with an implementation supporting |config|. 3. Otherwise, run the <a>Close VideoEncoder</a> algorithm with - {{NotSupportedError}} and abort these steps. - 4. Assign |config| to {{VideoEncoder/[[active encoder config]]}}. + {{NotSupportedError}} and return `"processed"`. + 4. Assign `true` to {{VideoEncoder/[[message queue blocked]]}}. + 5. Enqueue the following steps to {{VideoEncoder/[[codec work queue]]}}: + 1. Configure {{VideoEncoder/[[codec implementation]]}} with |config|. + 2. Set {{VideoEncoder/[[active encoder config]]}} to `config`. + 3. Assign `false` to {{VideoEncoder/[[message queue blocked]]}}. + 4. [=Queue a task=] to [=Process the control message queue=]. + 6. Return `"processed"`. </dd> <dt><dfn method for=VideoEncoder>encode(|frame|, |options|)</dfn></dt> @@ -1273,28 +1460,40 @@ [=Enqueues a control message=] to encode the given |frame|. When invoked, run these steps: - 1. If the value of |frame|'s {{platform object/[[Detached]]}} internal slot is - `true`, throw a {{TypeError}}. + 1. If the value of |frame|'s {{platform object/[[Detached]]}} internal slot + is `true`, throw a {{TypeError}}. 2. If {{VideoEncoder/[[state]]}} is not `"configured"`, throw an {{InvalidStateError}}. 3. Let |frameClone| hold the result of running the [=Clone VideoFrame=] algorithm with |frame|. 4. Increment {{VideoEncoder/[[encodeQueueSize]]}}. 5. [=Queue a control message=] to encode |frameClone|. + 6. [=Process the control message queue=]. - [=Running a control message=] to encode the frame means performing these steps. - 1. Attempt to use {{VideoEncoder/[[codec implementation]]}} to encode - |frameClone| according to |options|. - 2. If encoding results in an error, queue a task on the [=control thread=] - event loop to run the [=Close VideoEncoder=] algorithm with - {{EncodingError}}. - 3. Queue a task on the [=control thread=] event loop to decrement - {{VideoEncoder/[[encodeQueueSize]]}}. - 4. Let |encoded outputs| be a [=list=] of encoded video data outputs - emitted by {{VideoEncoder/[[codec implementation]]}}. - 5. If |encoded outputs| is not empty, queue a task on the [=control thread=] - event loop to run the [=Output EncodedVideoChunks=] algorithm with - |encoded outputs|. + [=Running a control message=] to encode the frame means performing these + steps: + 1. If {{VideoEncoder/[[codec saturated]]}} equals `true`, return `"not + processed"`. + 2. If encoding |frame| will cause the + {{VideoEncoder/[[codec implementation]]}} to become [=saturated=], + assign `true` to {{VideoEncoder/[[codec saturated]]}}. + 3. Decrement {{VideoEncoder/[[encodeQueueSize]]}} and run the + [=VideoEncoder/Schedule Dequeue Event=] algorithm. + 4. Enqueue the following steps to the {{VideoEncoder/[[codec work queue]]}}: + 1. Attempt to use {{VideoEncoder/[[codec implementation]]}} to encode + the |frameClone| according to |options|. + 2. If encoding results in an error, [=queue a task=] to run the + [=Close VideoEncoder=] algorithm with {{EncodingError}} and return. + 3. If {{VideoEncoder/[[codec saturated]]}} equals `true` and + {{VideoEncoder/[[codec implementation]]}} is no longer + [=saturated=], [=queue a task=] to perform the following steps: + 1. Assign `false` to {{VideoEncoder/[[codec saturated]]}}. + 2. [=Process the control message queue=]. + 4. Let |encoded outputs| be a [=list=] of encoded video data outputs + emitted by {{VideoEncoder/[[codec implementation]]}}. + 5. If |encoded outputs| is not empty, [=queue a task=] to run the + [=Output EncodedVideoChunks=] algorithm with |encoded outputs|. + 5. Return `"processed"`. </dd> <dt><dfn method for=VideoEncoder>flush()</dfn></dt> @@ -1306,22 +1505,24 @@ 1. If {{VideoEncoder/[[state]]}} is not `"configured"`, return [=a promise rejected with=] {{InvalidStateError}} {{DOMException}}. 2. Let |promise| be a new Promise. - 3. [=Queue a control message=] to flush the codec with |promise|. - 4. Append |promise| to {{VideoEncoder/[[pending flush promises]]}}. - 5. Return |promise|. - - [=Running a control message=] to flush the codec means performing these steps - with |promise|. - 1. Signal {{VideoEncoder/[[codec implementation]]}} to emit all [=internal - pending outputs=]. - 2. Let |encoded outputs| be a [=list=] of encoded video data outputs - emitted by {{VideoEncoder/[[codec implementation]]}}. - 3. If |encoded outputs| is not empty, queue a task on the [=control thread=] - event loop to run the [=Output EncodedVideoChunks=] algorithm with - |encoded outputs|. - 4. Queue a task on the [=control thread=] event loop to run these steps: - 1. Remove |promise| from {{VideoEncoder/[[pending flush promises]]}}. - 2. Resolve |promise|. + 3. Append |promise| to {{VideoEncoder/[[pending flush promises]]}}. + 4. [=Queue a control message=] to flush the codec with |promise|. + 5. [=Process the control message queue=]. + 6. Return |promise|. + + [=Running a control message=] to flush the codec means performing these + steps with |promise|: + 1. Enqueue the following steps to the {{VideoEncoder/[[codec work queue]]}}: + 1. Signal {{VideoEncoder/[[codec implementation]]}} to emit all + [=internal pending outputs=]. + 2. Let |encoded outputs| be a [=list=] of encoded video data outputs + emitted by {{VideoEncoder/[[codec implementation]]}}. + 3. [=Queue a task=] to perform these steps: + 1. If |encoded outputs| is not empty, run the + [=Output EncodedVideoChunks=] algorithm with |encoded outputs|. + 2. Remove |promise| from + {{VideoEncoder/[[pending flush promises]]}}. + 3. Resolve |promise|. </dd> <dt><dfn method for=VideoEncoder>reset()</dfn></dt> @@ -1375,6 +1576,14 @@ Algorithms {#videoencoder-algorithms} ------------------------------------- <dl> + <dt><dfn for=VideoEncoder>Schedule Dequeue Event</dfn> + <dd> + 1. If {{VideoEncoder/[[dequeue event scheduled]]}} equals `true`, return. + 2. Assign `true` to {{VideoEncoder/[[dequeue event scheduled]]}}. + 3. [=Queue a task=] to run the following steps: + 1. Fire a simple event named {{VideoEncoder/dequeue}} at [=this=]. + 2. Assign `false` to {{VideoEncoder/[[dequeue event scheduled]]}}. + </dd> <dt><dfn>Output EncodedVideoChunks</dfn> (with |outputs|)</dt> <dd> Run these steps: @@ -1448,8 +1657,11 @@ 4. Set {{VideoEncoder/[[active output config]]}} to `null`. 5. Signal {{VideoEncoder/[[codec implementation]]}} to cease producing output for the previous configuration. - 6. Remove all [=control messages=] from the [=control message queue=]. - 7. Set {{VideoEncoder/[[encodeQueueSize]]}} to zero. + 6. Remove all [=control messages=] from the + {{VideoEncoder/[[control message queue]]}}. + 7. If {{VideoEncoder/[[encodeQueueSize]]}} is greater than zero: + 1. Set {{VideoEncoder/[[encodeQueueSize]]}} to zero. + 2. Run the [=VideoEncoder/Schedule Dequeue Event=] algorithm. 8. For each |promise| in {{VideoEncoder/[[pending flush promises]]}}: 1. Reject |promise| with |exception|. 2. Remove |promise| from {{VideoEncoder/[[pending flush promises]]}}. @@ -1461,8 +1673,9 @@ 2. Set {{VideoEncoder/[[state]]}} to `"closed"`. 3. Clear {{VideoEncoder/[[codec implementation]]}} and release associated [=system resources=]. - 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on - the [=control thread=] event loop to invoke the {{AudioDecoder/[[error callback]]}} with |exception|. + 4. If |exception| is not an {{AbortError}} {{DOMException}}, + [=queue a task=] to invoke the {{VideoEncoder/[[error callback]]}} with + |exception|. </dd> </dl> @@ -1552,7 +1765,12 @@ 2. If `config[m]` is a nested dictionary, set `clone[m]` to the result of recursively running the <a>Clone Configuration</a> algorithm with `config[m]`. - 3. Otherwise, assign the value of `config[m]` to `clone[m]`. + 3. Otherwise, assign a copy of `config[m]` to `clone[m]`. + +Note: This implements a "deep-copy". These configuration objects are +frequently used as the input of asynchronous operations. Copying means that +modifying the original object while the operation is in flight won't change the +operation's outcome. Signalling Configuration Support{#config-support-info} @@ -1711,7 +1929,7 @@ <xmp class='idl'> dictionary VideoDecoderConfig { required DOMString codec; - BufferSource description; + AllowSharedBufferSource description; [EnforceRange] unsigned long codedWidth; [EnforceRange] unsigned long codedHeight; [EnforceRange] unsigned long displayAspectWidth; @@ -1761,10 +1979,10 @@ <dd> Height of the VideoFrame in pixels, potentially including non-visible padding, and prior to considering potential ratio adjustments. - </dd> - NOTE: {{VideoDecoderConfig/codedWidth}} and {{VideoDecoderConfig/codedHeight}} + NOTE: {{VideoDecoderConfig/codedWidth}} and {{VideoDecoderConfig/codedHeight}} are used when selecting a {{VideoDecoder/[[codec implementation]]}}. + </dd> <dt><dfn dict-member for=VideoDecoderConfig>displayAspectWidth</dfn></dt> <dd> @@ -1774,12 +1992,12 @@ <dt><dfn dict-member for=VideoDecoderConfig>displayAspectHeight</dfn></dt> <dd> Vertical dimension of the VideoFrame's aspect ratio when displayed. - </dd> - NOTE: {{VideoFrame/displayWidth}} and {{VideoFrame/displayHeight}} can both be + NOTE: {{VideoFrame/displayWidth}} and {{VideoFrame/displayHeight}} can both be different from {{VideoDecoderConfig/displayAspectWidth}} and {{VideoDecoderConfig/displayAspectHeight}}, but have identical ratios, after scaling is applied when [=create a videoframe|creating the video frame=]. + </dd> <dt><dfn dict-member for=VideoDecoderConfig>colorSpace</dfn></dt> <dd> @@ -1816,6 +2034,7 @@ [EnforceRange] unsigned long sampleRate; [EnforceRange] unsigned long numberOfChannels; [EnforceRange] unsigned long long bitrate; + BitrateMode bitrateMode; }; @@ -1826,7 +2045,10 @@ run these steps: 1. If {{AudioEncoderConfig/codec}} is not a valid codec string, return `false`. -2. Return `true`. +2. If the {{AudioEncoderConfig}} has a codec-specific extension and the corresponding + registration in the [[WEBCODECS-CODEC-REGISTRY]] defines steps to check whether + the extension is a valid extension, return the result of running those steps. +3. Return `true`.
codec
@@ -1842,6 +2064,13 @@
The average bitrate of the encoded audio given in units of bits per second.
+
bitrateMode
+
+ Configures the encoder to use a {{BitrateMode/constant}} or + {{BitrateMode/variable}} bitrate as defined by [[MEDIASTREAM-RECORDING]]. + + NOTE: Not all audio codecs support specific {{BitrateMode}}s, Authors are encouraged to check by calling {{AudioEncoder/isConfigSupported()}} with |config|. +
@@ -1855,11 +2084,11 @@ [EnforceRange] unsigned long displayWidth; [EnforceRange] unsigned long displayHeight; [EnforceRange] unsigned long long bitrate; - [EnforceRange] double framerate; + double framerate; HardwareAcceleration hardwareAcceleration = "no-preference"; AlphaOption alpha = "discard"; DOMString scalabilityMode; - BitrateMode bitrateMode = "variable"; + VideoEncoderBitrateMode bitrateMode = "variable"; LatencyMode latencyMode = "quality"; }; @@ -1929,7 +2158,7 @@
bitrate
The average bitrate of the encoded video given in units of bits per second. - + NOTE: Authors are encouraged to additionally provide a {{VideoEncoderConfig/framerate}} to inform rate control.
@@ -1966,8 +2195,8 @@
bitrateMode
- Configures encoding to use a {{BitrateMode/constant}} or - {{BitrateMode/variable}} bitrate as defined by [[MEDIASTREAM-RECORDING]]. + Configures encoding to use one of the rate control modes specified by + {{VideoEncoderBitrateMode}}. NOTE: The precise degree of bitrate fluctuation in either mode is implementation defined. @@ -2145,6 +2374,9 @@ }; +NOTE: Codec-specific extensions to {{VideoEncoderEncodeOptions}} are described in + their registrations in the [[WEBCODECS-CODEC-REGISTRY]]. +
keyFrame
@@ -2155,6 +2387,34 @@
+VideoEncoderBitrateMode{#video-encoder-bitrate-mode} +------------------------------------------- + + enum VideoEncoderBitrateMode { + "constant", + "variable", + "quantizer" + }; + + +
+
constant
+
Encode at a constant bitrate. See {{VideoEncoderConfig/bitrate}}.
+
variable
+
+ Encode using a variable bitrate, allowing more space to be used for + complex signals and less space for less complex signals. + See {{VideoEncoderConfig/bitrate}}. +
+
quantizer
+
+ Encode using a quantizer, that is specified for each video + frame in codec specific extensions of {{VideoEncoderEncodeOptions}}. +
+
+ + + CodecState{#codec-state} ------------------------ @@ -2194,7 +2454,7 @@ EncodedAudioChunk Interface {#encodedaudiochunk-interface} ------------------------------------------------------------ <xmp class='idl'> -[Exposed=(Window,DedicatedWorker)] +[Exposed=(Window,DedicatedWorker), Serializable] interface EncodedAudioChunk { constructor(EncodedAudioChunkInit init); readonly attribute EncodedAudioChunkType type; @@ -2202,7 +2462,7 @@ readonly attribute unsigned long long? duration; // microseconds readonly attribute unsigned long byteLength; - undefined copyTo([AllowShared] BufferSource destination); + undefined copyTo(AllowSharedBufferSource destination); }; dictionary EncodedAudioChunkInit { @@ -2219,7 +2479,7 @@ ### Internal Slots ### {#encodedaudiochunk-internal-slots} -: [[internal data]] +: [[internal data]] :: An array of bytes representing the encoded chunk data. : \[[type]] :: Describes whether the chunk is a [=key chunk=]. @@ -2263,10 +2523,28 @@ greater than in |destination|, throw a {{TypeError}}. 2. Copy the {{EncodedAudioChunk/[[internal data]]}} into |destination|. +### Serialization ###{#encodedaudiochunk-serialization} +: The {{EncodedAudioChunk}} [=serialization steps=] (with |value|, |serialized|, + and |forStorage|) are: +:: 1. If |forStorage| is `true`, throw a {{DataCloneError}}. + 2. For each {{EncodedAudioChunk}} internal slot in |value|, assign the value + of each internal slot to a field in |serialized| with the same name as + the internal slot. + +: The {{EncodedAudioChunk}} [=deserialization steps=] (with |serialized| and + |value|) are: +:: 1. For all named fields in |serialized|, assign the value of each named field + to the {{EncodedAudioChunk}} internal slot in |value| with the same name + as the named field. + +NOTE: Since {{EncodedAudioChunk}}s are immutable, User + Agents may choose to implement serialization using a reference counting + model similar to [[#audiodata-transfer-serialization]]. + EncodedVideoChunk Interface{#encodedvideochunk-interface} ----------------------------------------------------------- -[Exposed=(Window,DedicatedWorker)] +[Exposed=(Window,DedicatedWorker), Serializable] interface EncodedVideoChunk { constructor(EncodedVideoChunkInit init); readonly attribute EncodedVideoChunkType type; @@ -2274,14 +2552,14 @@ readonly attribute unsigned long long? duration; // microseconds readonly attribute unsigned long byteLength; - undefined copyTo([AllowShared] BufferSource destination); + undefined copyTo(AllowSharedBufferSource destination); }; dictionary EncodedVideoChunkInit { required EncodedVideoChunkType type; [EnforceRange] required long long timestamp; // microseconds [EnforceRange] unsigned long long duration; // microseconds - required BufferSource data; + required AllowSharedBufferSource data; }; enum EncodedVideoChunkType { @@ -2291,10 +2569,10 @@ ### Internal Slots ### {#encodedvideochunk-internal-slots} -: [[internal data]] +: [[internal data]] :: An array of bytes representing the encoded chunk data. : \[[type]] -:: The {{EncodedAudioChunkType}} of this {{EncodedVideoChunk}}; +:: The {{EncodedVideoChunkType}} of this {{EncodedVideoChunk}}; : \[[timestamp]] :: The presentation timestamp, given in microseconds. : \[[duration]] @@ -2337,6 +2615,24 @@ {{TypeError}}. 2. Copy the {{EncodedVideoChunk/[[internal data]]}} into |destination|. +### Serialization ###{#encodedvideochunk-serialization} +: The {{EncodedVideoChunk}} [=serialization steps=] (with |value|, |serialized|, + and |forStorage|) are: +:: 1. If |forStorage| is `true`, throw a {{DataCloneError}}. + 2. For each {{EncodedVideoChunk}} internal slot in |value|, assign the value + of each internal slot to a field in |serialized| with the same name as + the internal slot. + +: The {{EncodedVideoChunk}} [=deserialization steps=] (with |serialized| and + |value|) are: +:: 1. For all named fields in |serialized|, assign the value of each named field + to the {{EncodedVideoChunk}} internal slot in |value| with the same name + as the named field. + +NOTE: Since {{EncodedVideoChunk}}s are immutable, User + Agents may choose to implement serialization using a reference counting + model similar to [[#videoframe-transfer-serialization]]. + Raw Media Interfaces {#raw-media-interfaces} ==================================================== @@ -2353,7 +2649,7 @@ memory. To minimize the need for expensive copies, this specification defines a scheme for reference counting (`clone()` and `close()`). -NOTE: Authors are encourage to call `close()` immediately when frames are +NOTE: Authors are encouraged to call `close()` immediately when frames are no longer needed. ### Reference Counting ### {#raw-media-memory-model-reference-counting} @@ -2371,7 +2667,7 @@ object. {{VideoFrame}}.{{VideoFrame/close()}} and {{AudioData}}.{{AudioData/close()}} -will clear their [[resource reference]] slot, releasing the reference their +will clear their `[[resource reference]]` slot, releasing the reference their [=media resource=]. A [=media resource=] MUST remain alive at least as long @@ -2386,8 +2682,9 @@ This section is non-normative. -{{AudioData}} and {{VideoFrame}} are both [=transferable objects|transferable=] -and [=serializable objects|serializable=] objects. Their transfer and +{{AudioData}} and {{VideoFrame}} are both +[[HTML#transferable-objects|transferable]] and +[[HTML#serializable-objects|serializable]] objects. Their transfer and serialization steps are defined in [[#audiodata-transfer-serialization]] and [[#videoframe-transfer-serialization]] respectively. @@ -2419,7 +2716,7 @@ readonly attribute long long timestamp; // microseconds unsigned long allocationSize(AudioDataCopyToOptions options); - undefined copyTo([AllowShared] BufferSource destination, AudioDataCopyToOptions options); + undefined copyTo(AllowSharedBufferSource destination, AudioDataCopyToOptions options); AudioData clone(); undefined close(); }; @@ -2431,6 +2728,7 @@ [EnforceRange] required unsigned long numberOfChannels; [EnforceRange] required long long timestamp; // microseconds required BufferSource data; + sequence transfer = []; }; @@ -2462,7 +2760,12 @@ AudioData(init) 1. If |init| is not a [=valid AudioDataInit=], throw a {{TypeError}}. -2. Let |frame| be a new {{AudioData}} object, initialized as follows: +2. If |init|.{{AudioDataInit/transfer}} contains more than one reference + to the same {{ArrayBuffer}}, then throw a {{DataCloneError}} {{DOMException}}. +3. For each |transferable| in |init|.{{AudioDataInit/transfer}}: + 1. If {{platform object/[[Detached]]}} internal slot is `true`, + then throw a {{DataCloneError}} {{DOMException}}. +4. Let |frame| be a new {{AudioData}} object, initialized as follows: 1. Assign `false` to {{platform object/[[Detached]]}}. 2. Assign |init|.{{AudioDataInit/format}} to {{AudioData/[[format]]}}. @@ -2474,11 +2777,20 @@ {{AudioData/[[number of channels]]}}. 6. Assign |init|.{{AudioDataInit/timestamp}} to {{AudioData/[[timestamp]]}}. - 7. Let |resource| be a [=media resource=] containing a copy of - |init|.{{AudioDataInit/data}}. - 8. Let |resourceReference| be a reference to |resource|. - 9. Assign |resourceReference| to {{AudioData/[[resource reference]]}}. -3. Return |frame|. + 7. If |init|.{{AudioDataInit/transfer}} contains an {{ArrayBuffer}} + referenced by |init|.{{AudioDataInit/data}} the User Agent + MAY choose to: + 1. Let |resource| be a new [=media resource=] referencing sample data + in |data|. + 8. Otherwise: + 1. Let |resource| be a [=media resource=] containing a copy of + |init|.{{AudioDataInit/data}}. + 9. Let |resourceReference| be a reference to |resource|. + 10. Assign |resourceReference| to {{AudioData/[[resource reference]]}}. +5. For each |transferable| in |init|.{{AudioDataInit/transfer}}: + 1. Perform [DetachArrayBuffer](https://tc39.es/ecma262/#sec-detacharraybuffer) + on |transferable| +6. Return |frame|. ### Attributes ###{#audiodata-attributes} @@ -2614,7 +2926,7 @@ to |copyFrameCount|. 10. Let |elementCount| be |copyFrameCount|. 11. If |destFormat| describes an [=interleaved=] - {{AudioSampleFormat}}, mutliply |elementCount| by + {{AudioSampleFormat}}, multiply |elementCount| by {{AudioData/[[number of channels]]}} 12. return |elementCount|. @@ -2688,7 +3000,7 @@ |forStorage|) are: :: 1. If |value|'s {{platform object/[[Detached]]}} is `true`, throw a {{DataCloneError}} {{DOMException}}. - 2. If |forStorage| is `true`, throw a {{TypeError}}. + 2. If |forStorage| is `true`, throw a {{DataCloneError}}. 3. Let |resource| be the [=media resource=] referenced by |value|'s {{AudioData/[[resource reference]]}}. 4. Let |newReference| be a new reference to |resource|. @@ -2756,7 +3068,7 @@ A frame or (sample-frame) refers to a set of values of all channels of a multi-channel signal, that happen at the exact same time. -NOTE: Consequently if an audio signal is mono (has only one channel), a frame +NOTE: Consequently, if an audio signal is mono (has only one channel), a frame and a sample refer to the same thing. All audio [=samples=] in this specification are using linear pulse-code @@ -2922,7 +3234,7 @@ [Exposed=(Window,DedicatedWorker), Serializable, Transferable] interface VideoFrame { constructor(CanvasImageSource image, optional VideoFrameInit init = {}); - constructor([AllowShared] BufferSource data, VideoFrameBufferInit init); + constructor(AllowSharedBufferSource data, VideoFrameBufferInit init); readonly attribute VideoPixelFormat? format; readonly attribute unsigned long codedWidth; @@ -2932,13 +3244,15 @@ readonly attribute unsigned long displayWidth; readonly attribute unsigned long displayHeight; readonly attribute unsigned long long? duration; // microseconds - readonly attribute long long? timestamp; // microseconds + readonly attribute long long timestamp; // microseconds readonly attribute VideoColorSpace colorSpace; + VideoFrameMetadata metadata(); + unsigned long allocationSize( optional VideoFrameCopyToOptions options = {}); Promise> copyTo( - [AllowShared] BufferSource destination, + AllowSharedBufferSource destination, optional VideoFrameCopyToOptions options = {}); VideoFrame clone(); undefined close(); @@ -2957,6 +3271,8 @@ // Default matches image unless visibleRect is provided. [EnforceRange] unsigned long displayWidth; [EnforceRange] unsigned long displayHeight; + + VideoFrameMetadata metadata; }; dictionary VideoFrameBufferInit { @@ -2977,6 +3293,12 @@ [EnforceRange] unsigned long displayHeight; VideoColorSpaceInit colorSpace; + + sequence transfer = []; +}; + +dictionary VideoFrameMetadata { + // Possible members are recorded in the VideoFrame Metadata Registry. }; @@ -3032,6 +3354,11 @@ : [[color space]] :: The {{VideoColorSpace}} associated with this frame. +: \[[metadata]] +:: The {{VideoFrameMetadata}} associated with this frame. + Possible members are recorded in [[webcodecs-video-frame-metadata-registry]]. + By design, all {{VideoFrameMetadata}} properties are serializable. + ### Constructors ###{#videoframe-constructors} @@ -3040,12 +3367,17 @@ 1. [=Canvas/Check the usability of the image argument=]. If this throws an exception or returns bad, then throw an {{InvalidStateError}} {{DOMException}}. -2. If the [=origin/origin=] of |image|'s image data is not [=same origin=] - with the [=webappapis/entry settings object=]'s - [=origin/origin=], then throw a {{SecurityError}} - {{DOMException}}. +2. If |image| [=Canvas/is not origin-clean=], then throw a {{SecurityError}} {{DOMException}}. 3. Let |frame| be a new {{VideoFrame}}. 5. Switch on |image|: + + NOTE: Authors are encouraged to provide a meaningful timestamp unless it is + implicitly provided by the {{CanvasImageSource}} at construction. + Interfaces that consume {{VideoFrame}}s can rely on this value for + timing decisions. For example, {{VideoEncoder}} can use + {{VideoFrame/timestamp}} values to guide rate control (see + {{VideoEncoderConfig/framerate}}). + - {{HTMLImageElement}} - {{SVGImageElement}} 1. If {{VideoFrameInit/timestamp}} does not [=map/exist=] in @@ -3070,7 +3402,9 @@ {{InvalidStateError}} {{DOMException}}. 2. Let |currentPlaybackFrame| be the {{VideoFrame}} at the [=current playback position=]. - 3. Run the [=VideoFrame/Initialize Frame From Other Frame=] algorithm + 3. If {{VideoFrameInit/metadata}} does not [=map/exist=] in |init|, + assign |currentPlaybackFrame|.{{VideoFrame/[[metadata]]}} to it. + 4. Run the [=VideoFrame/Initialize Frame From Other Frame=] algorithm with |init|, |frame|, and |currentPlaybackFrame|. - {{HTMLCanvasElement}} @@ -3105,23 +3439,33 @@ 3. Let |overrideRect| be `undefined`. 4. If |init|.{{VideoFrameBufferInit/visibleRect}} [=map/exists=], assign its value to |overrideRect|. -4. Let |parsedRect| be the result of running the [=VideoFrame/Parse Visible +5. Let |parsedRect| be the result of running the [=VideoFrame/Parse Visible Rect=] algorithm with |defaultRect|, |overrideRect|, |init|.{{VideoFrameBufferInit/codedWidth}}, |init|.{{VideoFrameBufferInit/codedHeight}}, and |init|.{{VideoFrameBufferInit/format}}. -5. If |parsedRect| is an exception, return |parsedRect|. -6. Let |optLayout| be `undefined`. -7. If |options|.{{VideoFrameBufferInit/layout}} [=map/exists=], assign its value +6. If |parsedRect| is an exception, return |parsedRect|. +7. Let |optLayout| be `undefined`. +8. If |options|.{{VideoFrameBufferInit/layout}} [=map/exists=], assign its value to |optLayout|. -8. Let |combinedLayout| be the result of running the [=VideoFrame/Compute +9. Let |combinedLayout| be the result of running the [=VideoFrame/Compute Layout and Allocation Size=] algorithm with |parsedRect|, |init|.{{VideoFrameBufferInit/format}}, and |optLayout|. -9. If |combinedLayout| is an exception, throw |combinedLayout|. -10. If `data.byteLength` is less than |combinedLayout|’s +10. If |combinedLayout| is an exception, throw |combinedLayout|. +11. If `data.byteLength` is less than |combinedLayout|’s [=combined buffer layout/allocationSize=], throw a {{TypeError}}. -11. Let |resource| be a new [=media resource=] containing a copy of |data|. Use - {{VideoFrameBufferInit/visibleRect}} and {{VideoFrameBufferInit/layout}} +12. If |init|.{{VideoFrameBufferInit/transfer}} contains more than one reference + to the same {{ArrayBuffer}}, then throw a {{DataCloneError}} {{DOMException}}. +13. For each |transferable| in |init|.{{VideoFrameBufferInit/transfer}}: + 1. If {{platform object/[[Detached]]}} internal slot is `true`, + then throw a {{DataCloneError}} {{DOMException}}. +14. If |init|.{{VideoFrameBufferInit/transfer}} contains an {{ArrayBuffer}} + referenced by |data| the User Agent MAY choose to: + 1. Let |resource| be a new [=media resource=] referencing pixel data in + |data|. +15. Otherwise: + 1. Let |resource| be a new [=media resource=] containing a copy of |data|. + Use {{VideoFrameBufferInit/visibleRect}} and {{VideoFrameBufferInit/layout}} to determine where in |data| the pixels for each plane reside. The User Agent MAY choose to allocate @@ -3133,18 +3477,21 @@ reposition the visible rectangle within |resource|. The final position will be reflected by {{VideoFrame/visibleRect}}. -12. Let |resourceCodedWidth| be the coded width of |resource|. -13. Let |resourceCodedHeight| be the coded height of |resource|. -14. Let |resourceVisibleLeft| be the left offset for the visible rectangle of +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|. -15. Let |resourceVisibleTop| be the top offset for the visible rectangle of +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). -16. Let |frame| be a new {{VideoFrame}} object initialized as follows: +21. Let |frame| be a new {{VideoFrame}} object initialized as follows: 1. Assign |resourceCodedWidth|, |resourceCodedHeight|, |resourceVisibleLeft|, and |resourceVisibleTop| to {{VideoFrame/[[coded width]]}}, {{VideoFrame/[[coded height]]}}, @@ -3154,11 +3501,11 @@ 1. Let |truncatedVisibleWidth| be the value of {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/width}} after truncating. - 1. Assign |truncatedVisibleWidth| to {{VideoFrame/[[visible width]]}}. + 2. Assign |truncatedVisibleWidth| to {{VideoFrame/[[visible width]]}}. 3. Let |truncatedVisibleHeight| be the value of {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/height}} after truncating. - 2. Assign |truncatedVisibleHeight| to {{VideoFrame/[[visible height]]}}. + 4. Assign |truncatedVisibleHeight| to {{VideoFrame/[[visible height]]}}. 3. Otherwise: 1. Assign {{VideoFrame/[[coded width]]}} to {{VideoFrame/[[visible width]]}}. @@ -3179,7 +3526,9 @@ 9. Assign the result of running the [=VideoFrame/Pick Color Space=] algorithm, with |colorSpace| and {{VideoFrame/[[format]]}}, to {{VideoFrame/[[color space]]}}. -17. Return |frame|. + 10. Assign the result of calling [=Copy VideoFrame metadata=] + with |init|'s {{VideoFrameInit/metadata}} to |frame|.{{VideoFrame/[[metadata]]}}. +22. Return |frame|. ### Attributes ###{#videoframe-attributes} : format @@ -3358,7 +3707,7 @@ [=computed plane layout/destinationStride=]. 4. Increment |row| by `1`. 9. Increment |planeIndex| by `1`. - 5. Queue a task on the [=control thread=] event loop to resolve |p|. + 5. [=Queue a task=] to resolve |p|. 9. Return |p|. : clone() @@ -3377,6 +3726,15 @@ When invoked, run the [=Close VideoFrame=] algorithm with [=this=]. +: metadata() +:: Gets the {{VideoFrameMetadata}} associated with this frame. + + When invoked, run these steps: + 1. If {{platform object/[[Detached]]}} is true, + throw an {{InvalidStateError}} {{DOMException}}. + 2. Return the result of calling [=Copy VideoFrame metadata=] + with {{VideoFrame/[[metadata]]}}. + ### Algorithms ###{#videoframe-algorithms} : Create a VideoFrame (with |output|, |timestamp|, |duration|, |displayAspectWidth|, |displayAspectHeight|, and |colorSpace|) :: 1. Let |frame| be a new {{VideoFrame}}, constructed as follows: @@ -3391,7 +3749,7 @@ |output| in pixels. 8. Let |visibleLeft|, |visibleTop|, |visibleWidth|, and |visibleHeight| be the left, top, width and height for the visible rectangle of |output|. - 7. Let |displayWidth| and |displayHeight| be the the display size of + 7. Let |displayWidth| and |displayHeight| be the display size of |output| in pixels. 8. If |displayAspectWidth| and |displayAspectHeight| are provided, increase |displayWidth| or |displayHeight| until the ratio of @@ -3436,10 +3794,10 @@ {{VideoFrameInit/visibleRect}}.{{DOMRectInit/height}} == `0` return `false`. 5. If {{VideoFrameInit/visibleRect}}.{{DOMRectInit/y}} + - {{VideoFrameInit/visibleRect}}.{{DOMRectInit/height}} >= + {{VideoFrameInit/visibleRect}}.{{DOMRectInit/height}} > |codedHeight|, return `false`. 6. If {{VideoFrameInit/visibleRect}}.{{DOMRectInit/x}} + - {{VideoFrameInit/visibleRect}}.{{DOMRectInit/width}} >= + {{VideoFrameInit/visibleRect}}.{{DOMRectInit/width}} > |codedWidth|, return `false`. 2. If |codedWidth| = 0 or |codedHeight| = 0,return `false`. 3. If only one of {{VideoFrameInit/displayWidth}} or @@ -3455,10 +3813,10 @@ 2. If any attribute of {{VideoFrameBufferInit/visibleRect}} is negative or not finite, return `false`. 3. If {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/y}} + - {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/height}} >= + {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/height}} > {{VideoFrameBufferInit/codedHeight}}, return `false`. 4. If {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/x}} + - {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/width}} >= + {{VideoFrameBufferInit/visibleRect}}.{{DOMRectInit/width}} > {{VideoFrameBufferInit/codedWidth}}, return `false`. 5. If only one of {{VideoFrameBufferInit/displayWidth}} or {{VideoFrameBufferInit/displayHeight}} [=map/exists=], return `false`. @@ -3492,14 +3850,16 @@ algorithm with |init|, |frame|, |defaultVisibleRect|, |defaultDisplayWidth|, and |defaultDisplayHeight|. 9. If {{VideoFrameInit/duration}} [=map/exists=] in |init|, assign it to - |frame|.{{VideoFrame/duration}}. Otherwise, assign + |frame|'s {{VideoFrame/[[duration]]}}. Otherwise, assign |otherFrame|.{{VideoFrame/duration}} to - |frame|.{{VideoFrame/duration}}. + |frame|'s {{VideoFrame/[[duration]]}}. 10. If {{VideoFrameInit/timestamp}} [=map/exists=] in |init|, assign it to - |frame|.{{VideoFrame/timestamp}}. Otherwise, assign - |otherFrame|.{{VideoFrame/timestamp}} to - |frame|.{{VideoFrame/timestamp}}. + |frame|'s {{VideoFrame/[[timestamp]]}}. Otherwise, assign + |otherFrame|'s {{VideoFrame/timestamp}} to + |frame|'s {{VideoFrame/[[timestamp]]}}. 11. Assign |format| to |frame|.{{VideoFrame/[[format]]}}. + 12. Assign the result of calling [=Copy VideoFrame metadata=] + with |init|'s {{VideoFrameInit/metadata}} to |frame|.{{VideoFrame/[[metadata]]}}. : Initialize Frame With Resource and Size (with |init|, |frame|, |resource|, |width| and |height|) @@ -3522,9 +3882,9 @@ algorithm with |init|, |frame|, |defaultVisibleRect|, |width|, and |height|. 11. Assign `init`.{{VideoFrameInit/duration}} to - |frame|.{{VideoFrame/duration}}. + |frame|'s {{VideoFrame/[[duration]]}}. 12. Assign `init`.{{VideoFrameInit/timestamp}} to - |frame|.{{VideoFrame/timestamp}}. + |frame|'s {{VideoFrame/[[timestamp]]}}. 13. If |resource| has a known {{VideoColorSpace}}, assign its value to {{VideoFrame/[[color space]]}}. 14. Otherwise, assign a new {{VideoColorSpace}}, constructed with an empty @@ -3576,8 +3936,7 @@ {{VideoFrame/[[visible top]]}}, {{VideoFrame/[[visible width]]}}, {{VideoFrame/[[visible height]]}}, {{VideoFrame/[[display width]]}}, and {{VideoFrame/[[display height]]}}. - 5. Assign `null` to |frame|'s {{VideoFrame/[[duration]]}} and - {{VideoFrame/[[timestamp]]}}. + 5. Assign a new {{VideoFrameMetadata}} to |frame|.{{VideoFrame/[[metadata]]}}. : Parse VideoFrameCopyToOptions (with |options|) :: 1. Let |defaultRect| be the result of performing the getter steps for @@ -3617,7 +3976,7 @@ subsample for |plane|. 4. If |rect|.{{DOMRectReadOnly/x}} is not a multiple of |sampleWidth|, return `false`. - 5. If |rect|.{{DOMRectReadOnly/y}} is not a multiple of |sampleHeight|, + 5. If |rect|.{{DOMRectReadOnly/y}} is not a multiple of |sampleHeight|, return `false`. 8. Increment |planeIndex| by `1`. 5. Return `true`. @@ -3709,7 +4068,8 @@ 1. Assign |minAllocationSize| to |computedLayout|'s [=computed plane layout/destinationOffset=]. - 2. Assign |computedLayout|'s [=computed plane layout/sourceWidthBytes=] to + 2. Assign |computedLayout|'s + [=computed plane layout/sourceWidthBytes=] to |computedLayout|'s [=computed plane layout/destinationStride=]. 13. Let |planeSize| be the product of multiplying |computedLayout|'s [=computed plane layout/destinationStride=] and @@ -3750,6 +4110,13 @@ [=combined buffer layout/allocationSize=]. 9. Return |combinedLayout|. +: Copy VideoFrame metadata (with |metadata|) +:: 1. Let |metadataCopySerialized| be [$StructuredSerialize$](|metadata|). + 2. Let |metadataCopy| be [$StructuredDeserialize$](|metadataCopySerialized|, [=the current Realm=]). + 3. return |metadataCopy|. + +The goal of this algorithm is to ensure that metadata owned by a {{VideoFrame}} is immutable. + ### Transfer and Serialization ###{#videoframe-transfer-serialization} : The {{VideoFrame}} [=transfer steps=] (with |value| and |dataHolder|) are: @@ -3770,7 +4137,7 @@ |forStorage|) are: :: 1. If |value|'s {{platform object/[[Detached]]}} is `true`, throw a {{DataCloneError}} {{DOMException}}. - 2. If |forStorage| is `true`, throw a {{TypeError}}. + 2. If |forStorage| is `true`, throw a {{DataCloneError}}. 3. Let |resource| be the [=media resource=] referenced by |value|'s {{VideoFrame/[[resource reference]]}}. 4. Let |newReference| be a new reference to |resource|. @@ -3795,7 +4162,7 @@ Color space conversion during {{ImageBitmap}} construction is controlled by {{ImageBitmapOptions}} {{ImageBitmapOptions/colorSpaceConversion}}. Setting this -value to "none" disables color space conversion. +value to {{ColorSpaceConversion/"none"}} disables color space conversion. VideoFrame CopyTo() Options {#videoframe-copyto-options} ------------------------------------------------------------ @@ -3813,7 +4180,7 @@ NOTE: The steps of {{VideoFrame/copyTo()}} or {{VideoFrame/allocationSize()}} will enforce the following requirements: * The coordinates of {{VideoFrameCopyToOptions/rect}} are - sample-aligned as determiend by {{VideoFrame/[[format]]}}. + sample-aligned as determined by {{VideoFrame/[[format]]}}. * If {{VideoFrameCopyToOptions/layout}} [=map/exists=], a {{PlaneLayout}} is provided for all planes. @@ -3836,7 +4203,7 @@ DOMRects in VideoFrame {#videoframe-domrect} -------------------------------------------- -The {{VideoFrame}} interfaces uses {{DOMRect}}s to specify the position and +The {{VideoFrame}} interface uses {{DOMRect}}s to specify the position and dimensions for a rectangle of pixels. {{DOMRectInit}} is used with {{VideoFrame/copyTo()}} and {{VideoFrame/allocationSize()}} to describe the dimensions of the source rectangle. {{VideoFrame}} defines @@ -3853,7 +4220,7 @@ {{PlaneLayout}}s MAY be provided to {{VideoFrame}}'s {{VideoFrame/copyTo()}} to specify how the plane is laid out in the destination {{BufferSource}}}. Alternatively, callers can inspect {{VideoFrame/copyTo()}}'s -returned sequence of {{PlaneLayout}}s to learn the the offset and stride for +returned sequence of {{PlaneLayout}}s to learn the offset and stride for planes as decided by the User Agent. @@ -3925,7 +4292,7 @@ planes of Chroma, denoted Y, U and V, and present in this order. It is also often refered to as Planar YUV 4:2:0. - The U an V planes are [=sub-sampled=] horizontaly and vertically by a + The U an V planes are [=sub-sampled=] horizontally and vertically by a [=factor=] of 2 compared to the Y plane. Each sample in this format is 8 bits. @@ -3953,7 +4320,7 @@ present in this order. It is also often refered to as Planar YUV 4:2:0 with an alpha channel. - The U an V planes are [=sub-sampled=] horizontaly and vertically by a + The U an V planes are [=sub-sampled=] horizontally and vertically by a [=factor=] of 2 compared to the Y and Alpha planes. Each sample in this format is 8 bits. @@ -3982,7 +4349,7 @@ planes of Chroma, denoted Y, U and V, and present in this order. It is also often refered to as Planar YUV 4:2:2. - The U an V planes are [=sub-sampled=] horizontaly by a [=factor=] of 2 + The U an V planes are [=sub-sampled=] horizontally by a [=factor=] of 2 compared to the Y plane, and not [=sub-sampled=] vertically. Each sample in this format is 8 bits. @@ -4023,7 +4390,7 @@ another plane for the two Chroma components. The two planes are present in this order, and are refered to as respectively the Y plane and the UV plane. - The U an V components are [=sub-sampled=] horizontaly and vertically by a + The U an V components are [=sub-sampled=] horizontally and vertically by a [=factor=] of 2 compared to the components in the Y planes. Each sample in this format is 8 bits. @@ -4046,28 +4413,25 @@ {{VideoFrame/visibleRect}}.{{DOMRectInit/y}}) MUST be even. <div class=example> - An image in the NV12 pixel format that is 16 pixels wide and 9 pixels tall + An image in the NV12 pixel format that is 16 pixels wide and 10 pixels tall will be arranged like so in memory: ``` - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - YYYYYYYYYYYYYY - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV - UVUVUVUVUVUVUV + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + YYYYYYYYYYYYYYYY + UVUVUVUVUVUVUVUV + UVUVUVUVUVUVUVUV + UVUVUVUVUVUVUVUV + UVUVUVUVUVUVUVUV + UVUVUVUVUVUVUVUV ``` All samples being linear in memory. @@ -4150,10 +4514,10 @@ }; dictionary VideoColorSpaceInit { - VideoColorPrimaries primaries; - VideoTransferCharacteristics transfer; - VideoMatrixCoefficients matrix; - boolean fullRange; + VideoColorPrimaries? primaries = null; + VideoTransferCharacteristics? transfer = null; + VideoMatrixCoefficients? matrix = null; + boolean? fullRange = null; }; @@ -4172,18 +4536,10 @@ VideoColorSpace(init) 1. Let |c| be a new {{VideoColorSpace}} object, initialized as follows: - 1. If `primaries` is present in `init`, assign `init.primaries` to - {{VideoColorSpace/[[primaries]]}}. Otherwise, assign `null` to - {{VideoColorSpace/[[primaries]]}}. - 2. If `transfer` is present in `init`, assign `init.transfer` to - {{VideoColorSpace/[[transfer]]}}. Otherwise, assign `null` to - {{VideoColorSpace/[[transfer]]}}. - 3. If `matrix` is present in `init`, assign `init.matrix` to - {{VideoColorSpace/[[matrix]]}}. Otherwise, assign `null` to - {{VideoColorSpace/[[matrix]]}}. - 4. If `fullRange` is present in `init`, assign `init.fullRange` to - {{VideoColorSpace/[[full range]]}}. Otherwise, assign `null` to - {{VideoColorSpace/[[full range]]}}. + 1. Assign `init.primaries` to {{VideoColorSpace/[[primaries]]}}. + 2. Assign `init.transfer` to {{VideoColorSpace/[[transfer]]}}. + 3. Assign `init.matrix` to {{VideoColorSpace/[[matrix]]}}. + 4. Assign `init.fullRange` to {{VideoColorSpace/[[full range]]}}. 6. Return |c|. ### Attributes ### {#videocolorspace-attributes} @@ -4206,9 +4562,11 @@ enum VideoColorPrimaries { - "bt709", // BT.709, sRGB - "bt470bg", // BT.601 PAL - "smpte170m", // BT.601 NTSC + "bt709", + "bt470bg", + "smpte170m", + "bt2020", + "smpte432", }; @@ -4228,6 +4586,16 @@ Color primaries used by BT.601 NTSC, as described by [[H.273]] section 8.1 table 2 value 6.
+
bt2020
+
+ Color primaries used by BT.2020 and BT.2100, as described by [[H.273]] + section 8.1 table 2 value 9. +
+
smpte432
+
+ Color primaries used by P3 D65, as described by [[H.273]] + section 8.1 table 2 value 12. +
Video Transfer Characteristics {#videotransfercharacteristics} @@ -4237,9 +4605,12 @@ enum VideoTransferCharacteristics { - "bt709", // BT.709 - "smpte170m", // BT.601 (functionally the same as bt709) - "iec61966-2-1", // sRGB + "bt709", + "smpte170m", + "iec61966-2-1", + "linear", + "pq", + "hlg", }; @@ -4252,13 +4623,28 @@
smpte170m
Transfer characteristics used by BT.601, as described by [[H.273]] - section 8.2 table 3 value 6. + section 8.2 table 3 value 6. (Functionally the same as "bt709".)
iec61966-2-1
Transfer characteristics used by sRGB, as described by [[H.273]] section 8.2 table 3 value 13.
+
linear
+
+ Transfer characteristics used by linear RGB, as described by [[H.273]] + section 8.2 table 3 value 8. +
+
pq
+
+ Transfer characteristics used by BT.2100 PQ, as described by [[H.273]] + section 8.2 table 3 value 16. +
+
hlg
+
+ Transfer characteristics used by BT.2100 HLG, as described by [[H.273]] + section 8.2 table 3 value 18. +
Video Matrix Coefficients {#videomatrixcoefficients} @@ -4268,10 +4654,11 @@ enum VideoMatrixCoefficients { - "rgb", // sRGB - "bt709", // BT.709 - "bt470bg", // BT.601 PAL - "smpte170m", // BT.601 NTSC (functionally the same as bt470bg) + "rgb", + "bt709", + "bt470bg", + "smpte170m", + "bt2020-ncl", }; @@ -4294,7 +4681,12 @@
smpte170m
Matrix coefficients used by BT.601 NTSC, as described by [[H.273]] - section 8.3 table 4 value 6. + section 8.3 table 4 value 6. (Functionally the same as "bt470bg".) +
+
bt2020-ncl
+
+ Matrix coefficients used by BT.2020 NCL, as described by [[H.273]] + section 8.3 table 4 value 9.
@@ -4344,6 +4736,19 @@ ### Internal Slots ### {#imagedecoder-internal-slots} +: [[control message queue]] +:: A [=queue=] of [=control messages=] to be performed upon this [=codec=] + instance. See [=[[control message queue]]=]. + +: [[message queue blocked]] +:: A boolean indicating when processing the + {{ImageDecoder/[[control message queue]]}} is blocked by a pending + [=control message=]. See [=[[message queue blocked]]=]. + +: [[codec work queue]] +:: A [=parallel queue=] used for running parallel steps that reference the + {{ImageDecoder/[[codec implementation]]}}. See [=[[codec work queue]]=]. + : \[[ImageTrackList]] :: An {{ImageTrackList}} describing the tracks found in {{ImageDecoder/[[encoded data]]}} @@ -4361,7 +4766,8 @@ `true`. : [[codec implementation]] -:: An underlying image decoder implementation provided by the User Agent. +:: An underlying image decoder implementation provided by the User Agent. See + [=[[codec implementation]]=]. : [[encoded data]] :: A [=byte sequence=] containing the encoded image data to be decoded. @@ -4375,14 +4781,14 @@ : [[internal selected track index]] :: Identifies the image track within {{ImageDecoder/[[encoded data]]}} that is - used by decoding algorithms on the [=codec thread=]. + used by decoding algorithms. : [[tracks established]] :: A boolean indicating whether the track list has been established in {{ImageDecoder/[[ImageTrackList]]}}. : \[[closed]] -:: A boolean indicating that the ImageDecoder is in a permanent closed state +:: A boolean indicating that the {{ImageDecoder}} is in a permanent closed state and can no longer be used. : [[progressive frame generations]] @@ -4405,64 +4811,87 @@ When invoked, run these steps: 1. If |init| is not [=valid ImageDecoderInit=], throw a {{TypeError}}. - 2. Let |d| be a new {{ImageDecoder}} object. In the steps below, all + 2. If |init|.{{ImageDecoderInit/transfer}} contains more than one reference + to the same {{ArrayBuffer}}, then throw a {{DataCloneError}} {{DOMException}}. + 3. For each |transferable| in |init|.{{ImageDecoderInit/transfer}}: + 1. If {{platform object/[[Detached]]}} internal slot is `true`, + then throw a {{DataCloneError}} {{DOMException}}. + 4. Let |d| be a new {{ImageDecoder}} object. In the steps below, all mentions of {{ImageDecoder}} members apply to |d| unless stated otherwise. - 3. Assign {{ImageDecoder/[[ImageTrackList]]}} a new {{ImageTrackList}} + 5. Assign a new [=queue=] to {{ImageDecoder/[[control message queue]]}}. + 6. Assign `false` to {{ImageDecoder/[[message queue blocked]]}}. + 7. Assign the result of starting a new [=parallel queue=] to + {{ImageDecoder/[[codec work queue]]}}. + 8. Assign {{ImageDecoder/[[ImageTrackList]]}} a new {{ImageTrackList}} initialized as follows: 1. Assign a new [=list=] to {{ImageTrackList/[[track list]]}}. 2. Assign `-1` to {{ImageTrackList/[[selected index]]}}. - 4. Assign {{ImageDecoderInit/type}} to {{ImageDecoder/[[type]]}}. - 5. Assign `null` to {{ImageDecoder/[[codec implementation]]}}. - 6. If `init.preferAnimation` [=map/exists=], assign `init.preferAnimation` + 9. Assign {{ImageDecoderInit/type}} to {{ImageDecoder/[[type]]}}. + 10. Assign `null` to {{ImageDecoder/[[codec implementation]]}}. + 11. If `init.preferAnimation` [=map/exists=], assign `init.preferAnimation` to the {{ImageDecoder/[[prefer animation]]}} internal slot. Otherwise, assign 'null' to {{ImageDecoder/[[prefer animation]]}} internal slot. - 7. Assign a new [=list=] to {{ImageDecoder/[[pending decode promises]]}}. - 8. Assign `-1` to {{ImageDecoder/[[internal selected track index]]}}. - 9. Assign `false` to {{ImageDecoder/[[tracks established]]}}. - 10. Assign `false` to {{ImageDecoder/[[closed]]}}. - 11. Assign a new [=map=] to {{ImageDecoder/[[progressive frame + 12. Assign a new [=list=] to {{ImageDecoder/[[pending decode promises]]}}. + 13. Assign `-1` to {{ImageDecoder/[[internal selected track index]]}}. + 14. Assign `false` to {{ImageDecoder/[[tracks established]]}}. + 15. Assign `false` to {{ImageDecoder/[[closed]]}}. + 16. Assign a new [=map=] to {{ImageDecoder/[[progressive frame generations]]}}. - 12. If |init|'s {{ImageDecoderInit/data}} member is of type + 17. If |init|'s {{ImageDecoderInit/data}} member is of type {{ReadableStream}}: 1. Assign a new [=list=] to {{ImageDecoder/[[encoded data]]}}. 2. Assign `false` to {{ImageDecoder/[[complete]]}} 3. [=Queue a control message=] to [=configure the image decoder=] with |init|. - 4. Let |reader| be the result of [=getting a reader=] for + 4. [=Process the control message queue=]. + 5. Let |reader| be the result of [=getting a reader=] for {{ImageDecoderInit/data}}. - 5. In parallel, perform the [=Fetch Stream Data Loop=] on |d| with + 6. In parallel, perform the [=Fetch Stream Data Loop=] on |d| with |reader|. - 13. Otherwise: + 18. Otherwise: 1. Assert that `init.data` is of type {{BufferSource}}. - 2. Assign a copy of `init.data` to {{ImageDecoder/[[encoded data]]}}. - 3. Assign `true` to {{ImageDecoder/[[complete]]}}. - 4. Reslove {{ImageDecoder/[[completed promise]]}}. - 5. Queue a control message to [=configure the image decoder=] with + 2. If |init|.{{ImageDecoderInit/transfer}} contains an {{ArrayBuffer}} + referenced by |init|.{{ImageDecoderInit/data}} the User Agent + MAY choose to: + 1. Let {{ImageDecoder/[[encoded data]]}} reference bytes in |data| + representing an encoded image. + 3. Otherwise: + 1. Assign a copy of `init.data` to {{ImageDecoder/[[encoded data]]}}. + 4. Assign `true` to {{ImageDecoder/[[complete]]}}. + 5. Resolve {{ImageDecoder/[[completed promise]]}}. + 6. Queue a control message to [=configure the image decoder=] with |init|. - 6. Queue a control message to [=decode track metadata=]. - 14. return |d|. + 7. Queue a control message to [=decode track metadata=]. + 8. [=Process the control message queue=]. + 19. For each |transferable| in |init|.{{ImageDecoderInit/transfer}}: + 1. Perform [DetachArrayBuffer](https://tc39.es/ecma262/#sec-detacharraybuffer) + on |transferable| + 20. return |d|. [=Running a control message=] to configure the image decoder means running these steps: 1. Let |supported| be the result of running the [=ImageDecoder/Check Type Support=] algorithm with `init.type`. - 2. If |supported| is `false`, queue a task on the [=control thread=] event - loop to run the [=ImageDecoder/Close ImageDecoder=] algorithm - with a {{NotSupportedError}} {{DOMException}} and abort - these steps. - 3. If |supported| is `true`, assign the - {{ImageDecoder/[[codec implementation]]}} internal slot with an - implementation supporting `init.type` - 4. Configure {{ImageDecoder/[[codec implementation]]}} in accordance with - the values given for {{ImageDecoderInit/premultiplyAlpha}}, - {{ImageDecoderInit/colorSpaceConversion}}, - {{ImageDecoderInit/desiredWidth}}, and - {{ImageDecoderInit/desiredHeight}}. + 2. If |supported| is `false`, run the [=ImageDecoder/Close ImageDecoder=] + algorithm with a {{NotSupportedError}} {{DOMException}} and return + `"processed"`. + 3. Otherwise, assign the {{ImageDecoder/[[codec implementation]]}} internal + slot with an implementation supporting `init.type` + 3. Assign `true` to {{ImageDecoder/[[message queue blocked]]}}. + 3. Enqueue the following steps to the {{ImageDecoder/[[codec work queue]]}}: + 1. Configure {{ImageDecoder/[[codec implementation]]}} in accordance + with the values given for {{ImageDecoderInit/colorSpaceConversion}}, + {{ImageDecoderInit/desiredWidth}}, and + {{ImageDecoderInit/desiredHeight}}. + 2. Assign `false` to {{ImageDecoder/[[message queue blocked]]}}. + 3. [=Queue a task=] to [=Process the control message queue=]. + 4. Return `"processed"`. [=Running a control message=] to decode track metadata means running these steps: - 1. Run the [=ImageDecoder/Establish Tracks=] algorithm. + 1. Enqueue the following steps to the {{ImageDecoder/[[codec work queue]]}}: + 1. Run the [=ImageDecoder/Establish Tracks=] algorithm. ### Attributes ### {#imagedecoder-attributes} : type @@ -4504,19 +4933,23 @@ 3. If |options| is `undefined`, assign a new {{ImageDecodeOptions}} to |options|. 4. Let |promise| be a new {{Promise}}. - 5. [=Queue a control message=] to decode the image with |options|, and + 5. Append |promise| to {{ImageDecoder/[[pending decode promises]]}}. + 6. [=Queue a control message=] to decode the image with |options|, and |promise|. - 6. Append |promise| to {{ImageDecoder/[[pending decode promises]]}}. - 7. Return |promise|. + 7. [=Process the control message queue=]. + 8. Return |promise|. [=Running a control message=] to decode the image means running these steps: - 1. Wait for {{ImageDecoder/[[tracks established]]}} to become `true`. - 2. If |options|.{{ImageDecodeOptions/completeFramesOnly}} is `false` and - the image is a [=Progressive Image=] for which the User Agent supports - progressive decoding, run the [=Decode Progressive Frame=] algorithm with |options|.{{ImageDecodeOptions/frameIndex}} and |promise|. - 3. Otherwise, run the [=Decode Complete Frame=] algorithm with - |options|.{{ImageDecodeOptions/frameIndex}} and |promise|. + 1. Enqueue the following steps to the {{ImageDecoder/[[codec work queue]]}}: + 1. Wait for {{ImageDecoder/[[tracks established]]}} to become `true`. + 2. If |options|.{{ImageDecodeOptions/completeFramesOnly}} is `false` and + the image is a [=Progressive Image=] for which the User Agent + supports progressive decoding, run the [=Decode Progressive Frame=] + algorithm with |options|.{{ImageDecodeOptions/frameIndex}} and + |promise|. + 3. Otherwise, run the [=Decode Complete Frame=] algorithm with + |options|.{{ImageDecodeOptions/frameIndex}} and |promise|. : reset() :: Immediately aborts all pending work. @@ -4551,9 +4984,8 @@ : [=read request/chunk steps=], given |chunk| :: 1. If {{ImageDecoder/[[closed]]}} is `true`, abort these steps. - 2. If |chunk| is not a Uint8Array object, queue a task on the - [=control thread=] event loop to run the - [=ImageDecoder/Close ImageDecoder=] algorithm with a + 2. If |chunk| is not a Uint8Array object, [=queue a task=] to run + the [=ImageDecoder/Close ImageDecoder=] algorithm with a {{DataError}} {{DOMException}} and abort these steps. 3. Let |bytes| be the byte sequence represented by the Uint8Array object. @@ -4569,9 +5001,8 @@ 2. Resolve {{ImageDecoder/[[completed promise]]}}. : [=read request/error steps=] - :: 1. Queue a task on the [=control thread=] event loop to run the - [=ImageDecoder/Close ImageDecoder=] algorithm with a - {{NotReadableError}} {{DOMException}} + :: 1. [=Queue a task=] to run the [=ImageDecoder/Close ImageDecoder=] + algorithm with a {{NotReadableError}} {{DOMException}} 2. Read a chunk from |reader| given |readRequest|. @@ -4580,11 +5011,10 @@ 1. Assert {{ImageDecoder/[[tracks established]]}} is `false`. 2. If {{ImageDecoder/[[encoded data]]}} does not contain enough data to determine the number of tracks: - 1. If {{ImageDecoder/complete}} is `true`, queue a task on the - [=control thread=] event loop to run the [=ImageDecoder/Close ImageDecoder=] algorithm. + 1. If {{ImageDecoder/complete}} is `true`, [=queue a task=] to run the + [=ImageDecoder/Close ImageDecoder=] algorithm. 2. Abort these steps. - 3. If the number of tracks is found to be `0`, queue a task on the - [=control thread=] event loop to run the + 3. If the number of tracks is found to be `0`, [=queue a task=] to run the [=ImageDecoder/Close ImageDecoder=] algorithm and abort these steps. 4. Let |newTrackList| be a new [=list=]. 5. For each |image track| found in {{ImageDecoder/[[encoded data]]}}: @@ -4624,8 +5054,7 @@ 8. Assign |selectedTrackIndex| to {{ImageDecoder/[[internal selected track index]]}}. 9. Assign `true` to {{ImageDecoder/[[tracks established]]}}. - 10. Queue a task on the [=control thread=] event loop to perform the - following steps: + 10. [=Queue a task=] to perform the following steps: 1. Assign |newTrackList| to the {{ImageDecoder/tracks}} {{ImageTrackList/[[track list]]}} internal slot. 2. Assign |selectedTrackIndex| to {{ImageDecoder/tracks}} @@ -4673,17 +5102,14 @@ [=track update struct/track index=] is |trackIndex| and [=track update struct/frame count=] is |latestFrameCount|. 2. Append |change| to |tracksChanges|. - 5. If |tracksChanges| is [=list/empty=], abort these steps. - 6. Queue a task on the [=control thread=] event loop to perform the - following steps: + 5. If |tracksChanges| [=list/is empty=], abort these steps. + 6. [=Queue a task=] to perform the following steps: 1. For each update in |trackChanges|: 1. Let |updateTrack| be the {{ImageTrack}} at position `update.trackIndex` within {{ImageDecoder/tracks}}' {{ImageTrackList/[[track list]]}}. 2. Assign `update.frameCount` to |updateTrack|'s {{ImageTrack/[[frame count]]}}. - 3. Fire a simple event named {{ImageTrack/change}} at the - {{ImageDecoder/tracks}} object. : Decode Complete Frame (with |frameIndex| and |promise|) @@ -4719,11 +5145,20 @@ 11. Let |decodeResult| be a new {{ImageDecodeResult}} initialized as follows: 1. Assign 'true' to {{ImageDecodeResult/complete}}. - 2. Let |timestamp| and |duration| be the presentation timestamp and - duration for |output| as described by |encodedFrame|. If - |encodedFrame| does not describe a timestamp or - duration, assign `null` to the corresponding variable. - 3. Assign {{ImageDecodeResult/image}} with the result of running the + 2. Let |duration| be the presentation duration for |output| as + described by |encodedFrame|. If |encodedFrame| does not have a + duration, assign `null` to |duration|. + 3. Let |timestamp| be the presentation timestamp for |output| as + described by |encodedFrame|. If |encodedFrame| does not have a + timestamp: + 1. If |encodedFrame| is a still image assign `0` to |timestamp|. + 2. If |encodedFrame| is a constant rate animated image and + |duration| is not `null`, assign `|frameIndex| * |duration|` to + |timestamp|. + 3. If a |timestamp| can otherwise be trivially generated from + metadata without further decoding, assign that to |timestamp|. + 4. Otherwise, assign `0` to |timestamp|. + 4. Assign {{ImageDecodeResult/image}} with the result of running the [=Create a VideoFrame=] algorithm with |output|, |timestamp|, and |duration|. 12. Run the [=ImageDecoder/Resolve Decode=] algorithm with |promise| and @@ -4776,18 +5211,27 @@ for |output|. 3. Add a new entry to {{ImageDecoder/[[progressive frame generations]]}} with key |frameIndex| and value |frameGeneration|. - 15. Let |timestamp| and |duration| be the presentation timestamp and - duration for |output| as described by |encodedFrame|. If - |encodedFrame| does not describe a timestamp or - duration, assign `null` to the corresponding variable. - 16. Assign {{ImageDecodeResult/image}} with the result of running the - [=Create a VideoFrame=] algorithm with |output|, |timestamp|, and - |duration|. - 17. Remove |promise| from {{ImageDecoder/[[pending decode promises]]}}. - 18. Resolve |promise| with |decodeResult|. + 15. Let |duration| be the presentation duration for |output| as + described by |encodedFrame|. If |encodedFrame| does not describe a + duration, assign `null` to |duration|. + 16. Let |timestamp| be the presentation timestamp for |output| as + described by |encodedFrame|. If |encodedFrame| does not have a + timestamp: + 1. If |encodedFrame| is a still image assign `0` to |timestamp|. + 2. If |encodedFrame| is a constant rate animated image and + |duration| is not `null`, assign `|frameIndex| * |duration|` to + |timestamp|. + 3. If a |timestamp| can otherwise be trivially generated from + metadata without further decoding, assign that to |timestamp|. + 4. Otherwise, assign `0` to |timestamp|. + 17. Assign {{ImageDecodeResult/image}} with the result of running the + [=Create a VideoFrame=] algorithm with |output|, |timestamp|, and + |duration|. + 18. Remove |promise| from {{ImageDecoder/[[pending decode promises]]}}. + 19. Resolve |promise| with |decodeResult|. : Resolve Decode (with |promise| and |result|) -:: 1. Queue a task on the [=control thread=] event loop to run these steps: +:: 1. [=Queue a task=] to perform these steps: 1. If {{ImageDecoder/[[closed]]}}, abort these steps. 2. Assert that |promise| is an element of {{ImageDecoder/[[pending decode promises]]}}. @@ -4800,7 +5244,7 @@ 2. If {{ImageDecoder/complete}} is `true`, let |exception| be a {{RangeError}}. Otherwise, let |exception| be an {{InvalidStateError}} {{DOMException}}. - 3. Queue a task on the [=control thread=] event loop to run these steps: + 3. [=Queue a task=] to perform these steps: 1. If {{ImageDecoder/[[closed]]}}, abort these steps. 2. Assert that |promise| is an element of {{ImageDecoder/[[pending decode promises]]}}. @@ -4808,7 +5252,7 @@ 4. Reject |promise| with |exception|. : Fatally Reject Bad Data -:: 1. Queue a task on the [=control thread=] event loop to run these steps: +:: 1. [=Queue a task=] to perform these steps: 1. If {{ImageDecoder/[[closed]]}}, abort these steps. 2. Run the [=ImageDecoder/Close ImageDecoder=] algorithm with an {{EncodingError}} {{DOMException}}. @@ -4845,11 +5289,11 @@ dictionary ImageDecoderInit { required DOMString type; required ImageBufferSource data; - PremultiplyAlpha premultiplyAlpha = "default"; ColorSpaceConversion colorSpaceConversion = "default"; [EnforceRange] unsigned long desiredWidth; [EnforceRange] unsigned long desiredHeight; boolean preferAnimation; + sequence transfer = []; }; @@ -4862,7 +5306,7 @@ 3. If |data| is of type {{BufferSource}}: 1. If the result of running IsDetachedBuffer (described in [[!ECMASCRIPT]]) on |data| is `false`, return `false`. - 2. If |data| is [=empty=], return `false`. + 2. If |data| [=list/is empty=], return `false`. 4. If {{ImageDecoderInit/desiredWidth}} [=map/exists=] and {{ImageDecoderInit/desiredHeight}} does not exist, return `false`. 5. If {{ImageDecoderInit/desiredHeight}} [=map/exists=] and @@ -4870,7 +5314,7 @@ 6. Return `true`. A valid image MIME type is a string that is a [=valid MIME type -string=] and for which the `type`, per Section 3.1.1.1 of [[RFC7231]], is +string=] and for which the `type`, per Section 8.3.1 of [[RFC9110]], is `image`. : type @@ -4880,11 +5324,6 @@ :: {{BufferSource}} or {{ReadableStream}} of bytes representing an encoded image file as described by {{ImageDecoderInit/type}}. -: premultiplyAlpha -:: Controls whether decoded outputs' color channels are to be premultiplied by - their alpha channel, as defined by {{ImageBitmapOptions/premultiplyAlpha}} - in {{ImageBitmapOptions}}. - : colorSpaceConversion :: Controls whether decoded outputs' color space is converted or ignored, as defined by {{ImageBitmapOptions/colorSpaceConversion}} in @@ -5023,11 +5462,10 @@
 
 [Exposed=(Window,DedicatedWorker)]
-interface ImageTrack : EventTarget {
+interface ImageTrack {
   readonly attribute boolean animated;
   readonly attribute unsigned long frameCount;
   readonly attribute unrestricted float repetitionCount;
-  attribute EventHandler onchange;
   attribute boolean selected;
 };
 
@@ -5072,10 +5510,6 @@
 :: The {{ImageTrack/repetitionCount}} getter steps are to return the value of
     {{ImageTrack/[[repetition count]]}}.
 
-: onchange
-:: An [=event handler IDL attribute=] whose [=event handler event type=] is
-    {{ImageTrack/change}}.
-
 : selected
 :: The {{ImageTrack/selected}} getter steps are to return the value of
     {{ImageTrack/[[selected]]}}.
@@ -5106,19 +5540,17 @@
     11. [=Queue a control message=] to {{ImageTrack/[[ImageDecoder]]}}'s
         [=control message queue=] to update the internal selected track
         index with |selectedIndex|.
+    12. [=Process the control message queue=] belonging to
+        {{ImageTrack/[[ImageDecoder]]}}.
 
     [=Running a control message=] to update the internal selected track index
     means running these steps:
-    1. Assign |selectedIndex| to
-        {{ImageDecoder/[[internal selected track index]]}}.
-    2. Remove all entries from
-        {{ImageDecoder/[[progressive frame generations]]}}.
-
-
-### Event Summary ### {#imagetracklist-eventsummary}
-
-: change
-:: Fired at the {{ImageTrack}} when the {{ImageTrack/frameCount}} is altered.
+    1. Enqueue the following steps to {{ImageTrack/[[ImageDecoder]]}}'s
+        {{ImageDecoder/[[codec work queue]]}}:
+        1. Assign |selectedIndex| to
+            {{ImageDecoder/[[internal selected track index]]}}.
+        2. Remove all entries from
+            {{ImageDecoder/[[progressive frame generations]]}}.
 
 Resource Reclamation{#resource-reclamation}
 ==============================================
@@ -5165,7 +5597,7 @@
 
     - An {{AudioDecoder}} or {{VideoDecoder}}, when there is, respectively, an
         [=active=] {{AudioEncoder}} or {{VideoEncoder}} in the same
-        [=webappapis/global object=].
+        [=/global object=].
 
         NOTE: This prevents prevents breaking long running transcoding tasks.
 
@@ -5174,11 +5606,14 @@
 Security Considerations{#security-considerations}
 =================================================
 
+
+This section is non-normative. + The primary security impact is that features of this API make it easier for an attacker to exploit vulnerabilities in the underlying platform codecs. -Additionally, new abilities to configure and control the codecs MAY allow for new exploits that rely on a specific -configuration and/or sequence of control operations. +Additionally, new abilities to configure and control the codecs can allow for +new exploits that rely on a specific configuration and/or sequence of control +operations. Platform codecs are historically an internal detail of APIs like {{HTMLMediaElement}}, [[WEBAUDIO]], and [[WebRTC]]. In this way, it has always @@ -5195,43 +5630,43 @@ affords attackers the ability to invoke sequences of control methods that were not previously possible via the higher level APIs. -User Agents SHOULD mitigate this risk by extensively +The Working Group expects User Agents to mitigate this risk by extensively fuzzing their implementation with random inputs and control method invocations. Additionally, User Agents are encouraged to isolate their underlying codecs in processes with restricted privileges (sandbox) as a barrier against successful exploits being able to read user data. An additional concern is exposing the underlying codecs to input mutation race -conditions. Specifically, it SHOULD not be possible for -a site to mutate a codec input or output while the underlying codec MAY still be operating on that data. This concern is -mitigated by ensuring that input and output interfaces are immutable. +conditions, such as allowing a site to mutate a codec input or output while +the underlying codec is still operating on that data. This concern is mitigated +by ensuring that input and output interfaces are immutable. Privacy Considerations{#privacy-considerations} =============================================== +
+This section is non-normative. + The primary privacy impact is an increased ability to fingerprint users by querying for different codec capabilities to establish a codec feature profile. Much of this profile is already exposed by existing APIs. Such profiles are very -unlikely to be uniquely identifying, but MAY be used -with other metrics to create a fingerprint. - -An attacker MAY accumulate a codec feature profile by -calling `IsConfigSupported()` methods with a number of different configuration -dictionaries. Similarly, an attacker MAY attempt to -`configure()` a codec with different configuration dictionaries and observe -which configurations are accepted. - -Attackers MAY also use existing APIs to establish much -of the codec feature profile. For example, the [[media-capabilities]] -{{decodingInfo()}} API describes what types of decoders are supported and its -{{powerEfficient}} attribute MAY signal when a decoder -uses hardware acceleration. Similarly, the [[WebRTC]] -{{RTCRtpSender/getCapabilities()}} API MAY be used to -determine what types of encoders are supported and the -{{RTCPeerConnection/getStats()}} API MAY be used to -determine when an encoder uses hardware acceleration. WebCodecs will expose some -additional information in the form of low level codec features. +unlikely to be uniquely identifying, but can be used with other metrics to +create a fingerprint. + +An attacker can accumulate a codec feature profile by calling +`IsConfigSupported()` methods with a number of different configuration +dictionaries. Similarly, an attacker can attempt to `configure()` a codec with +different configuration dictionaries and observe which configurations are +accepted. + +Attackers can also use existing APIs to establish much of the codec feature +profile. For example, the [[media-capabilities]] {{decodingInfo()}} API +describes what types of decoders are supported and its {{powerEfficient}} +attribute can signal when a decoder uses hardware acceleration. Similarly, the +[[WebRTC]] {{RTCRtpSender/getCapabilities()}} API can be used to determine what +types of encoders are supported and the {{RTCPeerConnection/getStats()}} API can +be used to determine when an encoder uses hardware acceleration. WebCodecs will +expose some additional information in the form of low level codec features. A codec feature profile alone is unlikely to be uniquely identifying. Underlying codecs are often implemented entirely in software (be it part of the User Agent @@ -5240,9 +5675,9 @@ are often implemented with hardware acceleration, but such hardware is mass produced and devices of a particular class and manufacture date (e.g. flagship phones manufactured in 2020) will often have common capabilities. There will be -outliers (some users MAY run outdated versions of -software codecs or use a rare mix of custom assembled hardware), but most of the -time a given codec feature profile is shared by a large group of users. +outliers (some users can be running outdated versions of software codecs or use +a rare mix of custom assembled hardware), but most of the time a given codec +feature profile is shared by a large group of users. Segmenting groups of users by codec feature profile still amounts to a bit of entropy that can be combined with other metrics to uniquely identify a user. @@ -5263,7 +5698,7 @@ realtime media or in contended main thread environments are encouraged to ensure their media pipelines operate in worker contexts entirely independent of the main thread where possible. For example, realtime media processing of {{VideoFrame}}s - are generally be done in a worker context. + are generally to be done in a worker context. The main thread has significant potential for high contention and jank that can go unnoticed in development, yet degrade inconsistently across devices and User @@ -5275,3 +5710,14 @@ their target frame rates, main thread workload, how their application will be embedded, and the class of devices their users will be using.
+ +Acknowledgements{#acknowledgements} +=================================== + +The editors would like to thank Alex Russell, Chris Needham, Dale Curtis, Dan +Sanders, Eugene Zemtsov, Francois Daoust, Guido Urdaneta, Harald Alvestrand, +Jan-Ivar Bruaroey, Jer Noble, Mark Foltz, Peter Thatcher, Steve Anton, Matt +Wolenetz, Rijubrata Bhaumik, Thomas Guilbert, Tuukka Toivonen, and Youenn Fablet +for their contributions to this specification. Thank you also to the many +others who contributed to the specification, including through their +participation on the mailing list and in the issues. diff --git a/mp3_codec_registration.src.html b/mp3_codec_registration.src.html index df920787..184ab396 100644 --- a/mp3_codec_registration.src.html +++ b/mp3_codec_registration.src.html @@ -7,15 +7,16 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/mp3_codec_registration.html TR: https://www.w3.org/TR/webcodecs-mp3-codec-registration/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This registration is entered into the [[webcodecs-codec-registry]]. It describes, for MP3, the (1) fully qualified codec strings, (2) - the {{AudioDecoderConfig.description}} bytes, (3) the codec-specific - {{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] bytes, and (4) - the values of {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=]. + the {{AudioDecoderConfig/description|AudioDecoderConfig.description}} bytes, + (3) the codec-specific {{EncodedAudioChunk}} + {{EncodedAudioChunk/[[internal data]]}} bytes, and (4) + the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}}. The registration is not intended to include any information on whether a codec format is encumbered by intellectual property claims. Implementers and @@ -31,21 +32,6 @@ !Version History: https://github.com/w3c/webcodecs/commits
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-        text: AudioDecoderConfig.sampleRate; url: dom-audiodecoderconfig-samplerate
-        text: AudioDecoderConfig.numberOfChannels; url: dom-audiodecoderconfig-numberofchannels
-    type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-
 {
@@ -72,31 +58,36 @@
 EncodedAudioChunk data {#encodedaudiochunk-data}
 ================================================
 
-{{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] is expected to be
+{{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}} is expected to be
 a "frame", as described in the section 2.4.2.2 of the [[MP3]] specification.
 
 AudioDecoderConfig description {#audiodecoderconfig-description}
 ================================================================
 
-{{AudioDecoderConfig.description}} is not used for this codec.
+{{AudioDecoderConfig/description}} is not used for this codec.
 
-The {{AudioDecoderConfig.sampleRate}} and {{AudioDecoderConfig.numberOfChannels}}
+The {{AudioDecoderConfig/sampleRate}} and {{AudioDecoderConfig/numberOfChannels}}
 members are ignored.
 
 
 EncodedAudioChunk type {#encodedaudiochunk-type}
 ================================================
 
-The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing
-mp3 is always "[=EncodedAudioChunkType/key=]".
+The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing
+mp3 is always "{{EncodedAudioChunkType/key}}".
 
 NOTE: Once the initialization has succeeded, any mp3 packet can be decoded at
     any time without error, but this might not result in the expected audio
     output.
 
-Privacy and Security Considerations {#privacy-and-security-considerations}
+Privacy Considerations {#privacy-considerations}
+==========================================================================
+
+Please refer to the section [[WEBCODECS#privacy-considerations|Privacy
+Considerations]] in [[WEBCODECS]].
+
+Security Considerations {#security-considerations}
 ==========================================================================
 
-Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]]
-and [[WEBCODECS#security-considerations|Security Considerations]] sections in
-[[WEBCODECS]].
+Please refer to the section [[WEBCODECS#security-considerations|Security
+Considerations]] in [[WEBCODECS]].
diff --git a/opus_codec_registration.src.html b/opus_codec_registration.src.html
index 90c46b38..65b96f2b 100644
--- a/opus_codec_registration.src.html
+++ b/opus_codec_registration.src.html
@@ -7,16 +7,16 @@
 Group: mediawg
 ED: https://w3c.github.io/webcodecs/opus_codec_registration.html
 TR: https://www.w3.org/TR/webcodecs-opus-codec-registration/
-Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/
 Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/
+Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 
 Abstract: This registration is entered into the [[webcodecs-codec-registry]].
     It describes, for Opus, the (1) fully qualified codec strings, (2) the
-    codec-specific {{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=]
-    bytes, (3) the {{AudioDecoderConfig.description}} bytes, (4) the values of
-    {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=], and (5) the
-    codec-specific extensions to {{AudioEncoderConfig}}
+    codec-specific {{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}}
+    bytes, (3) the {{AudioDecoderConfig/description|AudioDecoderConfig.description}}
+    bytes, (4) the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}},
+    and (5) the codec-specific extensions to {{AudioEncoderConfig}}
 
     The registration is not intended to include any information on whether a
     codec format is encumbered by intellectual property claims. Implementers and
@@ -32,22 +32,6 @@
 !Version History: https://github.com/w3c/webcodecs/commits
 
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-    type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: method
-        for: AudioDecoder; text: AudioDecoder.decode; url: dom-audiodecoder-decode
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-        text: AudioEncoderConfig; url: dictdef-audioencoderconfig
-
 {
@@ -87,25 +71,25 @@
 AudioDecoderConfig description {#audiodecoderconfig-description}
 ================================================================
 
-{{AudioDecoderConfig.description}} can optionally set to an Identification
+{{AudioDecoderConfig/description}} can optionally set to an Identification
 Header, described in section 5.1 of [[OPUS-IN-OGG]].
 
-If an {{AudioDecoderConfig.description}} has been set, the bistream is assumed
+If a {{AudioDecoderConfig/description}} has been set, the bistream is assumed
 to be in {{OpusBitstreamFormat/ogg}} format.
 
-If an {{AudioDecoderConfig.description}} has not been set, the bitstream is
+If a {{AudioDecoderConfig/description}} has not been set, the bitstream is
 assumed to be in {{OpusBitstreamFormat/opus}} format.
 
 EncodedAudioChunk type {#encodedaudiochunk-type}
 ================================================
 
-The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing
-Opus is always "[=EncodedAudioChunkType/key=]".
+The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing
+Opus is always "{{EncodedAudioChunkType/key}}".
 
 NOTE: Once the initialization has succeeded, any packet can be decoded at any
 time without error, but this might not result in the expected audio output.
 
-AudiEncoderConfig extensions {#audioencoderconfig-extensions}
+AudioEncoderConfig extensions {#audioencoderconfig-extensions}
 =============================================================
 
 
@@ -131,16 +115,60 @@
 
 dictionary OpusEncoderConfig {
   OpusBitstreamFormat format = "opus";
+  [EnforceRange] unsigned long long frameDuration = 20000;
+  [EnforceRange] unsigned long complexity;
+  [EnforceRange] unsigned long packetlossperc = 0;
+  boolean useinbandfec = false;
+  boolean usedtx = false;
 };
 
 
+To check if an {{OpusEncoderConfig}} is valid, run these steps: +1. If {{OpusEncoderConfig/frameDuration}} is not a valid frame duration, + which is described section 2.1.4 of [[RFC6716]], return `false`. +1. If {{OpusEncoderConfig/complexity}} is specified and not within the range of + `0` and `10` inclusively, return `false`. +1. If {{OpusEncoderConfig/packetlossperc}} is specified and not within the range of + `0` and `100` inclusively, return `false`. +2. Return `true`. +
format
Configures the format of output {{EncodedAudioChunk}}s. See {{OpusBitstreamFormat}}.
+
frameDuration
+
+ Configures the frame duration, in microseconds, of output {{EncodedAudioChunk}}s. +
+
complexity
+
+ Configures the encoder's computational complexity, as described in section 2.1.9. + of [[RFC6716]]. The valid range is `0` to `10`, with `10` representing the highest + complexity. If no value is specificied, the default value is platform-specific: + User Agents SHOULD set a default of `5` for mobile + platforms, and a default of `9` for all other platforms. +
+
packetlossperc
+
+ Configures the encoder's expected packet loss percentage. The valid range is + `0` to `100`. + + NOTE: The packet loss percentage might be updated over the course of an + encoding, and it is recommended for User Agents to support these reconfigurations. +
+
useinbandfec
+
+ Specifies whether the encoder provides Opus in-band Forward Error Correction + (FEC), as described by section 2.1.7. of [[RFC6716]]. +
+
usedtx
+
+ Specifies if the encoder uses Discontinuous Transmission (DTX), as described + by section 2.1.9. of [[RFC6716]]. +
OpusBitstreamFormat {#opus-bitstream-format} @@ -165,13 +193,18 @@
ogg
The metadata of the encoded audio stream are provided at configuration via - {{AudioDecoderConfig.description}}. + {{AudioDecoderConfig/description|AudioDecoderConfig.description}}.
-Privacy and Security Considerations {#privacy-and-security-considerations} +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/pcm_codec_registration.src.html b/pcm_codec_registration.src.html index 0d6698af..663c6780 100644 --- a/pcm_codec_registration.src.html +++ b/pcm_codec_registration.src.html @@ -7,16 +7,16 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/pcm_codec_registration.html TR: https://www.w3.org/TR/webcodecs-pcm-codec-registration/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This registration is entered into the [[webcodecs-codec-registry]]. It describes, for Linear PCM, the (1) fully qualified codec strings, (2) the codec-specific {{EncodedAudioChunk}} - [=EncodedAudioChunk/[[internal data]]=] bytes, (3) the - {{AudioDecoderConfig.description}}, and (4) the values of - {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=]. + {{EncodedAudioChunk/[[internal data]]}} bytes, (3) the + {{AudioDecoderConfig/description|AudioDecoderConfig.description}}, and + (4) the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}}. Linear PCM is the [[webcodecs#audio-sample-formats|raw audio format]] used in WebCodecs and does not require decoding. The motivation for registering @@ -38,28 +38,8 @@
 spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
     type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-        text: sample; url: sample
         text: interleaved; url: interleaved
-        text: section on sample magnitude; url: audio-samples-magnitude
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-        text: AudioData; url: audiodata-interface
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-        text: AudioEncoderConfig; url: dictdef-audioencoderconfig
-    type: enum
-        text: AudioSampleFormat; url: enumdef-audiosampleformat
-        text: u8; url: dom-audiosampleformat-u8
-        text: s16; url: dom-audiosampleformat-s16
-        text: s24; url: dom-audiosampleformat-s24
-        text: s32; url: dom-audiosampleformat-s32
-        text: f32; url: dom-audiosampleformat-f32
 
@@ -80,7 +60,7 @@ NOTE: [[WEBCODECS]] does not define a 24-bit {{AudioSampleFormat}}. 24-bit samples are permitted within an {{EncodedAudioChunk}}, but such samples will be "decoded" in {{AudioData}} objects as either {{s32}} of {{f32}}. Please - see [[WEBCODECS]] [=section on sample magnitude=] for addtional details. + see [[WEBCODECS#audio-samples-magnitude]] for additional details. EncodedAudioChunk data {#encodedaudiochunk-data} ================================================ @@ -89,7 +69,7 @@ values are sampled at a regular interval, and where the quantization levels between two successive values are linearly uniform. -{{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] is expected to be +{{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}} is expected to be a sequence of bytes of arbitrary length, with a [=sample=] occuring every N bits, where N is defined by the codec string. For multichannel PCM, [=samples=] from different channels are [=interleaved=]. @@ -98,18 +78,23 @@ AudioDecoderConfig description {#audiodecoderconfig-description} ================================================================ -An {{AudioDecoderConfig.description}} is expected to be omitted from the +The {{AudioDecoderConfig/description}} is expected to be omitted from the {{AudioDecoderConfig}}. EncodedAudioChunk type {#encodedaudiochunk-type} ================================================ -The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing -Linear PCM is always "[=EncodedAudioChunkType/key=]". +The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing +Linear PCM is always "{{EncodedAudioChunkType/key}}". -Privacy and Security Considerations {#privacy-and-security-considerations} +Privacy Considerations {#privacy-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]]. diff --git a/samples/README.md b/samples/README.md index 68980b2c..54cc85db 100644 --- a/samples/README.md +++ b/samples/README.md @@ -1,6 +1,6 @@ # Samples -Try out our [WebCodecs samples](https://w3c.github.io/webcodecs/samples/). +Try out our [WebCodecs samples](https://webcodecs-samples.netlify.app/). Please make sure you are using the latest version of Chrome Canary to run these pages, as the latest API changes might not have made it to Chrome Stable. diff --git a/samples/_headers b/samples/_headers new file mode 100644 index 00000000..f47c3755 --- /dev/null +++ b/samples/_headers @@ -0,0 +1,4 @@ +/* + Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp + diff --git a/samples/audio-video-player/audio_video_player.html b/samples/audio-video-player/audio_video_player.html new file mode 100644 index 00000000..c6c8a47b --- /dev/null +++ b/samples/audio-video-player/audio_video_player.html @@ -0,0 +1,185 @@ + + +
+

+ This sample combines WebCodecs and WebAudio to create a media player that + renders synchronized audio and video. +

+

+ Check out the Video Decoding and Display + demo for a simpler introduction to video decoding and rendering. View + this video presentation + for an overview of audio rendering stack. +

+

+ This sample requires + cross origin isolation to use + SharedArrayBuffer. You may use + node server.js to host this sample locally + with the appropriate HTTP headers. +

+
+

+ Video Codec: + + + + + +

+ + + +
+ +
+ + diff --git a/samples/audio-video-player/media_worker.js b/samples/audio-video-player/media_worker.js new file mode 100644 index 00000000..5630573e --- /dev/null +++ b/samples/audio-video-player/media_worker.js @@ -0,0 +1,90 @@ +// The "media worker" houses and drives the AudioRenderer and VideoRenderer +// classes to perform demuxing and decoder I/O on a background worker thread. +console.info(`Worker started`); + +// Ideally we would use the static import { module } from ... syntax for this +// and the modules below. But presently mp4box.js does not use ES6 modules, +// so we import it as an old-style script and use the dynamic import() to load +// our modules below. +importScripts('../third_party/mp4boxjs/mp4box.all.min.js'); +let moduleLoadedResolver = null; +let modulesReady = new Promise(resolver => (moduleLoadedResolver = resolver)); +let playing = false +let audioRenderer = null; +let videoRenderer = null; +let lastMediaTimeSecs = 0; +let lastMediaTimeCapturePoint = 0; + +(async () => { + let audioImport = import('../lib/audio_renderer.js'); + let videoImport = import('../lib/video_renderer.js'); + Promise.all([audioImport, videoImport]).then((modules) => { + audioRenderer = new modules[0].AudioRenderer(); + videoRenderer = new modules[1].VideoRenderer(); + moduleLoadedResolver(); + moduleLoadedResolver = null; + console.info('Worker modules imported'); + }) +})(); + +function updateMediaTime(mediaTimeSecs, capturedAtHighResTimestamp) { + lastMediaTimeSecs = mediaTimeSecs; + // Translate into Worker's time origin + lastMediaTimeCapturePoint = + capturedAtHighResTimestamp - performance.timeOrigin; +} + +// Estimate current media time using last given time + offset from now() +function getMediaTimeMicroSeconds() { + let msecsSinceCapture = performance.now() - lastMediaTimeCapturePoint; + return ((lastMediaTimeSecs * 1000) + msecsSinceCapture) * 1000; +} + +self.addEventListener('message', async function(e) { + await modulesReady; + + console.info(`Worker message: ${JSON.stringify(e.data)}`); + + switch (e.data.command) { + case 'initialize': + let demuxerModule = await import('./mp4_pull_demuxer.js'); + + let audioDemuxer = new demuxerModule.MP4PullDemuxer(e.data.audioFile); + let audioReady = audioRenderer.initialize(audioDemuxer); + + let videoDemuxer = new demuxerModule.MP4PullDemuxer(e.data.videoFile); + let videoReady = videoRenderer.initialize(videoDemuxer, e.data.canvas); + await Promise.all([audioReady, videoReady]); + postMessage({command: 'initialize-done', + sampleRate: audioRenderer.sampleRate, + channelCount: audioRenderer.channelCount, + sharedArrayBuffer: audioRenderer.ringbuffer.buf}); + break; + case 'play': + playing = true; + + updateMediaTime(e.data.mediaTimeSecs, + e.data.mediaTimeCapturedAtHighResTimestamp); + + audioRenderer.play(); + + self.requestAnimationFrame(function renderVideo() { + if (!playing) + return; + videoRenderer.render(getMediaTimeMicroSeconds()); + self.requestAnimationFrame(renderVideo); + }); + break; + case 'pause': + playing = false; + audioRenderer.pause(); + break; + case 'update-media-time': + updateMediaTime(e.data.mediaTimeSecs, + e.data.mediaTimeCapturedAtHighResTimestamp); + break; + default: + console.error(`Worker bad message: ${e.data}`); + } + +}); diff --git a/samples/audio-video-player/mp4_pull_demuxer.js b/samples/audio-video-player/mp4_pull_demuxer.js new file mode 100644 index 00000000..54099228 --- /dev/null +++ b/samples/audio-video-player/mp4_pull_demuxer.js @@ -0,0 +1,211 @@ +import {PullDemuxerBase, AUDIO_STREAM_TYPE, VIDEO_STREAM_TYPE} from '../lib/pull_demuxer_base.js' + +const ENABLE_DEBUG_LOGGING = false; + +function debugLog(msg) { + if (!ENABLE_DEBUG_LOGGING) { + return; + } + console.debug(msg); +} + +// Wrapper around MP4Box.js that shims pull-based demuxing on top their +// push-based API. +export class MP4PullDemuxer extends PullDemuxerBase { + constructor(fileUri) { + super(); + this.fileUri = fileUri; + } + + async initialize(streamType) { + this.source = new MP4Source(this.fileUri); + this.readySamples = []; + this._pending_read_resolver = null; + this.streamType = streamType; + + await this._tracksReady(); + + if (this.streamType == AUDIO_STREAM_TYPE) { + this._selectTrack(this.audioTrack); + } else { + this._selectTrack(this.videoTrack); + } + } + + getDecoderConfig() { + if (this.streamType == AUDIO_STREAM_TYPE) { + return { + codec: this.audioTrack.codec, + sampleRate: this.audioTrack.audio.sample_rate, + numberOfChannels: this.audioTrack.audio.channel_count, + description: this.source.getAudioSpecificConfig() + }; + } else { + return { + // Browser doesn't support parsing full vp8 codec (eg: `vp08.00.41.08`), + // they only support `vp8`. + codec: this.videoTrack.codec.startsWith('vp08') ? 'vp8' : this.videoTrack.codec, + displayWidth: this.videoTrack.track_width, + displayHeight: this.videoTrack.track_height, + description: this._getDescription(this.source.getDescriptionBox()) + } + } + } + + async getNextChunk() { + let sample = await this._readSample(); + const type = sample.is_sync ? "key" : "delta"; + const pts_us = (sample.cts * 1000000) / sample.timescale; + const duration_us = (sample.duration * 1000000) / sample.timescale; + const ChunkType = this.streamType == AUDIO_STREAM_TYPE ? EncodedAudioChunk : EncodedVideoChunk; + return new ChunkType({ + type: type, + timestamp: pts_us, + duration: duration_us, + data: sample.data + }); + } + + _getDescription(descriptionBox) { + const stream = new DataStream(undefined, 0, DataStream.BIG_ENDIAN); + descriptionBox.write(stream); + return new Uint8Array(stream.buffer, 8); // Remove the box header. + } + + async _tracksReady() { + let info = await this.source.getInfo(); + this.videoTrack = info.videoTracks[0]; + this.audioTrack = info.audioTracks[0]; + } + + _selectTrack(track) { + console.assert(!this.selectedTrack, "changing tracks is not implemented"); + this.selectedTrack = track; + this.source.selectTrack(track); + } + + async _readSample() { + console.assert(this.selectedTrack); + console.assert(!this._pending_read_resolver); + + if (this.readySamples.length) { + return Promise.resolve(this.readySamples.shift()); + } + + let promise = new Promise((resolver) => { this._pending_read_resolver = resolver; }); + console.assert(this._pending_read_resolver); + this.source.start(this._onSamples.bind(this)); + return promise; + } + + _onSamples(samples) { + const SAMPLE_BUFFER_TARGET_SIZE = 50; + + this.readySamples.push(...samples); + if (this.readySamples.length >= SAMPLE_BUFFER_TARGET_SIZE) + this.source.stop(); + + let firstSampleTime = samples[0].cts * 1000000 / samples[0].timescale ; + debugLog(`adding new ${samples.length} samples (first = ${firstSampleTime}). total = ${this.readySamples.length}`); + + if (this._pending_read_resolver) { + this._pending_read_resolver(this.readySamples.shift()); + this._pending_read_resolver = null; + } + } +} + +class MP4Source { + constructor(uri) { + this.file = MP4Box.createFile(); + this.file.onError = console.error.bind(console); + this.file.onReady = this.onReady.bind(this); + this.file.onSamples = this.onSamples.bind(this); + + debugLog('fetching file'); + fetch(uri).then(response => { + debugLog('fetch responded'); + const reader = response.body.getReader(); + let offset = 0; + let mp4File = this.file; + + function appendBuffers({done, value}) { + if(done) { + mp4File.flush(); + return; + } + let buf = value.buffer; + buf.fileStart = offset; + + offset += buf.byteLength; + + mp4File.appendBuffer(buf); + + return reader.read().then(appendBuffers); + } + + return reader.read().then(appendBuffers); + }) + + this.info = null; + this._info_resolver = null; + } + + onReady(info) { + // TODO: Generate configuration changes. + this.info = info; + + if (this._info_resolver) { + this._info_resolver(info); + this._info_resolver = null; + } + } + + getInfo() { + if (this.info) + return Promise.resolve(this.info); + + return new Promise((resolver) => { this._info_resolver = resolver; }); + } + + getDescriptionBox() { + // TODO: make sure this is coming from the right track. + const entry = this.file.moov.traks[0].mdia.minf.stbl.stsd.entries[0]; + const box = entry.avcC || entry.hvcC || entry.vpcC || entry.av1C; + if (!box) { + throw new Error("avcC, hvcC, vpcC, or av1C box not found!"); + } + return box; + } + + getAudioSpecificConfig() { + // TODO: make sure this is coming from the right track. + + // 0x04 is the DecoderConfigDescrTag. Assuming MP4Box always puts this at position 0. + console.assert(this.file.moov.traks[0].mdia.minf.stbl.stsd.entries[0].esds.esd.descs[0].tag == 0x04); + // 0x40 is the Audio OTI, per table 5 of ISO 14496-1 + console.assert(this.file.moov.traks[0].mdia.minf.stbl.stsd.entries[0].esds.esd.descs[0].oti == 0x40); + // 0x05 is the DecSpecificInfoTag + console.assert(this.file.moov.traks[0].mdia.minf.stbl.stsd.entries[0].esds.esd.descs[0].descs[0].tag == 0x05); + + return this.file.moov.traks[0].mdia.minf.stbl.stsd.entries[0].esds.esd.descs[0].descs[0].data; + } + + selectTrack(track) { + debugLog('selecting track %d', track.id); + this.file.setExtractionOptions(track.id); + } + + start(onSamples) { + this._onSamples = onSamples; + this.file.start(); + } + + stop() { + this.file.stop(); + } + + onSamples(track_id, ref, samples) { + this._onSamples(samples); + } +} diff --git a/samples/capture-to-file/webm-writer2.js b/samples/capture-to-file/webm-writer2.js index ce8e75c8..84d25315 100755 --- a/samples/capture-to-file/webm-writer2.js +++ b/samples/capture-to-file/webm-writer2.js @@ -1,3 +1,7 @@ +// Note that these two fixes have been applied: +// https://github.com/w3c/webcodecs/issues/332#issuecomment-1077442192 +// Ctrl+F for "firstCueWritten" and "MAX_CLUSTER_DURATION_MSEC" to see the changes. + /** * A tool for presenting an ArrayBuffer as a stream for writing some simple data * types. @@ -630,7 +634,7 @@ function writeEBML(buffer, bufferFileOffset, ebml) { */ let WebMWriter = function(ArrayBufferDataStream, BlobBuffer) { return function(options) { - let MAX_CLUSTER_DURATION_MSEC = 5000000, DEFAULT_TRACK_NUMBER = 1, + let MAX_CLUSTER_DURATION_MSEC = 5000, DEFAULT_TRACK_NUMBER = 1, writtenHeader = false, videoWidth = 0, videoHeight = 0, firstTimestampEver = true, earliestTimestamp = 0, @@ -972,7 +976,11 @@ let WebMWriter = function(ArrayBufferDataStream, BlobBuffer) { * CuePoints (use addCuePoint()). The seek entry for the Cues in the * SeekHead is updated. */ + let firstCueWritten = false; function writeCues() { + if(firstCueWritten) return; + firstCueWritten = true; + let ebml = {'id': 0x1C53BB6B, 'data': cues}, cuesBuffer = new ArrayBufferDataStream( diff --git a/samples/data/bbb_audio_aac_frag.mp4 b/samples/data/bbb_audio_aac_frag.mp4 new file mode 100644 index 00000000..85962bb6 Binary files /dev/null and b/samples/data/bbb_audio_aac_frag.mp4 differ diff --git a/samples/data/bbb_video_av1_frag.mp4 b/samples/data/bbb_video_av1_frag.mp4 new file mode 100644 index 00000000..56135415 Binary files /dev/null and b/samples/data/bbb_video_av1_frag.mp4 differ diff --git a/samples/data/bbb_video_avc_frag.mp4 b/samples/data/bbb_video_avc_frag.mp4 new file mode 100644 index 00000000..942d465b Binary files /dev/null and b/samples/data/bbb_video_avc_frag.mp4 differ diff --git a/samples/data/bbb_video_hevc_frag.mp4 b/samples/data/bbb_video_hevc_frag.mp4 new file mode 100644 index 00000000..671025ff Binary files /dev/null and b/samples/data/bbb_video_hevc_frag.mp4 differ diff --git a/samples/data/bbb_video_vp8_frag.mp4 b/samples/data/bbb_video_vp8_frag.mp4 new file mode 100644 index 00000000..60cccf9a Binary files /dev/null and b/samples/data/bbb_video_vp8_frag.mp4 differ diff --git a/samples/data/bbb_video_vp9_frag.mp4 b/samples/data/bbb_video_vp9_frag.mp4 new file mode 100644 index 00000000..51763339 Binary files /dev/null and b/samples/data/bbb_video_vp9_frag.mp4 differ diff --git a/samples/image-decoder/giphy.gif b/samples/data/giphy.gif similarity index 100% rename from samples/image-decoder/giphy.gif rename to samples/data/giphy.gif diff --git a/samples/encode-decode-worker/css/main.css b/samples/encode-decode-worker/css/main.css new file mode 100644 index 00000000..c79b1318 --- /dev/null +++ b/samples/encode-decode-worker/css/main.css @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +.hidden { + display: none; +} + +.highlight { + background-color: #eee; + font-size: 1.2em; + margin: 0 0 30px 0; + padding: 0.2em 1.5em; +} + +.warning { + color: red; + font-weight: 400; +} + +@media screen and (min-width: 1000px) { + /* hack! to detect non-touch devices */ + div#links a { + line-height: 0.8em; + } +} + +audio { + max-width: 100%; +} + +body { + font-family: 'Roboto', sans-serif; + font-weight: 300; + margin: 0; + padding: 1em; + word-break: break-word; +} + +button { + background-color: #d84a38; + border: none; + border-radius: 2px; + color: white; + font-family: 'Roboto', sans-serif; + font-size: 0.8em; + margin: 0 0 1em 0; + padding: 0.5em 0.7em 0.6em 0.7em; +} + +button:active { + background-color: #cf402f; +} + +button:hover { + background-color: #cf402f; +} + +button[disabled] { + color: #ccc; +} + +button[disabled]:hover { + background-color: #d84a38; +} + +canvas { + background-color: #ccc; + max-width: 100%; + width: 100%; +} + +code { + font-family: 'Roboto', sans-serif; + font-weight: 400; +} + +div#container { + margin: 0 auto 0 auto; + max-width: 60em; + padding: 1em 1.5em 1.3em 1.5em; +} + +div#links { + padding: 0.5em 0 0 0; +} + +h1 { + border-bottom: 1px solid #ccc; + font-family: 'Roboto', sans-serif; + font-weight: 500; + margin: 0 0 0.8em 0; + padding: 0 0 0.2em 0; +} + +h2 { + color: #444; + font-weight: 500; +} + +h3 { + border-top: 1px solid #eee; + color: #666; + font-weight: 500; + margin: 10px 0 10px 0; + white-space: nowrap; +} + +li { + margin: 0 0 0.4em 0; +} + +html { + /* avoid annoying page width change + when moving from the home page */ + overflow-y: scroll; +} + +img { + border: none; + max-width: 100%; +} + +input[type=radio] { + position: relative; + top: -1px; +} + +p { + color: #444; + font-weight: 300; +} + +p#data { + border-top: 1px dotted #666; + font-family: Courier New, monospace; + line-height: 1.3em; + max-height: 1000px; + overflow-y: auto; + padding: 1em 0 0 0; +} + +p.borderBelow { + border-bottom: 1px solid #aaa; + padding: 0 0 20px 0; +} + +section p:last-of-type { + margin: 0; +} + +section { + border-bottom: 1px solid #eee; + margin: 0 0 30px 0; + padding: 0 0 20px 0; +} + +section:last-of-type { + border-bottom: none; + padding: 0 0 1em 0; +} + +select { + margin: 0 1em 1em 0; + position: relative; + top: -1px; +} + +h1 span { + white-space: nowrap; +} + +a { + color: #1D6EEE; + font-weight: 300; + text-decoration: none; +} + +h1 a { + font-weight: 300; + margin: 0 10px 0 0; + white-space: nowrap; +} + +a:hover { + color: #3d85c6; + text-decoration: underline; +} + +a#viewSource { + display: block; + margin: 1.3em 0 0 0; + border-top: 1px solid #999; + padding: 1em 0 0 0; +} + +div#errorMsg p { + color: #F00; +} + +div#links a { + display: block; + line-height: 1.3em; + margin: 0 0 1.5em 0; +} + +div.outputSelector { + margin: -1.3em 0 2em 0; +} + +p.description { + margin: 0 0 0.5em 0; +} + +strong { + font-weight: 500; +} + +textarea { + resize: none; + font-family: 'Roboto', sans-serif; +} + +video { + background: #222; + margin: 0 0 20px 0; + --width: 100%; + width: var(--width); + height: calc(var(--width) * 0.75); +} + +ul { + margin: 0 0 0.5em 0; +} + +@media screen and (max-width: 650px) { + .highlight { + font-size: 1em; + margin: 0 0 20px 0; + padding: 0.2em 1em; + } + + h1 { + font-size: 24px; + } +} + +@media screen and (max-width: 550px) { + button:active { + background-color: darkRed; + } + + h1 { + font-size: 22px; + } +} + +@media screen and (max-width: 450px) { + h1 { + font-size: 20px; + } +} + + diff --git a/samples/encode-decode-worker/index.html b/samples/encode-decode-worker/index.html new file mode 100644 index 00000000..25ff87ef --- /dev/null +++ b/samples/encode-decode-worker/index.html @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + WebCodecs in Worker + + + + + + + +
+

WebCodecs in Worker

+
+ + +

+ +
+ + +
+ +
+ + +
+ +
+

Codec:

+ +
+ +
+ +
+ +
+ +
+
+ +
+

Hardware Acceleration Preference:

+ +
+ +
+ +
+
+ +
+

Latency goal:

+ +
+ +
+
+ +
+

Bitrate mode:

+ +
+ +
+
+ +
+

Scalability Mode:

+ +
+ +
+ +
+
+ +
+

Resolution:

+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+ + +
Local Video
+

+
Encoded (and Decoded) Video via WebCodecs
+

+ + + + + diff --git a/samples/encode-decode-worker/js/main.js b/samples/encode-decode-worker/js/main.js new file mode 100644 index 00000000..ed487665 --- /dev/null +++ b/samples/encode-decode-worker/js/main.js @@ -0,0 +1,292 @@ +'use strict'; + +let preferredResolution; +let mediaStream, bitrate = 100000; +let stopped = false; +let preferredCodec ="VP8"; +let mode = "L1T3"; +let latencyPref = "realtime", bitPref = "variable"; +let hw = "no-preference"; +let streamWorker; +let inputStream, outputStream; +let videoSource; +const rate = document.querySelector('#rate'); +const connectButton = document.querySelector('#connect'); +const stopButton = document.querySelector('#stop'); +const codecButtons = document.querySelector('#codecButtons'); +const resButtons = document.querySelector('#resButtons'); +const modeButtons = document.querySelector('#modeButtons'); +const hwButtons = document.querySelector('#hwButtons'); +const videoSelect = document.querySelector('select#videoSource'); +const selectors = [videoSelect]; +connectButton.disabled = false; +stopButton.disabled = true; + +videoSelect.onchange = function () { + videoSource = videoSelect.value; +}; + +const qvgaConstraints = {video: {width: 320, height: 240}}; +const vgaConstraints = {video: {width: 640, height: 480}}; +const hdConstraints = {video: {width: 1280, height: 720}}; +const fullHdConstraints = {video: {width: {min: 1920}, height: {min: 1080}}}; +const tv4KConstraints = {video: {width: {exact: 3840}, height: {exact: 2160}}}; +const cinema4KConstraints = {video: {width: {exact: 4096}, height: {exact: 2160}}}; +const eightKConstraints = {video: {width: {min: 7680}, height: {min: 4320}}}; + +let constraints = qvgaConstraints; + +function addToEventLog(text, severity = 'info') { + let log = document.querySelector('textarea'); + log.value += 'log-' + severity + ': ' + text + '\n'; + if (severity == 'fatal') stop(); +} + +function gotDevices(deviceInfos) { + // Handles being called several times to update labels. Preserve values. + const values = selectors.map(select => select.value); + selectors.forEach(select => { + while (select.firstChild) { + select.removeChild(select.firstChild); + } + }); + for (let i = 0; i !== deviceInfos.length; ++i) { + const deviceInfo = deviceInfos[i]; + const option = document.createElement('option'); + option.value = deviceInfo.deviceId; + if (deviceInfo.kind === 'videoinput') { + option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`; + videoSelect.appendChild(option); + } + } + selectors.forEach((select, selectorIndex) => { + if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) { + select.value = values[selectorIndex]; + } + }); +} + +async function getResValue(radio) { + preferredResolution = radio.value; + addToEventLog('Resolution selected: ' + preferredResolution); + switch(preferredResolution) { + case "qvga": + constraints = qvgaConstraints; + break; + case "vga": + constraints = vgaConstraints; + break; + case "hd": + constraints = hdConstraints; + break; + case "full-hd": + constraints = fullHdConstraints; + break; + case "tv4K": + constraints = tv4KConstraints; + break; + case "cinema4K": + constraints = cinema4KConstraints; + break; + case "eightK": + constraints = eightKConstraints; + break; + default: + constraints = qvgaConstraints; + break; + } + // Get a MediaStream from the webcam, and reset the resolution. + try { + //stop the tracks + if (mediaStream){ + mediaStream.getTracks().forEach(track => { + track.stop(); + }); + } + gotDevices(await navigator.mediaDevices.enumerateDevices()); + constraints.deviceId = videoSource ? {exact: videoSource} : undefined; + mediaStream = await navigator.mediaDevices.getUserMedia(constraints); + document.getElementById('inputVideo').srcObject = mediaStream; + } catch(e){ + addToEventLog(`EnumerateDevices or gUM error: ${e.message}`); + } +} + +function getPrefValue(radio) { + latencyPref = radio.value; + addToEventLog('Latency preference selected: ' + latencyPref); +} + +function getBitPrefValue(radio) { + bitPref = radio.value; + addToEventLog('Bitrate mode selected: ' + bitPref); +} + +function getCodecValue(radio) { + preferredCodec = radio.value; + addToEventLog('Codec selected: ' + preferredCodec); +} + +function getModeValue(radio) { + mode = radio.value; + addToEventLog('Mode selected: ' + mode); +} + +function getHwValue(radio) { + hw = radio.value; + addToEventLog('Hardware Acceleration preference: ' + hw); +} + +function stop() { + stopped = true; + stopButton.disabled = true; + connectButton.disabled = true; + streamWorker.postMessage({ type: "stop" }); + try { + inputStream.cancel(); + addToEventLog('inputStream cancelled'); + } catch(e) { + addToEventLog(`Could not cancel inputStream: ${e.message}`); + } + try { + outputStream.abort(); + addToEventLog('outputStream aborted'); + } catch(e) { + addToEventLog(`Could not abort outputStream: ${e.message}`); + } +} + +document.addEventListener('DOMContentLoaded', async function(event) { + if (stopped) return; + addToEventLog('DOM Content Loaded'); + + if (typeof MediaStreamTrackProcessor === 'undefined' || + typeof MediaStreamTrackGenerator === 'undefined') { + addToEventLog('Your browser does not support the experimental Mediacapture-transform API.\n' + + 'Please launch with the --enable-blink-features=WebCodecs,MediaStreamInsertableStreams flag','fatal'); + return; + } + try { + gotDevices(await navigator.mediaDevices.enumerateDevices()); + } catch (e) { + addToEventLog('Error in Device enumeration'); + } + constraints.deviceId = videoSource ? {exact: videoSource} : undefined; + // Get a MediaStream from the webcam. + mediaStream = await navigator.mediaDevices.getUserMedia(constraints); + // Connect the webcam stream to the video element. + document.getElementById('inputVideo').srcObject = mediaStream; + // Create a new worker. + streamWorker = new Worker("js/stream_worker.js"); + addToEventLog('Worker created.'); + // Print messages from the worker in the text area. + streamWorker.addEventListener('message', function(e) { + addToEventLog('Worker msg: ' + e.data.text, e.data.severity); + }, false); + + stopButton.onclick = () => { + addToEventLog('Stop button clicked.'); + stop(); + } + + connectButton.onclick = () => { + connectButton.disabled = true; + stopButton.disabled = false; + hwButtons.style.display = "none"; + prefButtons.style.display = "none"; + bitButtons.style.display = "none"; + codecButtons.style.display = "none"; + resButtons.style.display = "none"; + modeButtons.style.display = "none"; + rateInput.style.display = "none"; + keyInput.style.display = "none"; + startMedia(); + } + + async function startMedia() { + if (stopped) return; + addToEventLog('startMedia called'); + try { + // Collect the bitrate + const rate = document.getElementById('rate').value; + + // Collect the keyframe gap + const keygap = document.getElementById('keygap').value; + + // Create a MediaStreamTrackProcessor, which exposes frames from the track + // as a ReadableStream of VideoFrames, using non-standard Chrome API. + let [track] = mediaStream.getVideoTracks(); + let ts = track.getSettings(); + const processor = new MediaStreamTrackProcessor(track); + inputStream = processor.readable; + + // Create a MediaStreamTrackGenerator, which exposes a track from a + // WritableStream of VideoFrames, using non-standard Chrome API. + const generator = new MediaStreamTrackGenerator({kind: 'video'}); + outputStream = generator.writable; + document.getElementById('outputVideo').srcObject = new MediaStream([generator]); + + //Create video Encoder configuration + const vConfig = { + keyInterval: keygap, + resolutionScale: 1, + framerateScale: 1.0, + }; + + let ssrcArr = new Uint32Array(1); + window.crypto.getRandomValues(ssrcArr); + const ssrc = ssrcArr[0]; + + const config = { + alpha: "discard", + latencyMode: latencyPref, + bitrateMode: bitPref, + codec: preferredCodec, + width: ts.width/vConfig.resolutionScale, + height: ts.height/vConfig.resolutionScale, + hardwareAcceleration: hw, + bitrate: rate, + framerate: ts.frameRate/vConfig.framerateScale, + keyInterval: vConfig.keyInterval, + ssrc: ssrc + }; + + if (mode != "L1T1") { + config.scalabilityMode = mode; + } + + switch(preferredCodec){ + case "H264": + config.codec = "avc1.42002A"; // baseline profile, level 4.2 + config.avc = { format: "annexb" }; + config.pt = 1; + break; + case "H265": + config.codec = "hvc1.1.6.L123.00"; // Main profile, level 4.1, main Tier + config.hevc = { format: "annexb" }; + config.pt = 2; + break; + case "VP8": + config.codec = "vp8"; + config.pt = 3; + break; + case "VP9": + config.codec = "vp09.00.10.08"; //VP9, Profile 0, level 1, bit depth 8 + config.pt = 4; + break; + case "AV1": + config.codec = "av01.0.08M.10.0.110.09" // AV1 Main Profile, level 4.0, Main tier, 10-bit content, non-monochrome, with 4:2:0 chroma subsampling + config.pt = 5; + break; + } + + // Transfer the readable stream to the worker, as well as other info from the user interface. + // NOTE: transferring frameStream and reading it in the worker is more + // efficient than reading frameStream here and transferring VideoFrames individually. + streamWorker.postMessage({ type: "stream", config: config, streams: {input: inputStream, output: outputStream}}, [inputStream, outputStream]); + + } catch(e) { + addToEventLog(e.name + ": " + e.message, 'fatal'); + } + } +}, false); diff --git a/samples/encode-decode-worker/js/stream_worker.js b/samples/encode-decode-worker/js/stream_worker.js new file mode 100644 index 00000000..6de09350 --- /dev/null +++ b/samples/encode-decode-worker/js/stream_worker.js @@ -0,0 +1,260 @@ +'use strict'; + +let encoder, decoder, pl, started = false, stopped = false; + +let encqueue_aggregate = { + all: [], + min: Number.MAX_VALUE, + max: 0, + avg: 0, + sum: 0, +}; + +let decqueue_aggregate = { + all: [], + min: Number.MAX_VALUE, + max: 0, + avg: 0, + sum: 0, +}; + +function encqueue_update(duration) { + encqueue_aggregate.all.push(duration); + encqueue_aggregate.min = Math.min(encqueue_aggregate.min, duration); + encqueue_aggregate.max = Math.max(encqueue_aggregate.max, duration); + encqueue_aggregate.sum += duration; +} + +function encqueue_report() { + encqueue_aggregate.all.sort(); + const len = encqueue_aggregate.all.length; + const half = len >> 1; + const f = (len + 1) >> 2; + const t = (3 * (len + 1)) >> 2; + const alpha1 = (len + 1)/4 - Math.trunc((len + 1)/4); + const alpha3 = (3 * (len + 1)/4) - Math.trunc(3 * (len + 1)/4); + const fquart = encqueue_aggregate.all[f] + alpha1 * (encqueue_aggregate.all[f + 1] - encqueue_aggregate.all[f]); + const tquart = encqueue_aggregate.all[t] + alpha3 * (encqueue_aggregate.all[t + 1] - encqueue_aggregate.all[t]); + const median = len % 2 === 1 ? encqueue_aggregate.all[len >> 1] : (encqueue_aggregate.all[half - 1] + encqueue_aggregate.all[half]) / 2; + return { + count: len, + min: encqueue_aggregate.min, + fquart: fquart, + avg: encqueue_aggregate.sum / len, + median: median, + tquart: tquart, + max: encqueue_aggregate.max, + }; +} + +function decqueue_update(duration) { + decqueue_aggregate.all.push(duration); + decqueue_aggregate.min = Math.min(decqueue_aggregate.min, duration); + decqueue_aggregate.max = Math.max(decqueue_aggregate.max, duration); + decqueue_aggregate.sum += duration; +} + +function decqueue_report() { + decqueue_aggregate.all.sort(); + const len = decqueue_aggregate.all.length; + const half = len >> 1; + const f = (len + 1) >> 2; + const t = (3 * (len + 1)) >> 2; + const alpha1 = (len + 1)/4 - Math.trunc((len + 1)/4); + const alpha3 = (3 * (len + 1)/4) - Math.trunc(3 * (len + 1)/4); + const fquart = decqueue_aggregate.all[f] + alpha1 * (decqueue_aggregate.all[f + 1] - decqueue_aggregate.all[f]); + const tquart = decqueue_aggregate.all[t] + alpha3 * (decqueue_aggregate.all[t + 1] - decqueue_aggregate.all[t]); + const median = len % 2 === 1 ? decqueue_aggregate.all[len >> 1] : (decqueue_aggregate.all[half - 1] + decqueue_aggregate.all[half]) / 2; + return { + count: len, + min: decqueue_aggregate.min, + fquart: fquart, + avg: decqueue_aggregate.sum / len, + median: median, + tquart: tquart, + max: decqueue_aggregate.max, + }; +} + +self.addEventListener('message', async function(e) { + if (stopped) return; + // In this demo, we expect at most two messages, one of each type. + let type = e.data.type; + + if (type == "stop") { + self.postMessage({text: 'Stop message received.'}); + if (started) pl.stop(); + return; + } else if (type != "stream"){ + self.postMessage({severity: 'fatal', text: 'Invalid message received.'}); + return; + } + // We received a "stream" event + self.postMessage({text: 'Stream event received.'}); + + try { + pl = new pipeline(e.data); + pl.start(); + } catch (e) { + self.postMessage({severity: 'fatal', text: `Pipeline creation failed: ${e.message}`}) + return; + } +}, false); + +class pipeline { + + constructor(eventData) { + this.stopped = false; + this.inputStream = eventData.streams.input; + this.outputStream = eventData.streams.output; + this.config = eventData.config; + } + + DecodeVideoStream(self) { + return new TransformStream({ + start(controller) { + this.decoder = decoder = new VideoDecoder({ + output: frame => controller.enqueue(frame), + error: (e) => { + self.postMessage({severity: 'fatal', text: `Init Decoder error: ${e.message}`}); + } + }); + }, + transform(chunk, controller) { + if (this.decoder.state != "closed") { + if (chunk.type == "config") { + let config = JSON.parse(chunk.config); + VideoDecoder.isConfigSupported(config).then((decoderSupport) => { + if(decoderSupport.supported) { + this.decoder.configure(decoderSupport.config); + self.postMessage({text: 'Decoder successfully configured:\n' + JSON.stringify(decoderSupport.config)}); + } else { + self.postMessage({severity: 'fatal', text: 'Config not supported:\n' + JSON.stringify(decoderSupport.config)}); + } + }) + .catch((e) => { + self.postMessage({severity: 'fatal', text: `Configuration error: ${e.message}`}); + }) + } else { + try { + const queue = this.decoder.decodeQueueSize; + decqueue_update(queue); + this.decoder.decode(chunk); + } catch (e) { + self.postMessage({severity: 'fatal', text: 'Derror size: ' + chunk.byteLength + ' seq: ' + chunk.seqNo + ' kf: ' + chunk.keyframeIndex + ' delta: ' + chunk.deltaframeIndex + ' dur: ' + chunk.duration + ' ts: ' + chunk.timestamp + ' ssrc: ' + chunk.ssrc + ' pt: ' + chunk.pt + ' tid: ' + chunk.temporalLayerId + ' type: ' + chunk.type}); + self.postMessage({severity: 'fatal', text: `Catch Decode error: ${e.message}`}); + } + } + } + } + }); + } + + EncodeVideoStream(self, config) { + return new TransformStream({ + start(controller) { + this.frameCounter = 0; + this.seqNo = 0; + this.keyframeIndex = 0; + this.deltaframeIndex = 0; + this.pending_outputs = 0; + this.encoder = encoder = new VideoEncoder({ + output: (chunk, cfg) => { + if (cfg.decoderConfig) { + const decoderConfig = JSON.stringify(cfg.decoderConfig); + self.postMessage({text: 'Configuration: ' + decoderConfig}); + const configChunk = + { + type: "config", + seqNo: this.seqNo, + keyframeIndex: this.keyframeIndex, + deltaframeIndex: this.deltaframeIndex, + timestamp: 0, + pt: 0, + config: decoderConfig + }; + controller.enqueue(configChunk); + } + chunk.temporalLayerId = 0; + if (cfg.svc) { + chunk.temporalLayerId = cfg.svc.temporalLayerId; + } + this.seqNo++; + if (chunk.type == 'key') { + this.keyframeIndex++; + this.deltaframeIndex = 0; + } else { + this.deltaframeIndex++; + } + this.pending_outputs--; + chunk.seqNo = this.seqNo; + chunk.keyframeIndex = this.keyframeIndex; + chunk.deltaframeIndex = this.deltaframeIndex; + controller.enqueue(chunk); + }, + error: (e) => { + self.postMessage({severity: 'fatal', text: `Encoder error: ${e.message}`}); + } + }); + VideoEncoder.isConfigSupported(config).then((encoderSupport) => { + if(encoderSupport.supported) { + this.encoder.configure(encoderSupport.config); + self.postMessage({text: 'Encoder successfully configured:\n' + JSON.stringify(encoderSupport.config)}); + } else { + self.postMessage({severity: 'fatal', text: 'Config not supported:\n' + JSON.stringify(encoderSupport.config)}); + } + }) + .catch((e) => { + self.postMessage({severity: 'fatal', text: `Configuration error: ${e.message}`}); + }) + }, + transform(frame, controller) { + if (this.pending_outputs <= 30) { + this.pending_outputs++; + const insert_keyframe = (this.frameCounter % config.keyInterval) == 0; + this.frameCounter++; + try { + if (this.encoder.state != "closed") { + const queue = this.encoder.encodeQueueSize; + encqueue_update(queue); + this.encoder.encode(frame, { keyFrame: insert_keyframe }); + } + } catch(e) { + self.postMessage({severity: 'fatal', text: 'Encoder Error: ' + e.message}); + } + } + frame.close(); + } + }); + } + + stop() { + const encqueue_stats = encqueue_report(); + const decqueue_stats = decqueue_report(); + self.postMessage({text: 'Encoder Queue report: ' + JSON.stringify(encqueue_stats)}); + self.postMessage({text: 'Decoder Queue report: ' + JSON.stringify(decqueue_stats)}); + if (stopped) return; + stopped = true; + this.stopped = true; + self.postMessage({text: 'stop() called'}); + if (encoder.state != "closed") encoder.close(); + if (decoder.state != "closed") decoder.close(); + self.postMessage({text: 'stop(): frame, encoder and decoder closed'}); + return; + } + + async start() { + if (stopped) return; + started = true; + let duplexStream, readStream, writeStream; + self.postMessage({text: 'Start method called.'}); + try { + await this.inputStream + .pipeThrough(this.EncodeVideoStream(self,this.config)) + .pipeThrough(this.DecodeVideoStream(self)) + .pipeTo(this.outputStream); + } catch (e) { + self.postMessage({severity: 'fatal', text: `start error: ${e.message}`}); + } + } +} diff --git a/samples/image-decoder/animated-gif-renderer.html b/samples/image-decoder/animated-gif-renderer.html index 3e4c31e6..570f6c68 100644 --- a/samples/image-decoder/animated-gif-renderer.html +++ b/samples/image-decoder/animated-gif-renderer.html @@ -1,7 +1,6 @@ WebCodecs Animated GIF Renderer -

@@ -93,5 +92,5 @@ imageDecoder.decode({frameIndex: imageIndex}).then(renderImage); } -fetch('giphy.gif').then(response => decodeImage(response.body)); +fetch('../data/giphy.gif').then(response => decodeImage(response.body)); diff --git a/samples/index.html b/samples/index.html index 6a76fda1..14043a61 100644 --- a/samples/index.html +++ b/samples/index.html @@ -11,18 +11,27 @@
-
-

MP4 Decoding

-

Demuxes (using mp4box.js) and decodes an mp4 file.

-
- -
-

Capture To File

-

Reading from camera, encoding via webcodecs, and creating a webm file on disk.

-
+ + + +
+

Capture To File

+

Reading from camera, encoding via webcodecs, and creating a webm file on disk.

+
+ +
diff --git a/samples/lib/audio_renderer.js b/samples/lib/audio_renderer.js new file mode 100644 index 00000000..d386b41a --- /dev/null +++ b/samples/lib/audio_renderer.js @@ -0,0 +1,211 @@ +import { AUDIO_STREAM_TYPE } from "./pull_demuxer_base.js"; +import { RingBuffer } from "../third_party/ringbufjs/ringbuf.js"; + +const DATA_BUFFER_DECODE_TARGET_DURATION = 0.3; +const DATA_BUFFER_DURATION = 0.6; +const DECODER_QUEUE_SIZE_MAX = 5; +const ENABLE_DEBUG_LOGGING = false; + +function debugLog(msg) { + if (!ENABLE_DEBUG_LOGGING) { + return; + } + console.debug(msg); +} + +export class AudioRenderer { + async initialize(demuxer) { + this.fillInProgress = false; + this.playing = false; + + this.demuxer = demuxer; + await this.demuxer.initialize(AUDIO_STREAM_TYPE); + + this.decoder = new AudioDecoder({ + output: this.bufferAudioData.bind(this), + error: e => console.error(e) + }); + const config = this.demuxer.getDecoderConfig(); + this.sampleRate = config.sampleRate; + this.channelCount = config.numberOfChannels; + + debugLog(config); + + let support = await AudioDecoder.isConfigSupported(config); + console.assert(support.supported); + this.decoder.configure(config); + + // Initialize the ring buffer between the decoder and the real-time audio + // rendering thread. The AudioRenderer has buffer space for approximately + // 500ms of decoded audio ahead. + let sampleCountIn500ms = + DATA_BUFFER_DURATION * this.sampleRate * this.channelCount; + let sab = RingBuffer.getStorageForCapacity( + sampleCountIn500ms, + Float32Array + ); + this.ringbuffer = new RingBuffer(sab, Float32Array); + this.interleavingBuffers = []; + + this.init_resolver = null; + let promise = new Promise(resolver => (this.init_resolver = resolver)); + + this.fillDataBuffer(); + return promise; + } + + play() { + // resolves when audio has effectively started: this can take some time if using + // bluetooth, for example. + debugLog("playback start"); + this.playing = true; + this.fillDataBuffer(); + } + + pause() { + debugLog("playback stop"); + this.playing = false; + } + + async fillDataBuffer() { + // This method is called from multiple places to ensure the buffer stays + // healthy. Sometimes these calls may overlap, but at any given point only + // one call is desired. + if (this.fillInProgress) + return; + + this.fillInProgress = true; + // This should be this file's ONLY call to the *Internal() variant of this method. + await this.fillDataBufferInternal(); + this.fillInProgress = false; + } + + async fillDataBufferInternal() { + debugLog(`fillDataBufferInternal()`); + + if (this.decoder.decodeQueueSize >= DECODER_QUEUE_SIZE_MAX) { + debugLog('\tdecoder saturated'); + // Some audio decoders are known to delay output until the next input. + // Make sure the DECODER_QUEUE_SIZE is big enough to avoid stalling on the + // return below. We're relying on decoder output callback to trigger + // another call to fillDataBuffer(). + console.assert(DECODER_QUEUE_SIZE_MAX >= 2); + return; + } + + let usedBufferElements = this.ringbuffer.capacity() - this.ringbuffer.available_write(); + let usedBufferSecs = usedBufferElements / (this.channelCount * this.sampleRate); + let pcntOfTarget = 100 * usedBufferSecs / DATA_BUFFER_DECODE_TARGET_DURATION; + if (usedBufferSecs >= DATA_BUFFER_DECODE_TARGET_DURATION) { + debugLog(`\taudio buffer full usedBufferSecs: ${usedBufferSecs} pcntOfTarget: ${pcntOfTarget}`); + + // When playing, schedule timeout to periodically refill buffer. Don't + // bother scheduling timeout if decoder already saturated. The output + // callback will call us back to keep filling. + if (this.playing) + // Timeout to arrive when buffer is half empty. + setTimeout(this.fillDataBuffer.bind(this), 1000 * usedBufferSecs / 2); + + // Initialize() is done when the buffer fills for the first time. + if (this.init_resolver) { + this.init_resolver(); + this.init_resolver = null; + } + + // Buffer full, so no further work to do now. + return; + } + + // Decode up to the buffering target or until decoder is saturated. + while (usedBufferSecs < DATA_BUFFER_DECODE_TARGET_DURATION && + this.decoder.decodeQueueSize < DECODER_QUEUE_SIZE_MAX) { + debugLog(`\tMore samples. usedBufferSecs:${usedBufferSecs} < target:${DATA_BUFFER_DECODE_TARGET_DURATION}.`); + let chunk = await this.demuxer.getNextChunk(); + this.decoder.decode(chunk); + + // NOTE: awaiting the demuxer.readSample() above will also give the + // decoder output callbacks a chance to run, so we may see usedBufferSecs + // increase. + usedBufferElements = this.ringbuffer.capacity() - this.ringbuffer.available_write(); + usedBufferSecs = usedBufferElements / (this.channelCount * this.sampleRate); + } + + if (ENABLE_DEBUG_LOGGING) { + let logPrefix = usedBufferSecs >= DATA_BUFFER_DECODE_TARGET_DURATION ? + '\tbuffered enough' : '\tdecoder saturated'; + pcntOfTarget = 100 * usedBufferSecs / DATA_BUFFER_DECODE_TARGET_DURATION; + debugLog(logPrefix + `; bufferedSecs:${usedBufferSecs} pcntOfTarget: ${pcntOfTarget}`); + } + } + + bufferHealth() { + return (1 - this.ringbuffer.available_write() / this.ringbuffer.capacity()) * 100; + } + + // From a array of Float32Array containing planar audio data `input`, writes + // interleaved audio data to `output`. Start the copy at sample + // `inputOffset`: index of the sample to start the copy from + // `inputSamplesToCopy`: number of input samples to copy + // `output`: a Float32Array to write the samples to + // `outputSampleOffset`: an offset in `output` to start writing + interleave(inputs, inputOffset, inputSamplesToCopy, output, outputSampleOffset) { + if (inputs.length * inputs[0].length < output.length) { + throw `not enough space in destination (${inputs.length * inputs[0].length} < ${output.length}})` + } + let channelCount = inputs.length; + let outIdx = outputSampleOffset; + let inputIdx = Math.floor(inputOffset / channelCount); + var channel = inputOffset % channelCount; + for (var i = 0; i < inputSamplesToCopy; i++) { + output[outIdx++] = inputs[channel][inputIdx]; + if (++channel == inputs.length) { + channel = 0; + inputIdx++; + } + } + } + + bufferAudioData(data) { + if (this.interleavingBuffers.length != data.numberOfChannels) { + this.interleavingBuffers = new Array(this.channelCount); + for (var i = 0; i < this.interleavingBuffers.length; i++) { + this.interleavingBuffers[i] = new Float32Array(data.numberOfFrames); + } + } + + debugLog(`bufferAudioData() ts:${data.timestamp} durationSec:${data.duration / 1000000}`); + // Write to temporary planar arrays, and interleave into the ring buffer. + for (var i = 0; i < this.channelCount; i++) { + data.copyTo(this.interleavingBuffers[i], { planeIndex: i }); + } + // Write the data to the ring buffer. Because it wraps around, there is + // potentially two copyTo to do. + let wrote = this.ringbuffer.writeCallback( + data.numberOfFrames * data.numberOfChannels, + (first_part, second_part) => { + this.interleave(this.interleavingBuffers, 0, first_part.length, first_part, 0); + this.interleave(this.interleavingBuffers, first_part.length, second_part.length, second_part, 0); + } + ); + + // FIXME - this could theoretically happen since we're pretty agressive + // about saturating the decoder without knowing the size of the + // AudioData.duration vs ring buffer capacity. + console.assert(wrote == data.numberOfChannels * data.numberOfFrames, 'Buffer full, dropping data!') + + // Logging maxBufferHealth below shows we currently max around 73%, so we're + // safe from the assert above *for now*. We should add an overflow buffer + // just to be safe. + // let bufferHealth = this.bufferHealth(); + // if (!('maxBufferHealth' in this)) + // this.maxBufferHealth = 0; + // if (bufferHealth > this.maxBufferHealth) { + // this.maxBufferHealth = bufferHealth; + // console.log(`new maxBufferHealth:${this.maxBufferHealth}`); + // } + + // fillDataBuffer() gives up if too much decode work is queued. Keep trying + // now that we've finished some. + this.fillDataBuffer(); + } +} diff --git a/samples/lib/audiosink.js b/samples/lib/audiosink.js new file mode 100644 index 00000000..0a0cda12 --- /dev/null +++ b/samples/lib/audiosink.js @@ -0,0 +1,30 @@ +registerProcessor("AudioSink", class AudioSink extends AudioWorkletProcessor { + constructor(options) { + super(); + let sab = options.processorOptions.sab; + this.consumerSide = new RingBuffer(sab, Float32Array); + this.mediaChannelCount = options.processorOptions.mediaChannelCount; + // https://www.w3.org/TR/webaudio/#render-quantum-size + const RENDER_QUANTUM_SIZE = 128; + this.deinterleaveBuffer = new Float32Array(this.mediaChannelCount * RENDER_QUANTUM_SIZE); + } + + // Deinterleave audio data from input (linear Float32Array) to output, an + // array of Float32Array. + deinterleave(input, output) { + let inputIdx = 0; + let outputChannelCount = output.length; + for (var i = 0; i < output[0].length; i++) { + for (var j = 0; j < outputChannelCount; j++) { + output[j][i] = input[inputIdx++]; + } + } + } + process(inputs, outputs, params) { + if (this.consumerSide.pop(this.deinterleaveBuffer) != this.deinterleaveBuffer.length) { + console.log("Warning: audio underrun"); + } + this.deinterleave(this.deinterleaveBuffer, outputs[0]); + return true; + } +}); diff --git a/samples/lib/pull_demuxer_base.js b/samples/lib/pull_demuxer_base.js new file mode 100644 index 00000000..f691c565 --- /dev/null +++ b/samples/lib/pull_demuxer_base.js @@ -0,0 +1,20 @@ +// Constants passed to initialize() to indicate which stream should be demuxed. +export const AUDIO_STREAM_TYPE = 0; +export const VIDEO_STREAM_TYPE = 1; + + +// Interface to be extended by concrete demuxer implementations. +export class PullDemuxerBase { + + // Starts fetching file. Resolves when enough of the file is fetched/parsed to + // populate getDecoderConfig(). + async initialize(streamType) {} + + // Returns either an AudioDecoderConfig or VideoDecoderConfig based on the + // streamType passed to initialize(). + getDecoderConfig() {} + + // Returns either EncodedAudioChunks or EncodedVideoChunks based on the + // streamType passed to initialize(). Returns null after EOF. + async getNextChunk() {} +} \ No newline at end of file diff --git a/samples/lib/video_renderer.js b/samples/lib/video_renderer.js new file mode 100644 index 00000000..13b505b1 --- /dev/null +++ b/samples/lib/video_renderer.js @@ -0,0 +1,134 @@ +import { VIDEO_STREAM_TYPE } from "./pull_demuxer_base.js"; +import { MP4PullDemuxer } from "../audio-video-player/mp4_pull_demuxer.js"; + +const FRAME_BUFFER_TARGET_SIZE = 3; +const ENABLE_DEBUG_LOGGING = false; + +function debugLog(msg) { + if (!ENABLE_DEBUG_LOGGING) + return; + console.debug(msg); +} + +// Controls demuxing and decoding of the video track, as well as rendering +// VideoFrames to canvas. Maintains a buffer of FRAME_BUFFER_TARGET_SIZE +// decoded frames for future rendering. +export class VideoRenderer { + async initialize(demuxer, canvas) { + this.frameBuffer = []; + this.fillInProgress = false; + + this.demuxer = demuxer; + await this.demuxer.initialize(VIDEO_STREAM_TYPE); + const config = this.demuxer.getDecoderConfig(); + + this.canvas = canvas; + this.canvas.width = config.displayWidth; + this.canvas.height = config.displayHeight; + this.canvasCtx = canvas.getContext('2d'); + + this.decoder = new VideoDecoder({ + output: this.bufferFrame.bind(this), + error: e => console.error(e), + }); + + let support = await VideoDecoder.isConfigSupported(config); + console.assert(support.supported); + this.decoder.configure(config); + + this.init_resolver = null; + let promise = new Promise((resolver) => this.init_resolver = resolver ); + + this.fillFrameBuffer(); + return promise; + } + + render(timestamp) { + debugLog('render(%d)', timestamp); + let frame = this.chooseFrame(timestamp); + this.fillFrameBuffer(); + + if (frame == null) { + console.warn('VideoRenderer.render(): no frame '); + return; + } + + this.paint(frame); + } + + chooseFrame(timestamp) { + if (this.frameBuffer.length == 0) + return null; + + let minTimeDelta = Number.MAX_VALUE; + let frameIndex = -1; + + for (let i = 0; i < this.frameBuffer.length; i++) { + let time_delta = Math.abs(timestamp - this.frameBuffer[i].timestamp); + if (time_delta < minTimeDelta) { + minTimeDelta = time_delta; + frameIndex = i; + } else { + break; + } + } + + console.assert(frameIndex != -1); + + if (frameIndex > 0) + debugLog('dropping %d stale frames', frameIndex); + + for (let i = 0; i < frameIndex; i++) { + let staleFrame = this.frameBuffer.shift(); + staleFrame.close(); + } + + let chosenFrame = this.frameBuffer[0]; + debugLog('frame time delta = %dms (%d vs %d)', minTimeDelta/1000, timestamp, chosenFrame.timestamp) + return chosenFrame; + } + + async fillFrameBuffer() { + if (this.frameBufferFull()) { + debugLog('frame buffer full'); + + if (this.init_resolver) { + this.init_resolver(); + this.init_resolver = null; + } + + return; + } + + // This method can be called from multiple places and we some may already + // be awaiting a demuxer read (only one read allowed at a time). + if (this.fillInProgress) { + return false; + } + this.fillInProgress = true; + + while (this.frameBuffer.length < FRAME_BUFFER_TARGET_SIZE && + this.decoder.decodeQueueSize < FRAME_BUFFER_TARGET_SIZE) { + let chunk = await this.demuxer.getNextChunk(); + this.decoder.decode(chunk); + } + + this.fillInProgress = false; + + // Give decoder a chance to work, see if we saturated the pipeline. + setTimeout(this.fillFrameBuffer.bind(this), 0); + } + + frameBufferFull() { + return this.frameBuffer.length >= FRAME_BUFFER_TARGET_SIZE; + } + + bufferFrame(frame) { + debugLog(`bufferFrame(${frame.timestamp})`); + this.frameBuffer.push(frame); + } + + paint(frame) { + this.canvasCtx.drawImage(frame, 0, 0, this.canvas.width, this.canvas.height); + } +} diff --git a/samples/lib/web_audio_controller.js b/samples/lib/web_audio_controller.js new file mode 100644 index 00000000..ca3a3c18 --- /dev/null +++ b/samples/lib/web_audio_controller.js @@ -0,0 +1,85 @@ +const ENABLE_DEBUG_LOGGING = false; + +function debugLog(msg) { + if (!ENABLE_DEBUG_LOGGING) { + return; + } + console.debug(msg); +} + +function URLFromFiles(files) { + const promises = files.map(file => + fetch(file).then(response => response.text()) + ); + + return Promise.all(promises).then(texts => { + const text = texts.join(""); + const blob = new Blob([text], { type: "application/javascript" }); + + return URL.createObjectURL(blob); + }); +} + +// Simple wrapper class for creating AudioWorklet, connecting it to an +// AudioContext, and controlling audio playback. +export class WebAudioController { + async initialize(sampleRate, channelCount, sharedArrayBuffer) { + // Set up AudioContext to house graph of AudioNodes and control rendering. + this.audioContext = new AudioContext({ + sampleRate: sampleRate, + latencyHint: "playback" + }); + this.audioContext.suspend(); + + // Make script modules available for execution by AudioWorklet. + var workletSource = await URLFromFiles(["../third_party/ringbufjs/ringbuf.js", "../lib/audiosink.js"]); + await this.audioContext.audioWorklet.addModule(workletSource); + + // Get an instance of the AudioSink worklet, passing it the memory for a + // ringbuffer, connect it to a GainNode for volume. This GainNode is in + // turn connected to the destination. + this.audioSink = new AudioWorkletNode(this.audioContext, "AudioSink", { + processorOptions: { + sab: sharedArrayBuffer, + mediaChannelCount: channelCount + }, + outputChannelCount: [channelCount] + }); + this.volumeGainNode = new GainNode(this.audioContext); + this.audioSink.connect(this.volumeGainNode).connect(this.audioContext.destination); + } + + setVolume(volume) { + if (volume < 0.0 && volume > 1.0) + return; + + // Smooth exponential volume ramps on change + this.volumeGainNode.gain.setTargetAtTime( + volume, + this.audioContext.currentTime, + 0.3 + ); + } + + async play() { + return this.audioContext.resume(); + } + + async pause() { + return this.audioContext.suspend(); + } + + getMediaTimeInSeconds() { + // The currently rendered audio sample is the current time of the + // AudioContext, offset by the total output latency, that is composed of + // the internal buffering of the AudioContext (e.g., double buffering), and + // the inherent latency of the audio playback system: OS buffering, + // hardware buffering, etc. This starts out negative, because it takes some + // time to buffer, and crosses zero as the first audio sample is produced + // by the audio output device. + let totalOutputLatency = + this.audioContext.outputLatency + this.audioContext.baseLatency; + + return Math.max(this.audioContext.currentTime - totalOutputLatency, 0.0); + } +} diff --git a/samples/media/bbb.mp4 b/samples/media/bbb.mp4 deleted file mode 100644 index 949aad11..00000000 Binary files a/samples/media/bbb.mp4 and /dev/null differ diff --git a/samples/mp4-decode/demux_decode_worker.js b/samples/mp4-decode/demux_decode_worker.js deleted file mode 100644 index c1ee333d..00000000 --- a/samples/mp4-decode/demux_decode_worker.js +++ /dev/null @@ -1,49 +0,0 @@ -importScripts('./mp4box.all.min.js'); -importScripts('./mp4_demuxer.js'); - -self.addEventListener('message', function(e) { - let offscreen = e.data.canvas; - let ctx = offscreen.getContext('2d'); - let startTime = 0; - let frameCount = 0; - - let demuxer = new MP4Demuxer("/webcodecs/samples/media/bbb.mp4"); - - function getFrameStats() { - let now = performance.now(); - let fps = ""; - - if (frameCount++) { - let elapsed = now - startTime; - fps = " (" + (1000.0 * frameCount / (elapsed)).toFixed(0) + " fps)" - } else { - // This is the first frame. - startTime = now; - } - - return "Extracted " + frameCount + " frames" + fps; - } - - let decoder = new VideoDecoder({ - output : frame => { - ctx.drawImage(frame, 0, 0, offscreen.width, offscreen.height); - - // Close ASAP. - frame.close(); - - // Draw some optional stats. - ctx.font = '35px sans-serif'; - ctx.fillStyle = "#ffffff"; - ctx.fillText(getFrameStats(), 40, 40, offscreen.width); - }, - error : e => console.error(e), - }); - - demuxer.getConfig().then((config) => { - offscreen.height = config.codedHeight; - offscreen.width = config.codedWidth; - - decoder.configure(config); - demuxer.start((chunk) => { decoder.decode(chunk); }) - }); -}) diff --git a/samples/mp4-decode/index.html b/samples/mp4-decode/index.html deleted file mode 100644 index d2dcef8a..00000000 --- a/samples/mp4-decode/index.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - WebCodec MP4 frame extration demo - - - -

- This demo extracts all frames from an MP4 file and renders them to a canvas as fast as possible. It uses mp4box.js to parse and demux the file. -

- - - - - - - diff --git a/samples/mp4-decode/mp4_demuxer.js b/samples/mp4-decode/mp4_demuxer.js deleted file mode 100644 index 6b8d528a..00000000 --- a/samples/mp4-decode/mp4_demuxer.js +++ /dev/null @@ -1,173 +0,0 @@ -class MP4Source { - constructor(uri) { - this.file = MP4Box.createFile(); - this.file.onError = console.error.bind(console); - this.file.onReady = this.onReady.bind(this); - this.file.onSamples = this.onSamples.bind(this); - - fetch(uri).then(response => { - const reader = response.body.getReader(); - let offset = 0; - let mp4File = this.file; - - function appendBuffers({done, value}) { - if(done) { - mp4File.flush(); - return; - } - - let buf = value.buffer; - buf.fileStart = offset; - - offset += buf.byteLength; - - mp4File.appendBuffer(buf); - - return reader.read().then(appendBuffers); - } - - return reader.read().then(appendBuffers); - }) - - this.info = null; - this._info_resolver = null; - } - - onReady(info) { - // TODO: Generate configuration changes. - this.info = info; - - if (this._info_resolver) { - this._info_resolver(info); - this._info_resolver = null; - } - } - - getInfo() { - if (this.info) - return Promise.resolve(this.info); - - return new Promise((resolver) => { this._info_resolver = resolver; }); - } - - getAvccBox() { - // TODO: make sure this is coming from the right track. - return this.file.moov.traks[0].mdia.minf.stbl.stsd.entries[0].avcC - } - - start(track, onChunk) { - this._onChunk = onChunk; - this.file.setExtractionOptions(track.id); - this.file.start(); - } - - onSamples(track_id, ref, samples) { - for (const sample of samples) { - const type = sample.is_sync ? "key" : "delta"; - - const chunk = new EncodedVideoChunk({ - type: type, - timestamp: sample.cts, - duration: sample.duration, - data: sample.data - }); - - this._onChunk(chunk); - } - } -} - -class Writer { - constructor(size) { - this.data = new Uint8Array(size); - this.idx = 0; - this.size = size; - } - - getData() { - if(this.idx != this.size) - throw "Mismatch between size reserved and sized used" - - return this.data.slice(0, this.idx); - } - - writeUint8(value) { - this.data.set([value], this.idx); - this.idx++; - } - - writeUint16(value) { - // TODO: find a more elegant solution to endianess. - var arr = new Uint16Array(1); - arr[0] = value; - var buffer = new Uint8Array(arr.buffer); - this.data.set([buffer[1], buffer[0]], this.idx); - this.idx +=2; - } - - writeUint8Array(value) { - this.data.set(value, this.idx); - this.idx += value.length; - } -} - -class MP4Demuxer { - constructor(uri) { - this.source = new MP4Source(uri); - } - - getExtradata(avccBox) { - var i; - var size = 7; - for (i = 0; i < avccBox.SPS.length; i++) { - // nalu length is encoded as a uint16. - size+= 2 + avccBox.SPS[i].length; - } - for (i = 0; i < avccBox.PPS.length; i++) { - // nalu length is encoded as a uint16. - size+= 2 + avccBox.PPS[i].length; - } - - var writer = new Writer(size); - - writer.writeUint8(avccBox.configurationVersion); - writer.writeUint8(avccBox.AVCProfileIndication); - writer.writeUint8(avccBox.profile_compatibility); - writer.writeUint8(avccBox.AVCLevelIndication); - writer.writeUint8(avccBox.lengthSizeMinusOne + (63<<2)); - - writer.writeUint8(avccBox.nb_SPS_nalus + (7<<5)); - for (i = 0; i < avccBox.SPS.length; i++) { - writer.writeUint16(avccBox.SPS[i].length); - writer.writeUint8Array(avccBox.SPS[i].nalu); - } - - writer.writeUint8(avccBox.nb_PPS_nalus); - for (i = 0; i < avccBox.PPS.length; i++) { - writer.writeUint16(avccBox.PPS[i].length); - writer.writeUint8Array(avccBox.PPS[i].nalu); - } - - return writer.getData(); - } - - async getConfig() { - let info = await this.source.getInfo(); - this.track = info.videoTracks[0]; - - var extradata = this.getExtradata(this.source.getAvccBox()); - - let config = { - codec: this.track.codec, - codedHeight: this.track.track_height, - codedWidth: this.track.track_width, - description: extradata, - } - - return Promise.resolve(config); - } - - start(onChunk) { - this.source.start(this.track, onChunk); - } -} diff --git a/samples/mp4-decode/mp4box.all.min.js b/samples/mp4-decode/mp4box.all.min.js deleted file mode 100644 index 0887cc9e..00000000 --- a/samples/mp4-decode/mp4box.all.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! mp4box 03-05-2021 */ - -var Log=function(){var i=new Date,r=4;return{setLogLevel:function(t){r=t==this.debug?1:t==this.info?2:t==this.warn?3:(this.error,4)},debug:function(t,e){void 0===console.debug&&(console.debug=console.log),r<=1&&console.debug("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)},log:function(t,e){this.debug(t.msg)},info:function(t,e){r<=2&&console.info("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)},warn:function(t,e){r<=3&&console.warn("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)},error:function(t,e){r<=4&&console.error("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)}}}();Log.getDurationString=function(t,e){var i;function r(t,e){for(var i=(""+t).split(".");i[0].length=this.getEndPosition()},MP4BoxStream.prototype.readAnyInt=function(t,e){var i=0;if(this.position+t<=this.buffer.byteLength){switch(t){case 1:i=e?this.dataview.getInt8(this.position):this.dataview.getUint8(this.position);break;case 2:i=e?this.dataview.getInt16(this.position):this.dataview.getUint16(this.position);break;case 3:if(e)throw"No method for reading signed 24 bits values";i=this.dataview.getUint8(this.position)<<16,i|=this.dataview.getUint8(this.position+1)<<8,i|=this.dataview.getUint8(this.position+2);break;case 4:i=e?this.dataview.getInt32(this.position):this.dataview.getUint32(this.position);break;case 8:if(e)throw"No method for reading signed 64 bits values";i=this.dataview.getUint32(this.position)<<32,i|=this.dataview.getUint32(this.position+4);break;default:throw"readInt method not implemented for size: "+t}return this.position+=t,i}throw"Not enough bytes in buffer"},MP4BoxStream.prototype.readUint8=function(){return this.readAnyInt(1,!1)},MP4BoxStream.prototype.readUint16=function(){return this.readAnyInt(2,!1)},MP4BoxStream.prototype.readUint24=function(){return this.readAnyInt(3,!1)},MP4BoxStream.prototype.readUint32=function(){return this.readAnyInt(4,!1)},MP4BoxStream.prototype.readUint64=function(){return this.readAnyInt(8,!1)},MP4BoxStream.prototype.readString=function(t){if(this.position+t<=this.buffer.byteLength){for(var e="",i=0;ithis._byteLength&&(this._byteLength=e);else{for(i<1&&(i=1);i=this._byteLength},DataStream.prototype.mapUint8Array=function(t){this._realloc(+t);var e=new Uint8Array(this._buffer,this.byteOffset+this.position,t);return this.position+=+t,e},DataStream.prototype.readInt32Array=function(t,e){t=null==t?this.byteLength-this.position/4:t;var i=new Int32Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readInt16Array=function(t,e){t=null==t?this.byteLength-this.position/2:t;var i=new Int16Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readInt8Array=function(t){t=null==t?this.byteLength-this.position:t;var e=new Int8Array(t);return DataStream.memcpy(e.buffer,0,this.buffer,this.byteOffset+this.position,t*e.BYTES_PER_ELEMENT),this.position+=e.byteLength,e},DataStream.prototype.readUint32Array=function(t,e){t=null==t?this.byteLength-this.position/4:t;var i=new Uint32Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readUint16Array=function(t,e){t=null==t?this.byteLength-this.position/2:t;var i=new Uint16Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readUint8Array=function(t){t=null==t?this.byteLength-this.position:t;var e=new Uint8Array(t);return DataStream.memcpy(e.buffer,0,this.buffer,this.byteOffset+this.position,t*e.BYTES_PER_ELEMENT),this.position+=e.byteLength,e},DataStream.prototype.readFloat64Array=function(t,e){t=null==t?this.byteLength-this.position/8:t;var i=new Float64Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readFloat32Array=function(t,e){t=null==t?this.byteLength-this.position/4:t;var i=new Float32Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readInt32=function(t){t=this._dataView.getInt32(this.position,null==t?this.endianness:t);return this.position+=4,t},DataStream.prototype.readInt16=function(t){t=this._dataView.getInt16(this.position,null==t?this.endianness:t);return this.position+=2,t},DataStream.prototype.readInt8=function(){var t=this._dataView.getInt8(this.position);return this.position+=1,t},DataStream.prototype.readUint32=function(t){t=this._dataView.getUint32(this.position,null==t?this.endianness:t);return this.position+=4,t},DataStream.prototype.readUint16=function(t){t=this._dataView.getUint16(this.position,null==t?this.endianness:t);return this.position+=2,t},DataStream.prototype.readUint8=function(){var t=this._dataView.getUint8(this.position);return this.position+=1,t},DataStream.prototype.readFloat32=function(t){t=this._dataView.getFloat32(this.position,null==t?this.endianness:t);return this.position+=4,t},DataStream.prototype.readFloat64=function(t){t=this._dataView.getFloat64(this.position,null==t?this.endianness:t);return this.position+=8,t},DataStream.endianness=0>16),this.writeUint8((65280&t)>>8),this.writeUint8(255&t)},DataStream.prototype.adjustUint32=function(t,e){var i=this.position;this.seek(t),this.writeUint32(e),this.seek(i)},DataStream.prototype.mapInt32Array=function(t,e){this._realloc(4*t);var i=new Int32Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=4*t,i},DataStream.prototype.mapInt16Array=function(t,e){this._realloc(2*t);var i=new Int16Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=2*t,i},DataStream.prototype.mapInt8Array=function(t){this._realloc(+t);var e=new Int8Array(this._buffer,this.byteOffset+this.position,t);return this.position+=+t,e},DataStream.prototype.mapUint32Array=function(t,e){this._realloc(4*t);var i=new Uint32Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=4*t,i},DataStream.prototype.mapUint16Array=function(t,e){this._realloc(2*t);var i=new Uint16Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=2*t,i},DataStream.prototype.mapFloat64Array=function(t,e){this._realloc(8*t);var i=new Float64Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=8*t,i},DataStream.prototype.mapFloat32Array=function(t,e){this._realloc(4*t);var i=new Float32Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=4*t,i};var MultiBufferStream=function(t){this.buffers=[],this.bufferIndex=-1,t&&(this.insertBuffer(t),this.bufferIndex=0)};MultiBufferStream.prototype=new DataStream(new ArrayBuffer,0,DataStream.BIG_ENDIAN),MultiBufferStream.prototype.initialized=function(){var t;return-1r.byteLength){this.buffers.splice(i,1),i--;continue}Log.warn("MultiBufferStream","Buffer (fileStart: "+t.fileStart+" - Length: "+t.byteLength+") already appended, ignoring")}else t.fileStart+t.byteLength<=r.fileStart||(t=this.reduceBuffer(t,0,r.fileStart-t.fileStart)),Log.debug("MultiBufferStream","Appending new buffer (fileStart: "+t.fileStart+" - Length: "+t.byteLength+")"),this.buffers.splice(i,0,t),0===i&&(this.buffer=t);e=!1;break}if(t.fileStart"+this.buffer.byteLength+")"),!0}return!1},MultiBufferStream.prototype.findPosition=function(t,e,i){for(var r=null,s=-1,a=!0===t?0:this.bufferIndex;a=e?(Log.debug("MultiBufferStream","Found position in existing buffer #"+s),s):-1},MultiBufferStream.prototype.findEndContiguousBuf=function(t){var e,i,t=void 0!==t?t:this.bufferIndex,r=this.buffers[t];if(this.buffers.length>t+1)for(e=t+1;e>3;return 31===e&&2<=i.data.length&&(e=32+((7&i.data[0])<<3)+((224&i.data[1])>>5)),e}return null},a.DecoderConfigDescriptor=function(t){a.Descriptor.call(this,4,t)},a.DecoderConfigDescriptor.prototype=new a.Descriptor,a.DecoderConfigDescriptor.prototype.parse=function(t){this.oti=t.readUint8(),this.streamType=t.readUint8(),this.bufferSize=t.readUint24(),this.maxBitrate=t.readUint32(),this.avgBitrate=t.readUint32(),this.size-=13,this.parseRemainingDescriptors(t)},a.DecoderSpecificInfo=function(t){a.Descriptor.call(this,5,t)},a.DecoderSpecificInfo.prototype=new a.Descriptor,a.SLConfigDescriptor=function(t){a.Descriptor.call(this,6,t)},a.SLConfigDescriptor.prototype=new a.Descriptor,this};"undefined"!=typeof exports&&(exports.MPEG4DescriptorParser=MPEG4DescriptorParser);var BoxParser={ERR_INVALID_DATA:-1,ERR_NOT_ENOUGH_DATA:0,OK:1,BASIC_BOXES:["mdat","idat","free","skip","meco","strk"],FULL_BOXES:["hmhd","nmhd","iods","xml ","bxml","ipro","mere"],CONTAINER_BOXES:[["moov",["trak","pssh"]],["trak"],["edts"],["mdia"],["minf"],["dinf"],["stbl",["sgpd","sbgp"]],["mvex",["trex"]],["moof",["traf"]],["traf",["trun","sgpd","sbgp"]],["vttc"],["tref"],["iref"],["mfra",["tfra"]],["meco"],["hnti"],["hinf"],["strk"],["strd"],["sinf"],["rinf"],["schi"],["trgr"],["udta",["kind"]],["iprp",["ipma"]],["ipco"]],boxCodes:[],fullBoxCodes:[],containerBoxCodes:[],sampleEntryCodes:{},sampleGroupEntryCodes:[],trackGroupTypes:[],UUIDBoxes:{},UUIDs:[],initialize:function(){BoxParser.FullBox.prototype=new BoxParser.Box,BoxParser.ContainerBox.prototype=new BoxParser.Box,BoxParser.SampleEntry.prototype=new BoxParser.Box,BoxParser.TrackGroupTypeBox.prototype=new BoxParser.FullBox,BoxParser.BASIC_BOXES.forEach(function(t){BoxParser.createBoxCtor(t)}),BoxParser.FULL_BOXES.forEach(function(t){BoxParser.createFullBoxCtor(t)}),BoxParser.CONTAINER_BOXES.forEach(function(t){BoxParser.createContainerBoxCtor(t[0],null,t[1])})},Box:function(t,e,i){this.type=t,this.size=e,this.uuid=i},FullBox:function(t,e,i){BoxParser.Box.call(this,t,e,i),this.flags=0,this.version=0},ContainerBox:function(t,e,i){BoxParser.Box.call(this,t,e,i),this.boxes=[]},SampleEntry:function(t,e,i,r){BoxParser.ContainerBox.call(this,t,e),this.hdr_size=i,this.start=r},SampleGroupEntry:function(t){this.grouping_type=t},TrackGroupTypeBox:function(t,e){BoxParser.FullBox.call(this,t,e)},createBoxCtor:function(e,t){BoxParser.boxCodes.push(e),BoxParser[e+"Box"]=function(t){BoxParser.Box.call(this,e,t)},BoxParser[e+"Box"].prototype=new BoxParser.Box,t&&(BoxParser[e+"Box"].prototype.parse=t)},createFullBoxCtor:function(e,i){BoxParser[e+"Box"]=function(t){BoxParser.FullBox.call(this,e,t)},BoxParser[e+"Box"].prototype=new BoxParser.FullBox,BoxParser[e+"Box"].prototype.parse=function(t){this.parseFullHeader(t),i&&i.call(this,t)}},addSubBoxArrays:function(t){if(t)for(var e=(this.subBoxNames=t).length,i=0;it.getEndPosition()?(t.seek(a),Log.info("BoxParser","Not enough data in stream to parse the entire '"+h+"' box"),{code:BoxParser.ERR_NOT_ENOUGH_DATA,type:h,size:o,hdr_size:n,start:a}):e?{code:BoxParser.OK,type:h,size:o,hdr_size:n,start:a}:(BoxParser[h+"Box"]?r=new BoxParser[h+"Box"](o):"uuid"!==h?(Log.warn("BoxParser","Unknown box type: '"+h+"'"),(r=new BoxParser.Box(h,o)).has_unparsed_data=!0):BoxParser.UUIDBoxes[s]?r=new BoxParser.UUIDBoxes[s](o):(Log.warn("BoxParser","Unknown uuid type: '"+s+"'"),(r=new BoxParser.Box(h,o)).uuid=s,r.has_unparsed_data=!0),r.hdr_size=n,r.start=a,r.write===BoxParser.Box.prototype.write&&"mdat"!==r.type&&(Log.info("BoxParser","'"+d+"' box writing not yet implemented, keeping unparsed data in memory for later write"),r.parseDataAndRewind(t)),r.parse(t),(a=t.getPosition()-(r.start+r.size))<0?(Log.warn("BoxParser","Parsing of box '"+d+"' did not read the entire indicated box data size (missing "+-a+" bytes), seeking forward"),t.seek(r.start+r.size)):0>10&31,t[1]=this.language>>5&31,t[2]=31&this.language,this.languageString=String.fromCharCode(t[0]+96,t[1]+96,t[2]+96)},BoxParser.SAMPLE_ENTRY_TYPE_VISUAL="Visual",BoxParser.SAMPLE_ENTRY_TYPE_AUDIO="Audio",BoxParser.SAMPLE_ENTRY_TYPE_HINT="Hint",BoxParser.SAMPLE_ENTRY_TYPE_METADATA="Metadata",BoxParser.SAMPLE_ENTRY_TYPE_SUBTITLE="Subtitle",BoxParser.SAMPLE_ENTRY_TYPE_SYSTEM="System",BoxParser.SAMPLE_ENTRY_TYPE_TEXT="Text",BoxParser.SampleEntry.prototype.parseHeader=function(t){t.readUint8Array(6),this.data_reference_index=t.readUint16(),this.hdr_size+=8},BoxParser.SampleEntry.prototype.parse=function(t){this.parseHeader(t),this.data=t.readUint8Array(this.size-this.hdr_size)},BoxParser.SampleEntry.prototype.parseDataAndRewind=function(t){this.parseHeader(t),this.data=t.readUint8Array(this.size-this.hdr_size),this.hdr_size-=8,t.position-=this.size-this.hdr_size},BoxParser.SampleEntry.prototype.parseFooter=function(t){BoxParser.ContainerBox.prototype.parse.call(this,t)},BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_HINT),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_METADATA),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SUBTITLE),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SYSTEM),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_TEXT),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,function(t){var e;this.parseHeader(t),t.readUint16(),t.readUint16(),t.readUint32Array(3),this.width=t.readUint16(),this.height=t.readUint16(),this.horizresolution=t.readUint32(),this.vertresolution=t.readUint32(),t.readUint32(),this.frame_count=t.readUint16(),e=Math.min(31,t.readUint8()),this.compressorname=t.readString(e),e<31&&t.readString(31-e),this.depth=t.readUint16(),t.readUint16(),this.parseFooter(t)}),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,function(t){this.parseHeader(t),t.readUint32Array(2),this.channel_count=t.readUint16(),this.samplesize=t.readUint16(),t.readUint16(),t.readUint16(),this.samplerate=t.readUint32()/65536,this.parseFooter(t)}),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc2"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc3"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc4"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"av01"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"hvc1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"hev1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"mp4a"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"ac-3"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"ec-3"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"encv"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"enca"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SUBTITLE,"encu"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SYSTEM,"encs"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_TEXT,"enct"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_METADATA,"encm"),BoxParser.createBoxCtor("a1lx",function(t){var e=16*(1+(1&(1&t.readUint8())));this.layer_size=[];for(var i=0;i<3;i++)this.layer_size[i]=16==e?t.readUint16():t.readUint32()}),BoxParser.createBoxCtor("a1op",function(t){this.op_index=t.readUint8()}),BoxParser.createFullBoxCtor("auxC",function(t){this.aux_type=t.readCString();var e=this.size-this.hdr_size-(this.aux_type.length+1);this.aux_subtype=t.readUint8Array(e)}),BoxParser.createBoxCtor("av1C",function(t){var e=t.readUint8();if(e>>7&!1)Log.error("av1C marker problem");else if(this.version=127&e,1===this.version)if(e=t.readUint8(),this.seq_profile=e>>5&7,this.seq_level_idx_0=31&e,e=t.readUint8(),this.seq_tier_0=e>>7&1,this.high_bitdepth=e>>6&1,this.twelve_bit=e>>5&1,this.monochrome=e>>4&1,this.chroma_subsampling_x=e>>3&1,this.chroma_subsampling_y=e>>2&1,this.chroma_sample_position=3&e,e=t.readUint8(),this.reserved_1=e>>5&7,0===this.reserved_1){if(this.initial_presentation_delay_present=e>>4&1,1===this.initial_presentation_delay_present)this.initial_presentation_delay_minus_one=15&e;else if(this.reserved_2=15&e,0!==this.reserved_2)return void Log.error("av1C reserved_2 parsing problem");e=this.size-this.hdr_size-4;this.configOBUs=t.readUint8Array(e)}else Log.error("av1C reserved_1 parsing problem");else Log.error("av1C version "+this.version+" not supported")}),BoxParser.createBoxCtor("avcC",function(t){var e,i;for(this.configurationVersion=t.readUint8(),this.AVCProfileIndication=t.readUint8(),this.profile_compatibility=t.readUint8(),this.AVCLevelIndication=t.readUint8(),this.lengthSizeMinusOne=3&t.readUint8(),this.nb_SPS_nalus=31&t.readUint8(),i=this.size-this.hdr_size-6,this.SPS=[],e=0;e>7):"rICC"!==this.colour_type&&"prof"!==this.colour_type||(this.ICC_profile=t.readUint8Array(this.size-4))}),BoxParser.createFullBoxCtor("cprt",function(t){this.parseLanguage(t),this.notice=t.readCString()}),BoxParser.createFullBoxCtor("cslg",function(t){0===this.version&&(this.compositionToDTSShift=t.readInt32(),this.leastDecodeToDisplayDelta=t.readInt32(),this.greatestDecodeToDisplayDelta=t.readInt32(),this.compositionStartTime=t.readInt32(),this.compositionEndTime=t.readInt32())}),BoxParser.createFullBoxCtor("ctts",function(t){var e,i=t.readUint32();if(this.sample_counts=[],this.sample_offsets=[],0===this.version)for(e=0;e>6,this.bsid=e>>1&31,this.bsmod=(1&e)<<2|i>>6&3,this.acmod=i>>3&7,this.lfeon=i>>2&1,this.bit_rate_code=3&i|t>>5&7}),BoxParser.createBoxCtor("dec3",function(t){var e=t.readUint16();this.data_rate=e>>3,this.num_ind_sub=7&e,this.ind_subs=[];for(var i=0;i>6,r.bsid=s>>1&31,r.bsmod=(1&s)<<4|a>>4&15,r.acmod=a>>1&7,r.lfeon=1&a,r.num_dep_sub=n>>1&15,0>12,t.readUint8Array(20)),e.push(i[s]),128&r)break}this.numMetadataBlocks=e.length+" ("+e.join(", ")+")"}),BoxParser.createBoxCtor("dimm",function(t){this.bytessent=t.readUint64()}),BoxParser.createBoxCtor("dmax",function(t){this.time=t.readUint32()}),BoxParser.createBoxCtor("dmed",function(t){this.bytessent=t.readUint64()}),BoxParser.createFullBoxCtor("dref",function(t){var e;this.entries=[];for(var i=t.readUint32(),r=0;r>6,this.general_tier_flag=(32&i)>>5,this.general_profile_idc=31&i,this.general_profile_compatibility=t.readUint32(),this.general_constraint_indicator=t.readUint8Array(6),this.general_level_idc=t.readUint8(),this.min_spatial_segmentation_idc=4095&t.readUint16(),this.parallelismType=3&t.readUint8(),this.chroma_format_idc=3&t.readUint8(),this.bit_depth_luma_minus8=7&t.readUint8(),this.bit_depth_chroma_minus8=7&t.readUint8(),this.avgFrameRate=t.readUint16(),i=t.readUint8(),this.constantFrameRate=i>>6,this.numTemporalLayers=(13&i)>>3,this.temporalIdNested=(4&i)>>2,this.lengthSizeMinusOne=3&i,this.nalu_arrays=[];for(var r=t.readUint8(),s=0;s>7,a.nalu_type=63&i;for(var n=t.readUint16(),o=0;o>4&15,this.length_size=15&e,e=t.readUint8(),this.base_offset_size=e>>4&15,1===this.version||2===this.version?this.index_size=15&e:this.index_size=0,this.items=[];var i=0;if(this.version<2)i=t.readUint16();else{if(2!==this.version)throw"version of iloc box not supported";i=t.readUint32()}for(var r=0;r>7,this.axis=1&t}),BoxParser.createFullBoxCtor("infe",function(t){return 0!==this.version&&1!==this.version||(this.item_ID=t.readUint16(),this.item_protection_index=t.readUint16(),this.item_name=t.readCString(),this.content_type=t.readCString(),this.content_encoding=t.readCString()),1===this.version?(this.extension_type=t.readString(4),Log.warn("BoxParser","Cannot parse extension type"),void t.seek(this.start+this.size)):void(2<=this.version&&(2===this.version?this.item_ID=t.readUint16():3===this.version&&(this.item_ID=t.readUint32()),this.item_protection_index=t.readUint16(),this.item_type=t.readString(4),this.item_name=t.readCString(),"mime"===this.item_type?(this.content_type=t.readCString(),this.content_encoding=t.readCString()):"uri "===this.item_type&&(this.item_uri_type=t.readCString())))}),BoxParser.createFullBoxCtor("ipma",function(t){var e,i;for(entry_count=t.readUint32(),this.associations=[],e=0;e>7==1,1&this.flags?n.property_index=(127&a)<<8|t.readUint8():n.property_index=127&a}}}),BoxParser.createFullBoxCtor("iref",function(t){var e;for(this.references=[];t.getPosition()>7,r.assignment_type=127&s,r.assignment_type){case 0:r.grouping_type=t.readString(4);break;case 1:r.grouping_type=t.readString(4),r.grouping_type_parameter=t.readUint32();break;case 2:case 3:break;case 4:r.sub_track_id=t.readUint32();break;default:Log.warn("BoxParser","Unknown leva assignement type")}}}),BoxParser.createBoxCtor("lsel",function(t){this.layer_id=t.readUint16()}),BoxParser.createBoxCtor("maxr",function(t){this.period=t.readUint32(),this.bytes=t.readUint32()}),BoxParser.createBoxCtor("mdcv",function(t){this.display_primaries=[],this.display_primaries[0]={},this.display_primaries[0].x=t.readUint16(),this.display_primaries[0].y=t.readUint16(),this.display_primaries[1]={},this.display_primaries[1].x=t.readUint16(),this.display_primaries[1].y=t.readUint16(),this.display_primaries[2]={},this.display_primaries[2].x=t.readUint16(),this.display_primaries[2].y=t.readUint16(),this.white_point={},this.white_point.x=t.readUint16(),this.white_point.y=t.readUint16(),this.max_display_mastering_luminance=t.readUint32(),this.min_display_mastering_luminance=t.readUint32()}),BoxParser.createFullBoxCtor("mdhd",function(t){1==this.version?(this.creation_time=t.readUint64(),this.modification_time=t.readUint64(),this.timescale=t.readUint32(),this.duration=t.readUint64()):(this.creation_time=t.readUint32(),this.modification_time=t.readUint32(),this.timescale=t.readUint32(),this.duration=t.readUint32()),this.parseLanguage(t),t.readUint16()}),BoxParser.createFullBoxCtor("mehd",function(t){1&this.flags&&(Log.warn("BoxParser","mehd box incorrectly uses flags set to 1, converting version to 1"),this.version=1),1==this.version?this.fragment_duration=t.readUint64():this.fragment_duration=t.readUint32()}),BoxParser.createFullBoxCtor("meta",function(t){this.boxes=[],BoxParser.ContainerBox.prototype.parse.call(this,t)}),BoxParser.createFullBoxCtor("mfhd",function(t){this.sequence_number=t.readUint32()}),BoxParser.createFullBoxCtor("mfro",function(t){this._size=t.readUint32()}),BoxParser.createFullBoxCtor("mvhd",function(t){1==this.version?(this.creation_time=t.readUint64(),this.modification_time=t.readUint64(),this.timescale=t.readUint32(),this.duration=t.readUint64()):(this.creation_time=t.readUint32(),this.modification_time=t.readUint32(),this.timescale=t.readUint32(),this.duration=t.readUint32()),this.rate=t.readUint32(),this.volume=t.readUint16()>>8,t.readUint16(),t.readUint32Array(2),this.matrix=t.readUint32Array(9),t.readUint32Array(6),this.next_track_id=t.readUint32()}),BoxParser.createBoxCtor("npck",function(t){this.packetssent=t.readUint32()}),BoxParser.createBoxCtor("nump",function(t){this.packetssent=t.readUint64()}),BoxParser.createFullBoxCtor("padb",function(t){var e=t.readUint32();this.padbits=[];for(var i=0;i>7,this.avgRateFlag=e>>6&1,this.durationFlag&&(this.duration=t.readUint32()),this.avgRateFlag&&(this.accurateStatisticsFlag=t.readUint8(),this.avgBitRate=t.readUint16(),this.avgFrameRate=t.readUint16()),this.dependency=[];for(var i=t.readUint8(),r=0;r>7,this.num_leading_samples=127&t}),BoxParser.createSampleGroupCtor("rash",function(t){if(this.operation_point_count=t.readUint16(),this.description_length!==2+(1===this.operation_point_count?2:6*this.operation_point_count)+9)Log.warn("BoxParser","Mismatch in "+this.grouping_type+" sample group length"),this.data=t.readUint8Array(this.description_length-2);else{if(1===this.operation_point_count)this.target_rate_share=t.readUint16();else{this.target_rate_share=[],this.available_bitrate=[];for(var e=0;e>4,this.skip_byte_block=15&e,this.isProtected=t.readUint8(),this.Per_Sample_IV_Size=t.readUint8(),this.KID=BoxParser.parseHex16(t),this.constant_IV_size=0,this.constant_IV=0,1===this.isProtected&&0===this.Per_Sample_IV_Size&&(this.constant_IV_size=t.readUint8(),this.constant_IV=t.readUint8Array(this.constant_IV_size))}),BoxParser.createSampleGroupCtor("stsa",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createSampleGroupCtor("sync",function(t){t=t.readUint8();this.NAL_unit_type=63&t}),BoxParser.createSampleGroupCtor("tele",function(t){t=t.readUint8();this.level_independently_decodable=t>>7}),BoxParser.createSampleGroupCtor("tsas",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createSampleGroupCtor("tscl",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createSampleGroupCtor("vipr",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createFullBoxCtor("sbgp",function(t){this.grouping_type=t.readString(4),1===this.version?this.grouping_type_parameter=t.readUint32():this.grouping_type_parameter=0,this.entries=[];for(var e=t.readUint32(),i=0;i>6,this.sample_depends_on[r]=e>>4&3,this.sample_is_depended_on[r]=e>>2&3,this.sample_has_redundancy[r]=3&e}),BoxParser.createFullBoxCtor("senc"),BoxParser.createFullBoxCtor("sgpd",function(t){this.grouping_type=t.readString(4),Log.debug("BoxParser","Found Sample Groups of type "+this.grouping_type),1===this.version?this.default_length=t.readUint32():this.default_length=0,2<=this.version&&(this.default_group_description_index=t.readUint32()),this.entries=[];for(var e=t.readUint32(),i=0;i>31&1,r.referenced_size=2147483647&s,r.subsegment_duration=t.readUint32(),s=t.readUint32(),r.starts_with_SAP=s>>31&1,r.SAP_type=s>>28&7,r.SAP_delta_time=268435455&s}}),BoxParser.SingleItemTypeReferenceBox=function(t,e,i,r){BoxParser.Box.call(this,t,e),this.hdr_size=i,this.start=r},BoxParser.SingleItemTypeReferenceBox.prototype=new BoxParser.Box,BoxParser.SingleItemTypeReferenceBox.prototype.parse=function(t){this.from_item_ID=t.readUint16();var e=t.readUint16();this.references=[];for(var i=0;i>4&15,this.sample_sizes[e+1]=15&r}else if(8===this.field_size)for(e=0;e>4&15,this.default_skip_byte_block=15&e),this.default_isProtected=t.readUint8(),this.default_Per_Sample_IV_Size=t.readUint8(),this.default_KID=BoxParser.parseHex16(t),1===this.default_isProtected&&0===this.default_Per_Sample_IV_Size&&(this.default_constant_IV_size=t.readUint8(),this.default_constant_IV=t.readUint8Array(this.default_constant_IV_size))}),BoxParser.createFullBoxCtor("tfdt",function(t){1==this.version?this.baseMediaDecodeTime=t.readUint64():this.baseMediaDecodeTime=t.readUint32()}),BoxParser.createFullBoxCtor("tfhd",function(t){var e=0;this.track_id=t.readUint32(),this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET?(this.base_data_offset=t.readUint64(),e+=8):this.base_data_offset=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_DESC?(this.default_sample_description_index=t.readUint32(),e+=4):this.default_sample_description_index=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_DUR?(this.default_sample_duration=t.readUint32(),e+=4):this.default_sample_duration=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_SIZE?(this.default_sample_size=t.readUint32(),e+=4):this.default_sample_size=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_FLAGS?(this.default_sample_flags=t.readUint32(),e+=4):this.default_sample_flags=0}),BoxParser.createFullBoxCtor("tfra",function(t){this.track_ID=t.readUint32(),t.readUint24();var e=t.readUint8();this.length_size_of_traf_num=e>>4&3,this.length_size_of_trun_num=e>>2&3,this.length_size_of_sample_num=3&e,this.entries=[];for(var i=t.readUint32(),r=0;r>8,t.readUint16(),this.matrix=t.readInt32Array(9),this.width=t.readUint32(),this.height=t.readUint32()}),BoxParser.createBoxCtor("tmax",function(t){this.time=t.readUint32()}),BoxParser.createBoxCtor("tmin",function(t){this.time=t.readUint32()}),BoxParser.createBoxCtor("totl",function(t){this.bytessent=t.readUint32()}),BoxParser.createBoxCtor("tpay",function(t){this.bytessent=t.readUint32()}),BoxParser.createBoxCtor("tpyl",function(t){this.bytessent=t.readUint64()}),BoxParser.TrackGroupTypeBox.prototype.parse=function(t){this.parseFullHeader(t),this.track_group_id=t.readUint32()},BoxParser.createTrackGroupCtor("msrc"),BoxParser.TrackReferenceTypeBox=function(t,e,i,r){BoxParser.Box.call(this,t,e),this.hdr_size=i,this.start=r},BoxParser.TrackReferenceTypeBox.prototype=new BoxParser.Box,BoxParser.TrackReferenceTypeBox.prototype.parse=function(t){this.track_ids=t.readUint32Array((this.size-this.hdr_size)/4)},BoxParser.trefBox.prototype.parse=function(t){for(var e;t.getPosition()e&&this.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET?(this.data_offset=t.readInt32(),e+=4):this.data_offset=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TRUN_FLAGS_FIRST_FLAG?(this.first_sample_flags=t.readUint32(),e+=4):this.first_sample_flags=0,this.sample_duration=[],this.sample_size=[],this.sample_flags=[],this.sample_composition_time_offset=[],this.size-this.hdr_size>e)for(var i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}),BoxParser.createUUIDBox("d08a4f1810f34a82b6c832d8aba183d3",!0,!1,function(t){this.system_id=BoxParser.parseHex16(t);var e=t.readUint32();0>4,this.chromaSubsampling=e>>1&7,this.videoFullRangeFlag=1&e,this.colourPrimaries=t.readUint8(),this.transferCharacteristics=t.readUint8(),this.matrixCoefficients=t.readUint8()):(this.profile=t.readUint8(),this.level=t.readUint8(),e=t.readUint8(),this.bitDepth=e>>4&15,this.colorSpace=15&e,e=t.readUint8(),this.chromaSubsampling=e>>4&15,this.transferFunction=e>>1&7,this.videoFullRangeFlag=1&e),this.codecIntializationDataSize=t.readUint16(),this.codecIntializationData=t.readUint8Array(this.codecIntializationDataSize)}),BoxParser.createBoxCtor("vttC",function(t){this.text=t.readString(this.size-this.hdr_size)}),BoxParser.SampleEntry.prototype.isVideo=function(){return!1},BoxParser.SampleEntry.prototype.isAudio=function(){return!1},BoxParser.SampleEntry.prototype.isSubtitle=function(){return!1},BoxParser.SampleEntry.prototype.isMetadata=function(){return!1},BoxParser.SampleEntry.prototype.isHint=function(){return!1},BoxParser.SampleEntry.prototype.getCodec=function(){return this.type.replace(".","")},BoxParser.SampleEntry.prototype.getWidth=function(){return""},BoxParser.SampleEntry.prototype.getHeight=function(){return""},BoxParser.SampleEntry.prototype.getChannelCount=function(){return""},BoxParser.SampleEntry.prototype.getSampleRate=function(){return""},BoxParser.SampleEntry.prototype.getSampleSize=function(){return""},BoxParser.VisualSampleEntry.prototype.isVideo=function(){return!0},BoxParser.VisualSampleEntry.prototype.getWidth=function(){return this.width},BoxParser.VisualSampleEntry.prototype.getHeight=function(){return this.height},BoxParser.AudioSampleEntry.prototype.isAudio=function(){return!0},BoxParser.AudioSampleEntry.prototype.getChannelCount=function(){return this.channel_count},BoxParser.AudioSampleEntry.prototype.getSampleRate=function(){return this.samplerate},BoxParser.AudioSampleEntry.prototype.getSampleSize=function(){return this.samplesize},BoxParser.SubtitleSampleEntry.prototype.isSubtitle=function(){return!0},BoxParser.MetadataSampleEntry.prototype.isMetadata=function(){return!0},BoxParser.decimalToHex=function(t,e){var i=Number(t).toString(16);for(e=null==e?e=2:e;i.length>=1;t+=BoxParser.decimalToHex(i,0),t+=".",0===this.hvcC.general_tier_flag?t+="L":t+="H",t+=this.hvcC.general_level_idc;var s=!1,a="";for(r=5;0<=r;r--)(this.hvcC.general_constraint_indicator[r]||s)&&(a="."+BoxParser.decimalToHex(this.hvcC.general_constraint_indicator[r],0)+a,s=!0);t+=a}return t},BoxParser.mp4aSampleEntry.prototype.getCodec=function(){var t=BoxParser.SampleEntry.prototype.getCodec.call(this);if(this.esds&&this.esds.esd){var e=this.esds.esd.getOTI(),i=this.esds.esd.getAudioConfig();return t+"."+BoxParser.decimalToHex(e)+(i?"."+i:"")}return t},BoxParser.stxtSampleEntry.prototype.getCodec=function(){var t=BoxParser.SampleEntry.prototype.getCodec.call(this);return this.mime_format?t+"."+this.mime_format:t},BoxParser.av01SampleEntry.prototype.getCodec=function(){var t,e=BoxParser.SampleEntry.prototype.getCodec.call(this);return 2===this.av1C.seq_profile&&1===this.av1C.high_bitdepth?t=1===this.av1C.twelve_bit?"12":"10":this.av1C.seq_profile<=2&&(t=1===this.av1C.high_bitdepth?"10":"08"),e+"."+this.av1C.seq_profile+"."+this.av1C.seq_level_idx_0+(this.av1C.seq_tier_0?"H":"M")+"."+t},BoxParser.Box.prototype.writeHeader=function(t,e){this.size+=8,this.size>MAX_SIZE&&(this.size+=8),"uuid"===this.type&&(this.size+=16),Log.debug("BoxWriter","Writing box "+this.type+" of size: "+this.size+" at position "+t.getPosition()+(e||"")),this.size>MAX_SIZE?t.writeUint32(1):(this.sizePosition=t.getPosition(),t.writeUint32(this.size)),t.writeString(this.type,null,4),"uuid"===this.type&&t.writeUint8Array(this.uuid),this.size>MAX_SIZE&&t.writeUint64(this.size)},BoxParser.FullBox.prototype.writeHeader=function(t){this.size+=4,BoxParser.Box.prototype.writeHeader.call(this,t," v="+this.version+" f="+this.flags),t.writeUint8(this.version),t.writeUint24(this.flags)},BoxParser.Box.prototype.write=function(t){"mdat"===this.type?this.data&&(this.size=this.data.length,this.writeHeader(t),t.writeUint8Array(this.data)):(this.size=this.data?this.data.length:0,this.writeHeader(t),this.data&&t.writeUint8Array(this.data))},BoxParser.ContainerBox.prototype.write=function(t){this.size=0,this.writeHeader(t);for(var e=0;ee?1:0,this.flags=0,this.size=4,1===this.version&&(this.size+=4),this.writeHeader(t),1===this.version?t.writeUint64(this.baseMediaDecodeTime):t.writeUint32(this.baseMediaDecodeTime)},BoxParser.tfhdBox.prototype.write=function(t){this.version=0,this.size=4,this.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET&&(this.size+=8),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DESC&&(this.size+=4),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DUR&&(this.size+=4),this.flags&BoxParser.TFHD_FLAG_SAMPLE_SIZE&&(this.size+=4),this.flags&BoxParser.TFHD_FLAG_SAMPLE_FLAGS&&(this.size+=4),this.writeHeader(t),t.writeUint32(this.track_id),this.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET&&t.writeUint64(this.base_data_offset),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DESC&&t.writeUint32(this.default_sample_description_index),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DUR&&t.writeUint32(this.default_sample_duration),this.flags&BoxParser.TFHD_FLAG_SAMPLE_SIZE&&t.writeUint32(this.default_sample_size),this.flags&BoxParser.TFHD_FLAG_SAMPLE_FLAGS&&t.writeUint32(this.default_sample_flags)},BoxParser.tkhdBox.prototype.write=function(t){this.version=0,this.size=80,this.writeHeader(t),t.writeUint32(this.creation_time),t.writeUint32(this.modification_time),t.writeUint32(this.track_id),t.writeUint32(0),t.writeUint32(this.duration),t.writeUint32(0),t.writeUint32(0),t.writeInt16(this.layer),t.writeInt16(this.alternate_group),t.writeInt16(this.volume<<8),t.writeUint16(0),t.writeInt32Array(this.matrix),t.writeUint32(this.width),t.writeUint32(this.height)},BoxParser.trexBox.prototype.write=function(t){this.version=0,this.flags=0,this.size=20,this.writeHeader(t),t.writeUint32(this.track_id),t.writeUint32(this.default_sample_description_index),t.writeUint32(this.default_sample_duration),t.writeUint32(this.default_sample_size),t.writeUint32(this.default_sample_flags)},BoxParser.trunBox.prototype.write=function(t){this.version=0,this.size=4,this.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET&&(this.size+=4),this.flags&BoxParser.TRUN_FLAGS_FIRST_FLAG&&(this.size+=4),this.flags&BoxParser.TRUN_FLAGS_DURATION&&(this.size+=4*this.sample_duration.length),this.flags&BoxParser.TRUN_FLAGS_SIZE&&(this.size+=4*this.sample_size.length),this.flags&BoxParser.TRUN_FLAGS_FLAGS&&(this.size+=4*this.sample_flags.length),this.flags&BoxParser.TRUN_FLAGS_CTS_OFFSET&&(this.size+=4*this.sample_composition_time_offset.length),this.writeHeader(t),t.writeUint32(this.sample_count),this.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET&&(this.data_offset_position=t.getPosition(),t.writeInt32(this.data_offset)),this.flags&BoxParser.TRUN_FLAGS_FIRST_FLAG&&t.writeUint32(this.first_sample_flags);for(var e=0;e=e?t:new Array(e-t.length+1).join(i)+t}function r(t){var e=Math.floor(t/3600),i=Math.floor((t-3600*e)/60),r=Math.floor(t-3600*e-60*i),t=Math.floor(1e3*(t-3600*e-60*i-r));return s(e,2)+":"+s(i,2)+":"+s(r,2)+"."+s(t,3)}for(var a=this.parseSample(i),n="",o=0;o=r.samples.length)&&(Log.info("ISOFile","Sending fragmented data on track #"+i.id+" for samples ["+Math.max(0,r.nextSample-i.nb_samples)+","+(r.nextSample-1)+"]"),Log.info("ISOFile","Sample data size in memory: "+this.getAllocatedSampleDataSize()),this.onSegment&&this.onSegment(i.id,i.user,i.segmentStream.buffer,r.nextSample,t||r.nextSample>=r.samples.length),i.segmentStream=null,i!==this.fragmentedTracks[e]))break}if(null!==this.onSamples)for(e=0;e=r.samples.length)&&(Log.debug("ISOFile","Sending samples on track #"+a.id+" for sample "+r.nextSample),this.onSamples&&this.onSamples(a.id,a.user,a.samples),a.samples=[],a!==this.extractedTracks[e]))break}}}},ISOFile.prototype.getBox=function(t){t=this.getBoxes(t,!0);return t.length?t[0]:null},ISOFile.prototype.getBoxes=function(t,e){var i=[];return ISOFile._sweep.call(this,t,i,e),i},ISOFile._sweep=function(t,e,i){for(var r in this.type&&this.type==t&&e.push(this),this.boxes){if(e.length&&i)return;ISOFile._sweep.call(this.boxes[r],t,e,i)}},ISOFile.prototype.getTrackSamplesInfo=function(t){t=this.getTrackById(t);if(t)return t.samples},ISOFile.prototype.getTrackSample=function(t,e){t=this.getTrackById(t);return this.getSample(t,e)},ISOFile.prototype.releaseUsedSamples=function(t,e){var i=0,r=this.getTrackById(t);r.lastValidSample||(r.lastValidSample=0);for(var s=r.lastValidSample;st*s.timescale){h=r-1;break}e&&s.is_sync&&(o=r)}for(e&&(h=o),t=i.samples[h].cts,i.nextSample=h;i.samples[h].alreadyRead===i.samples[h].size&&i.samples[h+1];)h++;return a=i.samples[h].offset+i.samples[h].alreadyRead,Log.info("ISOFile","Seeking to "+(e?"RAP":"")+" sample #"+i.nextSample+" on track "+i.tkhd.track_id+", time "+Log.getDurationString(t,n)+" and offset: "+a),{offset:a,time:t/n}},ISOFile.prototype.seek=function(t,e){var i,r,s=this.moov,a={offset:1/0,time:1/0};if(this.moov){for(r=0;r=r[s].last_sample_in_run&&(r[s].last_sample_in_run<0&&(r[s].last_sample_in_run=0),r[s].entry_index++,r[s].entry_index<=r[s].sbgp.entries.length-1&&(r[s].last_sample_in_run+=r[s].sbgp.entries[r[s].entry_index].sample_count)),r[s].entry_index<=r[s].sbgp.entries.length-1?e.sample_groups[s].group_description_index=r[s].sbgp.entries[r[s].entry_index].group_description_index:e.sample_groups[s].group_description_index=-1,0!==e.sample_groups[s].group_description_index&&(n=r[s].fragment_description||r[s].description,0>16)-1:e.sample_groups[s].group_description_index-1,n&&0<=a&&(e.sample_groups[s].description=n.entries[a])):n&&2<=n.version&&0>16&1),p.is_leading=g>>26&3,p.depends_on=g>>24&3,p.is_depended_on=g>>22&3,p.has_redundancy=g>>20&3,p.degradation_priority=65535&g;var c=!!(h.tfhd.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET),m=!!(h.tfhd.flags&BoxParser.TFHD_FLAG_DEFAULT_BASE_IS_MOOF),_=!!(f.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET),g=0,g=c?h.tfhd.base_data_offset:m||0===y?o.start:a;p.offset=0===y&&0===u?_?g+f.data_offset:g:a,a=p.offset+p.size,(0MAX_SIZE&&(this.size+=8),"uuid"===this.type&&(this.size+=16),t.log(t.indent+"size:"+this.size),t.log(t.indent+"type:"+this.type)},BoxParser.FullBox.prototype.printHeader=function(t){this.size+=4,BoxParser.Box.prototype.printHeader.call(this,t),t.log(t.indent+"version:"+this.version),t.log(t.indent+"flags:"+this.flags)},BoxParser.Box.prototype.print=function(t){this.printHeader(t)},BoxParser.ContainerBox.prototype.print=function(t){this.printHeader(t);for(var e,i=0;i>8)),t.log(t.indent+"matrix: "+this.matrix.join(", ")),t.log(t.indent+"next_track_id: "+this.next_track_id)},BoxParser.tkhdBox.prototype.print=function(t){BoxParser.FullBox.prototype.printHeader.call(this,t),t.log(t.indent+"creation_time: "+this.creation_time),t.log(t.indent+"modification_time: "+this.modification_time),t.log(t.indent+"track_id: "+this.track_id),t.log(t.indent+"duration: "+this.duration),t.log(t.indent+"volume: "+(this.volume>>8)),t.log(t.indent+"matrix: "+this.matrix.join(", ")),t.log(t.indent+"layer: "+this.layer),t.log(t.indent+"alternate_group: "+this.alternate_group),t.log(t.indent+"width: "+this.width),t.log(t.indent+"height: "+this.height)};var MP4Box={createFile:function(t,e){t=void 0===t||t,e=new ISOFile(e);return e.discardMdatData=!t,e}};"undefined"!=typeof exports&&(exports.createFile=MP4Box.createFile); -//# sourceMappingURL=mp4box.all.min.js.map \ No newline at end of file diff --git a/samples/mp4-decode/mp4box.all.min.js.map b/samples/mp4-decode/mp4box.all.min.js.map deleted file mode 100644 index 824c42f0..00000000 --- a/samples/mp4-decode/mp4box.all.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mp4box.all.min.js","sources":["mp4box.all.js"],"names":["Log","start","Date","log_level","setLogLevel","level","this","debug","info","warn","error","module","msg","undefined","console","log","getDurationString","duration","_timescale","neg","pad","number","length","a","split","join","duration_sec","hours","Math","floor","minutes","msec","printRanges","ranges","str","i","end","exports","MP4BoxStream","arrayBuffer","ArrayBuffer","buffer","dataview","DataView","position","prototype","getPosition","getEndPosition","byteLength","getLength","seek","pos","npos","max","min","isNaN","isFinite","isEos","readAnyInt","size","signed","res","getInt8","getUint8","getInt16","getUint16","getInt32","getUint32","readUint8","readUint16","readUint24","readUint32","readUint64","readString","s","String","fromCharCode","readCString","arr","b","push","apply","readInt8","readInt16","readInt32","readInt64","readUint8Array","Uint8Array","readInt16Array","Int16Array","readUint16Array","readUint32Array","Uint32Array","readInt32Array","Int32Array","DataStream","byteOffset","endianness","_byteOffset","dataView","LITTLE_ENDIAN","_realloc","extra","_dynamicSize","req","blen","_buffer","_byteLength","buf","src","set","_trimAlloc","dst","BIG_ENDIAN","Object","defineProperty","get","v","_dataView","isEof","mapUint8Array","e","memcpy","BYTES_PER_ELEMENT","arrayToNative","readInt8Array","Int8Array","Uint16Array","readFloat64Array","Float64Array","readFloat32Array","Float32Array","readFloat32","getFloat32","readFloat64","getFloat64","dstOffset","srcOffset","dstU8","srcU8","array","arrayIsLittleEndian","flipArrayEndianness","nativeToEndian","littleEndian","u8","j","k","tmp","failurePosition","fromCharCodeUint8","uint8arr","encoding","TextDecoder","decode","len","MAX_SIZE","pow","save","filename","blob","Blob","window","URL","createObjectURL","url","document","createElement","body","appendChild","setAttribute","click","revokeObjectURL","shift","offset","writeInt32Array","mapInt32Array","writeInt32","writeInt16Array","mapInt16Array","writeInt16","writeInt8Array","mapInt8Array","writeInt8","writeUint32Array","mapUint32Array","writeUint32","writeUint16Array","mapUint16Array","writeUint16","writeUint8Array","writeUint8","writeFloat64Array","mapFloat64Array","writeFloat64","writeFloat32Array","mapFloat32Array","writeFloat32","setInt32","setInt16","setInt8","setUint32","setUint16","setUint8","setFloat32","setFloat64","writeUCS2String","lengthOverride","charCodeAt","writeString","TextEncoder","encode","substring","writeCString","writeStruct","structDefinition","struct","t","writeType","tp","Array","charset","test","parseInt","ta","writeUint64","h","writeUint24","adjustUint32","value","MultiBufferStream","buffers","bufferIndex","insertBuffer","initialized","firstBuffer","fileStart","logBufferLevel","concat","buffer1","buffer2","reduceBuffer","newLength","smallB","usedBytes","ab","to_add","splice","range","bufferedString","used","total","cleanBuffers","mergeNextBuffer","next_buffer","oldLength","oldUsedBytes","oldFileStart","findPosition","fromStart","filePosition","markAsUsed","abuffer","index","findEndContiguousBuf","inputindex","nextBuf","currentBuf","getEndFilePositionAfter","addUsedBytes","nbBytes","setAllUsedBytes","MPEG4DescriptorParser","descTagToName","getDescriptorName","tag","that","classes","parseOneDescriptor","stream","byteRead","hdrSize","desc","Descriptor","parse","_tag","_size","descs","data","findDescriptor","parseRemainingDescriptors","ES_Descriptor","call","l","ES_ID","flags","dependsOn_ES_ID","OCR_ES_ID","getOTI","dcd","oti","getAudioConfig","dsi","audioObjectType","DecoderConfigDescriptor","streamType","bufferSize","maxBitrate","avgBitrate","DecoderSpecificInfo","SLConfigDescriptor","BoxParser","ERR_INVALID_DATA","ERR_NOT_ENOUGH_DATA","OK","BASIC_BOXES","FULL_BOXES","CONTAINER_BOXES","boxCodes","fullBoxCodes","containerBoxCodes","sampleEntryCodes","sampleGroupEntryCodes","trackGroupTypes","UUIDBoxes","UUIDs","initialize","FullBox","Box","ContainerBox","SampleEntry","TrackGroupTypeBox","forEach","type","createBoxCtor","createFullBoxCtor","types","createContainerBoxCtor","_type","_uuid","uuid","version","boxes","hdr_size","SampleGroupEntry","grouping_type","parseMethod","parseFullHeader","addSubBoxArrays","subBoxNames","nbSubBoxes","createMediaSampleEntryCtor","mediaType","createSampleEntryCtor","createEncryptedSampleEntryCtor","createSampleGroupCtor","createTrackGroupCtor","createUUIDBox","isFullBox","isContainerBox","TKHD_FLAG_ENABLED","TKHD_FLAG_IN_MOVIE","TKHD_FLAG_IN_PREVIEW","TFHD_FLAG_BASE_DATA_OFFSET","TFHD_FLAG_SAMPLE_DESC","TFHD_FLAG_SAMPLE_DUR","TFHD_FLAG_SAMPLE_SIZE","TFHD_FLAG_SAMPLE_FLAGS","TFHD_FLAG_DUR_EMPTY","TFHD_FLAG_DEFAULT_BASE_IS_MOOF","TRUN_FLAGS_DATA_OFFSET","TRUN_FLAGS_FIRST_FLAG","TRUN_FLAGS_DURATION","TRUN_FLAGS_SIZE","TRUN_FLAGS_FLAGS","TRUN_FLAGS_CTS_OFFSET","add","name","addBox","box","prop","addEntry","_prop","parseUUID","parseHex16","hex16","hex","toString","parseOneBox","headerOnly","parentSize","code","box_type","has_unparsed_data","write","parseDataAndRewind","diff","ret","indexOf","parseLanguage","language","chars","languageString","SAMPLE_ENTRY_TYPE_VISUAL","SAMPLE_ENTRY_TYPE_AUDIO","SAMPLE_ENTRY_TYPE_HINT","SAMPLE_ENTRY_TYPE_METADATA","SAMPLE_ENTRY_TYPE_SUBTITLE","SAMPLE_ENTRY_TYPE_SYSTEM","SAMPLE_ENTRY_TYPE_TEXT","parseHeader","data_reference_index","parseFooter","compressorname_length","width","height","horizresolution","vertresolution","frame_count","compressorname","depth","channel_count","samplesize","samplerate","FieldLength","layer_size","op_index","aux_type","aux_subtype_length","aux_subtype","seq_profile","seq_level_idx_0","seq_tier_0","high_bitdepth","twelve_bit","monochrome","chroma_subsampling_x","chroma_subsampling_y","chroma_sample_position","reserved_1","initial_presentation_delay_present","initial_presentation_delay_minus_one","reserved_2","configOBUs_length","configOBUs","toparse","configurationVersion","AVCProfileIndication","profile_compatibility","AVCLevelIndication","lengthSizeMinusOne","nb_SPS_nalus","SPS","nalu","nb_PPS_nalus","PPS","ext","bufferSizeDB","cleanApertureWidthN","cleanApertureWidthD","cleanApertureHeightN","cleanApertureHeightD","horizOffN","horizOffD","vertOffN","vertOffD","max_content_light_level","max_pic_average_light_level","entry_count","chunk_offsets","maxCLL","maxFALL","colour_type","colour_primaries","transfer_characteristics","matrix_coefficients","full_range_flag","ICC_profile","notice","compositionToDTSShift","leastDecodeToDisplayDelta","greatestDecodeToDisplayDelta","compositionStartTime","compositionEndTime","sample_counts","sample_offsets","tmp_byte1","tmp_byte2","tmp_byte3","fscod","bsid","bsmod","acmod","lfeon","bit_rate_code","tmp_16","data_rate","num_ind_sub","ind_subs","ind_sub","num_dep_sub","chan_loc","boxesFound","knownBlockTypes","flagAndType","numMetadataBlocks","bytessent","time","entries","extended_language","entry","segment_duration","media_time","media_rate_integer","media_rate_fraction","timescale","presentation_time","event_duration","id","scheme_id_uri","presentation_time_delta","message_size","message_data","esd_data","esd_parser","esd","fieldCount","fieldOrdering","data_format","major_brand","minor_version","compatible_brands","handler","slice","tmp_byte","general_profile_space","general_tier_flag","general_profile_idc","general_profile_compatibility","general_constraint_indicator","general_level_idc","min_spatial_segmentation_idc","parallelismType","chroma_format_idc","bit_depth_luma_minus8","bit_depth_chroma_minus8","avgFrameRate","constantFrameRate","numTemporalLayers","temporalIdNested","nalu_arrays","numOfArrays","nalu_array","completeness","nalu_type","numNalus","item_infos","byte","offset_size","length_size","base_offset_size","index_size","items","item_count","item","item_ID","construction_method","base_offset","extent_count","extents","extent","extent_index","extent_offset","extent_length","reserved","axis","item_protection_index","item_name","content_type","content_encoding","extension_type","item_type","item_uri_type","associations","item_assoc","association_count","props","p","essential","property_index","references","SingleItemTypeReferenceBox","SingleItemTypeReferenceBoxLarge","angle","image_width","image_height","schemeURI","count","levels","track_ID","padding_flag","assignment_type","grouping_type_parameter","sub_track_id","layer_id","period","bytes","display_primaries","x","y","white_point","max_display_mastering_luminance","min_display_mastering_luminance","creation_time","modification_time","fragment_duration","sequence_number","rate","volume","matrix","next_track_id","packetssent","sample_count","padbits","hSpacing","vSpacing","text","payloadID","rtpmap_string","initial_delay","item_id","num_channels","bits_per_channels","ref_track_id","ntp_timestamp","system_id","kid","datasize","descriptionformat","sdptext","aux_info_type","aux_info_type_parameter","default_sample_info_size","sample_info_size","mime_format","namespace","schema_location","auxiliary_mime_types","displayFlags","horizontal_justification","vertical_justification","bg_color_rgba","box_record","style_record","roll_count","first_output_sample","sample_offset","remaining","description_length","num_output_samples","num_total_samples","layerNumber","accurateStatisticsFlag","avgBitRate","subSequenceIdentifier","durationFlag","avgRateFlag","dependency","numReferences","dependencyInfo","subSeqDirectionFlag","roll_distance","num_leading_samples_known","num_leading_samples","operation_point_count","target_rate_share","available_bitrate","maximum_bitrate","minimum_bitrate","discard_priority","crypt_byte_block","skip_byte_block","isProtected","Per_Sample_IV_Size","KID","constant_IV_size","constant_IV","NAL_unit_type","level_independently_decodable","group_description_index","scheme_type","scheme_version","scheme_uri","is_leading","sample_depends_on","sample_is_depended_on","sample_has_redundancy","default_length","default_group_description_index","reference_ID","earliest_presentation_time","first_offset","ref","tmp_32","reference_type","referenced_size","subsegment_duration","starts_with_SAP","SAP_type","SAP_delta_time","from_item_ID","primaryRChromaticity_x","primaryRChromaticity_y","primaryGChromaticity_x","primaryGChromaticity_y","primaryBChromaticity_x","primaryBChromaticity_y","whitePointChromaticity_x","whitePointChromaticity_y","luminanceMax","luminanceMin","balance","subsegments","subsegment_count","subsegment","range_count","range_size","priority","switch_group","alternate_group","attribute_list","first_chunk","samples_per_chunk","sample_description_index","entryCount","shadowed_sample_numbers","sync_sample_numbers","sample_numbers","sample_sizes","sample_size","delta","sample_deltas","tmp32","single_view_allowed","stereo_scheme","stereo_indication_type","ftypBox","field_size","subsample_count","sampleInfo","sample_delta","subsamples","subsample","discardable","codec_specific_parameters","default_crypt_byte_block","default_skip_byte_block","default_isProtected","default_Per_Sample_IV_Size","default_KID","default_constant_IV_size","default_constant_IV","baseMediaDecodeTime","readBytes","track_id","base_data_offset","default_sample_description_index","default_sample_duration","default_sample_size","default_sample_flags","length_size_of_traf_num","length_size_of_trun_num","length_size_of_sample_num","number_of_entries","moof_offset","traf_number","trun_number","sample_number","layer","track_group_id","TrackReferenceTypeBox","track_ids","trefBox","data_offset","first_sample_flags","sample_duration","sample_flags","sample_composition_time_offset","config","location","LiveServerManifest","replace","default_AlgorithmID","default_IV_size","fragment_count","absolute_time","absolute_duration","graphicsmode","opcolor","profile","bitDepth","chromaSubsampling","videoFullRangeFlag","colourPrimaries","transferCharacteristics","matrixCoefficients","colorSpace","transferFunction","codecIntializationDataSize","codecIntializationData","isVideo","isAudio","isSubtitle","isMetadata","isHint","getCodec","getWidth","getHeight","getChannelCount","getSampleRate","getSampleSize","VisualSampleEntry","AudioSampleEntry","SubtitleSampleEntry","MetadataSampleEntry","decimalToHex","d","padding","Number","avc1SampleEntry","avc2SampleEntry","avc3SampleEntry","avc4SampleEntry","baseCodec","avcC","hev1SampleEntry","hvc1SampleEntry","hvcC","val","reversed","hasByte","constraint_string","mp4aSampleEntry","esds","stxtSampleEntry","av01SampleEntry","bitdepth","av1C","writeHeader","sizePosition","avcCBox","co64Box","cslgBox","cttsBox","drefBox","elngBox","elstBox","emsgBox","hdlrBox","kindBox","mdhdBox","mehdBox","mfhdBox","mvhdBox","writeFooter","stppSampleEntry","sbgpBox","sgpdBox","sidxBox","stcoBox","stscBox","stsdBox","stshBox","stssBox","stszBox","constant","sttsBox","tfdtBox","UINT32_MAX","tfhdBox","tkhdBox","trexBox","trunBox","data_offset_position","vmhdBox","unpack","samples","pts","dts","m","Infinity","description_index","chunk_index","DIFF_BOXES_PROP_NAMES","DIFF_PRIMITIVE_ARRAY_PROP_NAMES","boxEqualFields","box_a","box_b","boxEqual","VTTin4Parser","parseSample","cue","cues","getText","startTime","endTime","n","z","secToTimestamp","insec","ms","string","cueIn4","payl","XMLSubtitlein4Parser","sample","resources","documentString","DOMParser","parseFromString","Textin4Parser","parseConfig","ISOFile","mdats","moofs","isProgressive","moovStartFound","onMoovStart","moovStartSent","onReady","readySent","onSegment","onSamples","onError","sampleListBuilt","fragmentedTracks","extractedTracks","isFragmentationInitialized","sampleProcessingStarted","nextMoofNumber","itemListBuilt","onSidx","sidxSent","setSegmentOptions","user","options","fragTrack","trak","getTrackById","nextSample","segmentStream","nb_samples","rapAlignement","nbSamples","unsetSegmentOptions","setExtractionOptions","extractTrack","unsetExtractionOptions","restoreParsePosition","hasIncompleteMdat","processIncompleteMdat","saveParsePosition","processIncompleteBox","updateUsedBytes","checkBuffer","appendBuffer","last","nextFileStart","moov","buildSampleLists","updateSampleLists","getInfo","processSamples","nextSeekPosition","nextParsePosition","sidx","meta","flattenItemInfo","processItems","onItem","getAllocatedSampleDataSize","track","sample_desc","movie","_1904","getTime","hasMoov","mvhd","isFragmented","mvex","mehd","hasIOD","iods","brands","ftyp","created","modified","tracks","audioTracks","videoTracks","subtitleTracks","metadataTracks","hintTracks","otherTracks","traks","mdia","minf","stbl","stsd","tkhd","hdlr","tref","edts","edits","elst","movie_duration","movie_timescale","track_width","track_height","mdhd","cts_shift","cslg","samples_duration","codec","kind","udta","kinds","elng","samples_size","bitrate","audio","sample_rate","video","mime","fragTrak","result","createFragment","extractTrak","getSample","getBox","getBoxes","returnEarly","_sweep","getTrackSamplesInfo","getTrackSample","releaseUsedSamples","sampleNum","lastValidSample","releaseSample","samplesDataSize","stop","flush","seekTrack","useRap","seek_offset","rap_seek_sample_num","seek_sample_num","cts","is_sync","alreadyRead","trak_seek_info","seek_info","equal","box_index","a_box","b_box","lastBoxStartPosition","parsingMdat","discardMdatData","init","_options","addTrack","media_duration","sample_description_entry","media_type","codes","description","description_boxes","buildTrakSampleLists","computeSize","stream_","addSample","depends_on","is_depended_on","has_redundancy","degradation_priority","moof","createSingleSampleMoof","trafs","truns","moofBox","traf","lastMoofIndex","resetTables","initial_duration","stco","co64","stsc","stsz","stz2","stts","ctts","stss","initSampleGroups","sbgps","trak_sgpds","traf_sgpds","sample_group_info","sample_group_key","SampleGroupInfo","_parameter","_sbgp","sbgp","last_sample_in_run","entry_index","sample_groups_info","fragment_description","is_fragment","setSampleGroupProperties","sample_groups","process_sdtp","sdtp","subs","sgpds","stdp","chunk_run_index","last_chunk_in_run","offset_in_chunk","last_sample_in_chunk","last_sample_in_stts_run","stts_run_index","last_sample_in_ctts_run","ctts_run_index","last_stss_index","subs_entry_index","last_subs_sample_index","last_run_position","trex","tfhd","getTrexById","trun","moof_number","number_in_traf","first_sample_index","first_traf_merged","tfdt","bdop","dbim","dop","bdo","has_fragment_subsamples","sample_index","lengthAfterStart","getCodecs","codecs","trexs","itemsDataSize","iinf","ref_to","protection_index","protection","ipro","protections","iloc","itemloc","source","dinf","pitm","primary","iref","iprp","ipmas","ipma","association","properties","propEntry","propbox","ipco","getItem","releaseItem","callback","sent","hasItem","getMetaHandler","getPrimaryItem","itemToFragmentedTrackFile","itemId","file","trackOptions","ispe","trackId","outstream","sampleNumber","mdat","mdatBox","writeInitializationSegment","total_duration","getBuffer","initializeSegmentation","initSegs","seg","moovBox","printHeader","output","indent","print","prev_indent","MP4Box","createFile","_keepMdatData","_stream","keepMdatData"],"mappings":";;AAKA,IAAIA,IAAM,WACR,IAAIC,EAAQ,IAAIC,KAKZC,EAJmB,EAwCvB,MAnCgB,CACfC,YAAc,SAASC,GACGF,EAArBE,GAASC,KAAKC,MAJG,EAKZF,GAASC,KAAKE,KANF,EAOZH,GAASC,KAAKG,KARA,GASLH,KAAKI,MAVF,IAatBH,MAAQ,SAASI,EAAQC,QACFC,IAAlBC,QAAQP,QACXO,QAAQP,MAAQO,QAAQC,KAEFZ,GAdF,GAepBW,QAAQP,MAAM,IAAIP,IAAIgB,kBAAkB,IAAId,KAAOD,EAAM,KAAM,IAAI,IAAIU,EAAO,IAAIC,IAGpFG,IAAM,SAASJ,EAAQC,GACtBN,KAAKC,MAAMI,EAAOC,MAEnBJ,KAAO,SAASG,EAAQC,GACDT,GAvBD,GAwBpBW,QAAQN,KAAK,IAAIR,IAAIgB,kBAAkB,IAAId,KAAOD,EAAM,KAAM,IAAI,IAAIU,EAAO,IAAIC,IAGnFH,KAAO,SAASE,EAAQC,GACET,GA7BF,GA8BtBW,QAAQL,KAAK,IAAIT,IAAIgB,kBAAkB,IAAId,KAAOD,EAAM,KAAM,IAAI,IAAIU,EAAO,IAAIC,IAGnFF,MAAQ,SAASC,EAAQC,GACDT,GAnCF,GAoCpBW,QAAQJ,MAAM,IAAIV,IAAIgB,kBAAkB,IAAId,KAAOD,EAAM,KAAM,IAAI,IAAIU,EAAO,IAAIC,KAtC7E,GA8CVZ,IAAIgB,kBAAoB,SAASC,EAAUC,GAC1C,IAAIC,EAEJ,SAASC,EAAIC,EAAQC,GAGpB,IAFA,IACIC,GADM,GAAKF,GACHG,MAAM,KACXD,EAAE,GAAGD,OAASA,GACpBC,EAAE,GAAK,IAAMA,EAAE,GAEhB,OAAOA,EAAEE,KAAK,KAEXR,EAAW,GACdE,GAAM,EACNF,GAAYA,GAEZE,GAAM,EAEP,IACIO,EAAeT,GADHC,GAAc,GAE1BS,EAAQC,KAAKC,MAAMH,EAAa,MACpCA,GAAwB,KAARC,EACZG,EAAUF,KAAKC,MAAMH,EAAa,IAElCK,EAAoB,KADxBL,GAA0B,GAAVI,GAKhB,OAFAC,GAAqB,KADrBL,EAAeE,KAAKC,MAAMH,IAE1BK,EAAOH,KAAKC,MAAME,IACVZ,EAAM,IAAK,IAAIQ,EAAM,IAAIP,EAAIU,EAAQ,GAAG,IAAIV,EAAIM,EAAa,GAAG,IAAIN,EAAIW,EAAK,IAItF/B,IAAIgC,YAAc,SAASC,GAC1B,IAAIX,EAASW,EAAOX,OACpB,GAAa,EAATA,EAAY,CAEf,IADA,IAAIY,EAAM,GACDC,EAAI,EAAGA,EAAIb,EAAQa,IAClB,EAAJA,IAAOD,GAAO,KAClBA,GAAO,IAAIlC,IAAIgB,kBAAkBiB,EAAOhC,MAAMkC,IAAK,IAAInC,IAAIgB,kBAAkBiB,EAAOG,IAAID,IAAI,IAE9F,OAAOD,EAEP,MAAO,WAIc,oBAAZG,UACVA,QAAQrC,IAAMA,KAGf,IAAIsC,aAAe,SAASC,GAC1B,KAAIA,aAAuBC,aAIzB,KAAM,wBAHNlC,KAAKmC,OAASF,EACdjC,KAAKoC,SAAW,IAAIC,SAASJ,GAI/BjC,KAAKsC,SAAW,GAMlBN,aAAaO,UAAUC,YAAc,WACnC,OAAOxC,KAAKsC,UAGdN,aAAaO,UAAUE,eAAiB,WACtC,OAAOzC,KAAKmC,OAAOO,YAGrBV,aAAaO,UAAUI,UAAY,WACjC,OAAO3C,KAAKmC,OAAOO,YAGrBV,aAAaO,UAAUK,KAAO,SAAUC,GAClCC,EAAOxB,KAAKyB,IAAI,EAAGzB,KAAK0B,IAAIhD,KAAKmC,OAAOO,WAAYG,IAExD,OADA7C,KAAKsC,SAAYW,MAAMH,KAAUI,SAASJ,GAAS,EAAIA,GAChD,GAGTd,aAAaO,UAAUY,MAAQ,WAC7B,OAAOnD,KAAKwC,eAAiBxC,KAAKyC,kBAMpCT,aAAaO,UAAUa,WAAa,SAASC,EAAMC,GACjD,IAAIC,EAAM,EACV,GAAIvD,KAAKsC,SAAWe,GAAQrD,KAAKmC,OAAOO,WAAY,CAClD,OAAQW,GACN,KAAK,EAEDE,EADED,EACItD,KAAKoC,SAASoB,QAAQxD,KAAKsC,UAE3BtC,KAAKoC,SAASqB,SAASzD,KAAKsC,UAEpC,MACF,KAAK,EAEDiB,EADED,EACItD,KAAKoC,SAASsB,SAAS1D,KAAKsC,UAE5BtC,KAAKoC,SAASuB,UAAU3D,KAAKsC,UAErC,MACF,KAAK,EACH,GAAIgB,EACF,KAAM,8CAENC,EAAMvD,KAAKoC,SAASqB,SAASzD,KAAKsC,WAAa,GAC/CiB,GAAOvD,KAAKoC,SAASqB,SAASzD,KAAKsC,SAAS,IAAM,EAClDiB,GAAOvD,KAAKoC,SAASqB,SAASzD,KAAKsC,SAAS,GAE9C,MACF,KAAK,EAEDiB,EADED,EACItD,KAAKoC,SAASwB,SAAS5D,KAAKsC,UAE5BtC,KAAKoC,SAASyB,UAAU7D,KAAKsC,UAErC,MACF,KAAK,EACH,GAAIgB,EACF,KAAM,8CAENC,EAAMvD,KAAKoC,SAASyB,UAAU7D,KAAKsC,WAAa,GAChDiB,GAAOvD,KAAKoC,SAASyB,UAAU7D,KAAKsC,SAAS,GAE/C,MACF,QACE,KAAO,4CAA4Ce,EAGvD,OADArD,KAAKsC,UAAWe,EACTE,EAEP,KAAM,8BAIVvB,aAAaO,UAAUuB,UAAY,WACjC,OAAO9D,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAUwB,WAAa,WAClC,OAAO/D,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAUyB,WAAa,WAClC,OAAOhE,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAU0B,WAAa,WAClC,OAAOjE,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAU2B,WAAa,WAClC,OAAOlE,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAU4B,WAAa,SAASnD,GAC3C,GAAIhB,KAAKsC,SAAWtB,GAAUhB,KAAKmC,OAAOO,WAAY,CAEpD,IADA,IAAI0B,EAAI,GACCvC,EAAI,EAAGA,EAAIb,EAAQa,IAC1BuC,GAAKC,OAAOC,aAAatE,KAAK8D,aAEhC,OAAOM,EAEP,KAAM,8BAIVpC,aAAaO,UAAUgC,YAAc,WAEnC,IADA,IAAIC,EAAM,KACE,CACV,IAAIC,EAAIzE,KAAK8D,YACb,GAAU,IAANW,EAGF,MAFAD,EAAIE,KAAKD,GAKb,OAAOJ,OAAOC,aAAaK,MAAM,KAAMH,IAGzCxC,aAAaO,UAAUqC,SAAW,WAChC,OAAO5E,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAUsC,UAAY,WACjC,OAAO7E,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAUuC,UAAY,WACjC,OAAO9E,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAUwC,UAAY,WACjC,OAAO/E,KAAKoD,WAAW,GAAG,IAG5BpB,aAAaO,UAAUyC,eAAiB,SAAShE,GAE/C,IADA,IAAIwD,EAAM,IAAIS,WAAWjE,GAChBa,EAAI,EAAGA,EAAIb,EAAQa,IAC1B2C,EAAI3C,GAAK7B,KAAK8D,YAEhB,OAAOU,GAGTxC,aAAaO,UAAU2C,eAAiB,SAASlE,GAE/C,IADA,IAAIwD,EAAM,IAAIW,WAAWnE,GAChBa,EAAI,EAAGA,EAAIb,EAAQa,IAC1B2C,EAAI3C,GAAK7B,KAAK6E,YAEhB,OAAOL,GAGTxC,aAAaO,UAAU6C,gBAAkB,SAASpE,GAEhD,IADA,IAAIwD,EAAM,IAAIW,WAAWnE,GAChBa,EAAI,EAAGA,EAAIb,EAAQa,IAC1B2C,EAAI3C,GAAK7B,KAAK+D,aAEhB,OAAOS,GAGTxC,aAAaO,UAAU8C,gBAAkB,SAASrE,GAEhD,IADA,IAAIwD,EAAM,IAAIc,YAAYtE,GACjBa,EAAI,EAAGA,EAAIb,EAAQa,IAC1B2C,EAAI3C,GAAK7B,KAAKiE,aAEhB,OAAOO,GAGTxC,aAAaO,UAAUgD,eAAiB,SAASvE,GAE/C,IADA,IAAIwD,EAAM,IAAIgB,WAAWxE,GAChBa,EAAI,EAAGA,EAAIb,EAAQa,IAC1B2C,EAAI3C,GAAK7B,KAAK8E,YAEhB,OAAON,GAGc,oBAAZzC,UACTA,QAAQC,aAAeA,cAUzB,IAAIyD,WAAa,SAASxD,EAAayD,EAAYC,GACjD3F,KAAK4F,YAAcF,GAAc,EAC7BzD,aAAuBC,YACzBlC,KAAKmC,OAASF,EACiB,iBAAfA,GAChBjC,KAAK6F,SAAW5D,EACZyD,IACF1F,KAAK4F,aAAeF,IAGtB1F,KAAKmC,OAAS,IAAID,YAAYD,GAAe,GAE/CjC,KAAKsC,SAAW,EAChBtC,KAAK2F,WAA2B,MAAdA,EAAqBF,WAAWK,cAAgBH,GAEpEF,WAAWlD,UAAY,GAEvBkD,WAAWlD,UAAUC,YAAc,WACjC,OAAOxC,KAAKsC,UAQdmD,WAAWlD,UAAUwD,SAAW,SAASC,GACvC,GAAKhG,KAAKiG,aAAV,CAGA,IAAIC,EAAMlG,KAAK4F,YAAc5F,KAAKsC,SAAW0D,EACzCG,EAAOnG,KAAKoG,QAAQ1D,WACxB,GAAIwD,GAAOC,EACLD,EAAMlG,KAAKqG,cACbrG,KAAKqG,YAAcH,OAFvB,CASA,IAHIC,EAAO,IACTA,EAAO,GAEIA,EAAND,GACLC,GAAQ,EAEV,IAAIG,EAAM,IAAIpE,YAAYiE,GACtBI,EAAM,IAAItB,WAAWjF,KAAKoG,SACpB,IAAInB,WAAWqB,EAAK,EAAGC,EAAIvF,QACjCwF,IAAID,GACRvG,KAAKmC,OAASmE,EACdtG,KAAKqG,YAAcH,KAWrBT,WAAWlD,UAAUkE,WAAa,WAChC,IAGIH,EACAI,EACAH,EALAvG,KAAKqG,aAAerG,KAAKoG,QAAQ1D,aAGjC4D,EAAM,IAAIpE,YAAYlC,KAAKqG,aAC3BK,EAAM,IAAIzB,WAAWqB,GACrBC,EAAM,IAAItB,WAAWjF,KAAKoG,QAAS,EAAGM,EAAI1F,QAC9C0F,EAAIF,IAAID,GACRvG,KAAKmC,OAASmE,IAQhBb,WAAWkB,YAAa,EAMxBlB,WAAWK,eAAgB,EAQ3BL,WAAWlD,UAAU8D,YAAc,EAMnCO,OAAOC,eAAepB,WAAWlD,UAAW,aAC1C,CAAEuE,IAAK,WACL,OAAO9G,KAAKqG,YAAcrG,KAAK4F,eAQnCgB,OAAOC,eAAepB,WAAWlD,UAAW,SAC1C,CAAEuE,IAAK,WAEH,OADA9G,KAAKyG,aACEzG,KAAKoG,SAEdI,IAAK,SAASO,GACZ/G,KAAKoG,QAAUW,EACf/G,KAAKgH,UAAY,IAAI3E,SAASrC,KAAKoG,QAASpG,KAAK4F,aACjD5F,KAAKqG,YAAcrG,KAAKoG,QAAQ1D,cAQtCkE,OAAOC,eAAepB,WAAWlD,UAAW,aAC1C,CAAEuE,IAAK,WACH,OAAO9G,KAAK4F,aAEdY,IAAK,SAASO,GACZ/G,KAAK4F,YAAcmB,EACnB/G,KAAKgH,UAAY,IAAI3E,SAASrC,KAAKoG,QAASpG,KAAK4F,aACjD5F,KAAKqG,YAAcrG,KAAKoG,QAAQ1D,cAQtCkE,OAAOC,eAAepB,WAAWlD,UAAW,WAC1C,CAAEuE,IAAK,WACH,OAAO9G,KAAKgH,WAEdR,IAAK,SAASO,GACZ/G,KAAK4F,YAAcmB,EAAErB,WACrB1F,KAAKoG,QAAUW,EAAE5E,OACjBnC,KAAKgH,UAAY,IAAI3E,SAASrC,KAAKoG,QAASpG,KAAK4F,aACjD5F,KAAKqG,YAAcrG,KAAK4F,YAAcmB,EAAErE,cAU9C+C,WAAWlD,UAAUK,KAAO,SAASC,GAC/BC,EAAOxB,KAAKyB,IAAI,EAAGzB,KAAK0B,IAAIhD,KAAK0C,WAAYG,IACjD7C,KAAKsC,SAAYW,MAAMH,KAAUI,SAASJ,GAAS,EAAIA,GASzD2C,WAAWlD,UAAU0E,MAAQ,WAC3B,OAAQjH,KAAKsC,UAAYtC,KAAKqG,aAahCZ,WAAWlD,UAAU2E,cAAgB,SAASlG,GAC5ChB,KAAK+F,UAAS/E,GACd,IAAIwD,EAAM,IAAIS,WAAWjF,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAEtE,OADAhB,KAAKsC,WAAYtB,EACVwD,GAWTiB,WAAWlD,UAAUgD,eAAiB,SAASvE,EAAQmG,GACrDnG,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAW,EAAKtB,EAChE,IAAIwD,EAAM,IAAIgB,WAAWxE,GAMzB,OALAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7B5B,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAU2C,eAAiB,SAASlE,EAAQmG,GACrDnG,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAW,EAAKtB,EAChE,IAAIwD,EAAM,IAAIW,WAAWnE,GAMzB,OALAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7B5B,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAUgF,cAAgB,SAASvG,GAC5CA,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAYtB,EAC5D,IAAIwD,EAAM,IAAIgD,UAAUxG,GAKxB,OAJAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7BrH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAU8C,gBAAkB,SAASrE,EAAQmG,GACtDnG,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAW,EAAKtB,EAChE,IAAIwD,EAAM,IAAIc,YAAYtE,GAM1B,OALAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7B5B,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAU6C,gBAAkB,SAASpE,EAAQmG,GACtDnG,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAW,EAAKtB,EAChE,IAAIwD,EAAM,IAAIiD,YAAYzG,GAM1B,OALAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7B5B,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAUyC,eAAiB,SAAShE,GAC7CA,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAYtB,EAC5D,IAAIwD,EAAM,IAAIS,WAAWjE,GAKzB,OAJAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7BrH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAUmF,iBAAmB,SAAS1G,EAAQmG,GACvDnG,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAW,EAAKtB,EAChE,IAAIwD,EAAM,IAAImD,aAAa3G,GAM3B,OALAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7B5B,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAUqF,iBAAmB,SAAS5G,EAAQmG,GACvDnG,EAAmB,MAAVA,EAAkBhB,KAAK0C,WAAW1C,KAAKsC,SAAW,EAAKtB,EAChE,IAAIwD,EAAM,IAAIqD,aAAa7G,GAM3B,OALAyE,WAAW2B,OAAO5C,EAAIrC,OAAQ,EACZnC,KAAKmC,OAAQnC,KAAK0F,WAAW1F,KAAKsC,SAClCtB,EAAOwD,EAAI6C,mBAC7B5B,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAYkC,EAAI9B,WACd8B,GAUTiB,WAAWlD,UAAUuC,UAAY,SAASqC,GACpCJ,EAAI/G,KAAKgH,UAAUpD,SAAS5D,KAAKsC,SAAe,MAAL6E,EAAYnH,KAAK2F,WAAawB,GAE7E,OADAnH,KAAKsC,UAAY,EACVyE,GASTtB,WAAWlD,UAAUsC,UAAY,SAASsC,GACpCJ,EAAI/G,KAAKgH,UAAUtD,SAAS1D,KAAKsC,SAAe,MAAL6E,EAAYnH,KAAK2F,WAAawB,GAE7E,OADAnH,KAAKsC,UAAY,EACVyE,GAQTtB,WAAWlD,UAAUqC,SAAW,WAC9B,IAAImC,EAAI/G,KAAKgH,UAAUxD,QAAQxD,KAAKsC,UAEpC,OADAtC,KAAKsC,UAAY,EACVyE,GASTtB,WAAWlD,UAAU0B,WAAa,SAASkD,GACrCJ,EAAI/G,KAAKgH,UAAUnD,UAAU7D,KAAKsC,SAAe,MAAL6E,EAAYnH,KAAK2F,WAAawB,GAE9E,OADAnH,KAAKsC,UAAY,EACVyE,GASTtB,WAAWlD,UAAUwB,WAAa,SAASoD,GACrCJ,EAAI/G,KAAKgH,UAAUrD,UAAU3D,KAAKsC,SAAe,MAAL6E,EAAYnH,KAAK2F,WAAawB,GAE9E,OADAnH,KAAKsC,UAAY,EACVyE,GAQTtB,WAAWlD,UAAUuB,UAAY,WAC/B,IAAIiD,EAAI/G,KAAKgH,UAAUvD,SAASzD,KAAKsC,UAErC,OADAtC,KAAKsC,UAAY,EACVyE,GASTtB,WAAWlD,UAAUuF,YAAc,SAASX,GACtCJ,EAAI/G,KAAKgH,UAAUe,WAAW/H,KAAKsC,SAAe,MAAL6E,EAAYnH,KAAK2F,WAAawB,GAE/E,OADAnH,KAAKsC,UAAY,EACVyE,GASTtB,WAAWlD,UAAUyF,YAAc,SAASb,GACtCJ,EAAI/G,KAAKgH,UAAUiB,WAAWjI,KAAKsC,SAAe,MAAL6E,EAAYnH,KAAK2F,WAAawB,GAE/E,OADAnH,KAAKsC,UAAY,EACVyE,GASTtB,WAAWE,WAA4D,EAA/C,IAAI6B,UAAU,IAAIrC,WAAW,CAAC,IAAIhD,QAAQ,GAYlEsD,WAAW2B,OAAS,SAASV,EAAKwB,EAAW3B,EAAK4B,EAAWzF,GACvD0F,EAAQ,IAAInD,WAAWyB,EAAKwB,EAAWxF,GACvC2F,EAAQ,IAAIpD,WAAWsB,EAAK4B,EAAWzF,GAC3C0F,EAAM5B,IAAI6B,IAWZ5C,WAAW6B,cAAgB,SAASgB,EAAOC,GACzC,OAAIA,GAAuBvI,KAAK2F,WACvB2C,EAEAtI,KAAKwI,oBAAoBF,IAYpC7C,WAAWgD,eAAiB,SAASH,EAAOI,GAC1C,OAAI1I,KAAK2F,YAAc+C,EACdJ,EAEAtI,KAAKwI,oBAAoBF,IAUpC7C,WAAW+C,oBAAsB,SAASF,GAExC,IADA,IAAIK,EAAK,IAAI1D,WAAWqD,EAAMnG,OAAQmG,EAAM5C,WAAY4C,EAAM5F,YACrDb,EAAE,EAAGA,EAAEyG,EAAM5F,WAAYb,GAAGyG,EAAMjB,kBACzC,IAAK,IAAIuB,EAAE/G,EAAEyG,EAAMjB,kBAAkB,EAAGwB,EAAEhH,EAAKgH,EAAFD,EAAKA,IAAKC,IAAK,CAC1D,IAAIC,EAAMH,EAAGE,GACbF,EAAGE,GAAKF,EAAGC,GACXD,EAAGC,GAAKE,EAGZ,OAAOR,GAST7C,WAAWlD,UAAUwG,gBAAkB,EAEvC1E,OAAO2E,kBAAoB,SAASC,GAEhC,IADA,IAAIzE,EAAM,GACD3C,EAAI,EAAGA,EAAIoH,EAASjI,OAAQa,IACnC2C,EAAI3C,GAAKoH,EAASpH,GAEpB,OAAOwC,OAAOC,aAAaK,MAAM,KAAMH,IAU3CiB,WAAWlD,UAAU4B,WAAa,SAASnD,EAAQkI,GACjD,OAAgB,MAAZA,GAAgC,SAAZA,EACf7E,OAAO2E,kBAAkBrE,MAAM,KAAM,CAAC3E,KAAKkH,cAAwB,MAAVlG,EAAiBhB,KAAK0C,WAAW1C,KAAKsC,SAAWtB,KAE1G,IAAKmI,YAAYD,GAAWE,OAAOpJ,KAAKkH,cAAclG,KAWjEyE,WAAWlD,UAAUgC,YAAc,SAASvD,GAC1C,IAAImF,EAAOnG,KAAK0C,WAAW1C,KAAKsC,SAC5BqG,EAAK,IAAI1D,WAAWjF,KAAKoG,QAASpG,KAAK4F,YAAc5F,KAAKsC,UAC1D+G,EAAMlD,EACI,MAAVnF,IACFqI,EAAM/H,KAAK0B,IAAIhC,EAAQmF,IAEzB,IAAK,IAAItE,EAAI,EAAGA,EAAIwH,GAAiB,IAAVV,EAAG9G,GAAUA,KACxC,IAAIuC,EAAIC,OAAO2E,kBAAkBrE,MAAM,KAAM,CAAC3E,KAAKkH,cAAcrF,KAMjE,OALc,MAAVb,EACFhB,KAAKsC,UAAY+G,EAAIxH,EACZA,GAAKsE,IACdnG,KAAKsC,UAAY,GAEZ8B,GAOT,IAAIkF,SAAWhI,KAAKiI,IAAI,EAAG,IAE3B9D,WAAWlD,UAAUwC,UAAY,WAC/B,OAAQ/E,KAAK8E,YAAYwE,SAAUtJ,KAAKiE,cAE1CwB,WAAWlD,UAAU2B,WAAa,WACjC,OAAQlE,KAAKiE,aAAaqF,SAAUtJ,KAAKiE,cAG1CwB,WAAWlD,UAAUwC,UAAY,WAC/B,OAAQ/E,KAAKiE,aAAaqF,SAAUtJ,KAAKiE,cAG3CwB,WAAWlD,UAAUyB,WAAa,WACjC,OAAQhE,KAAK8D,aAAa,KAAK9D,KAAK8D,aAAa,GAAG9D,KAAK8D,aAGnC,oBAAZ/B,UACTA,QAAQ0D,WAAaA,YAUvBA,WAAWlD,UAAUiH,KAAO,SAASC,GACnC,IAAIC,EAAO,IAAIC,KAAK,CAAC3J,KAAKmC,SAC1B,IAAIyH,OAAOC,MAAOA,IAAIC,gBAYlB,KAAK,4CAXL,IAAIC,EAAMH,OAAOC,IAAIC,gBAAgBJ,GACjCzI,EAAI+I,SAASC,cAAc,KAE/BD,SAASE,KAAKC,YAAYlJ,GAC1BA,EAAEmJ,aAAa,OAAQL,GACvB9I,EAAEmJ,aAAa,WAAYX,GAE3BxI,EAAEmJ,aAAa,SAAU,SACzBnJ,EAAEoJ,QACFT,OAAOC,IAAIS,gBAAgBP,IAYjCtE,WAAWlD,UAAU0D,cAAe,EACpCW,OAAOC,eAAepB,WAAWlD,UAAW,cAC1C,CAAEuE,IAAK,WACH,OAAO9G,KAAKiG,cAEdO,IAAK,SAASO,GACPA,GACH/G,KAAKyG,aAEPzG,KAAKiG,aAAec,KAS1BtB,WAAWlD,UAAUgI,MAAQ,SAASC,GACpC,IAAIlE,EAAM,IAAIpE,YAAYlC,KAAKqG,YAAYmE,GACvC9D,EAAM,IAAIzB,WAAWqB,GACrBC,EAAM,IAAItB,WAAWjF,KAAKoG,QAASoE,EAAQ9D,EAAI1F,QACnD0F,EAAIF,IAAID,GACRvG,KAAKmC,OAASmE,EACdtG,KAAKsC,UAAYkI,GASnB/E,WAAWlD,UAAUkI,gBAAkB,SAASjG,EAAK2C,GAEnD,GADAnH,KAAK+F,SAAsB,EAAbvB,EAAIxD,QACdwD,aAAegB,YACfxF,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAK0K,cAAclG,EAAIxD,OAAQmG,QAE/B,IAAK,IAAItF,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAK2K,WAAWnG,EAAI3C,GAAIsF,IAW9B1B,WAAWlD,UAAUqI,gBAAkB,SAASpG,EAAK2C,GAEnD,GADAnH,KAAK+F,SAAsB,EAAbvB,EAAIxD,QACdwD,aAAeW,YACfnF,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAK6K,cAAcrG,EAAIxD,OAAQmG,QAE/B,IAAK,IAAItF,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAK8K,WAAWtG,EAAI3C,GAAIsF,IAU9B1B,WAAWlD,UAAUwI,eAAiB,SAASvG,GAE7C,GADAxE,KAAK+F,UAASvB,EAAIxD,QACdwD,aAAegD,WACfxH,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAKgL,aAAaxG,EAAIxD,aAEtB,IAAK,IAAIa,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAKiL,UAAUzG,EAAI3C,KAWzB4D,WAAWlD,UAAU2I,iBAAmB,SAAS1G,EAAK2C,GAEpD,GADAnH,KAAK+F,SAAsB,EAAbvB,EAAIxD,QACdwD,aAAec,aACftF,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAKmL,eAAe3G,EAAIxD,OAAQmG,QAEhC,IAAK,IAAItF,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAKoL,YAAY5G,EAAI3C,GAAIsF,IAW/B1B,WAAWlD,UAAU8I,iBAAmB,SAAS7G,EAAK2C,GAEpD,GADAnH,KAAK+F,SAAsB,EAAbvB,EAAIxD,QACdwD,aAAeiD,aACfzH,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAKsL,eAAe9G,EAAIxD,OAAQmG,QAEhC,IAAK,IAAItF,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAKuL,YAAY/G,EAAI3C,GAAIsF,IAU/B1B,WAAWlD,UAAUiJ,gBAAkB,SAAShH,GAE9C,GADAxE,KAAK+F,UAASvB,EAAIxD,QACdwD,aAAeS,YACfjF,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAKkH,cAAc1C,EAAIxD,aAEvB,IAAK,IAAIa,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAKyL,WAAWjH,EAAI3C,KAW1B4D,WAAWlD,UAAUmJ,kBAAoB,SAASlH,EAAK2C,GAErD,GADAnH,KAAK+F,SAAsB,EAAbvB,EAAIxD,QACdwD,aAAemD,cACf3H,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAK2L,gBAAgBnH,EAAIxD,OAAQmG,QAEjC,IAAK,IAAItF,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAK4L,aAAapH,EAAI3C,GAAIsF,IAWhC1B,WAAWlD,UAAUsJ,kBAAoB,SAASrH,EAAK2C,GAErD,GADAnH,KAAK+F,SAAsB,EAAbvB,EAAIxD,QACdwD,aAAeqD,cACf7H,KAAK0F,WAAW1F,KAAKsC,SAAWkC,EAAI6C,oBAAsB,EAC5D5B,WAAW2B,OAAOpH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SACnCkC,EAAIrC,OAAQ,EACZqC,EAAI9B,YACtB1C,KAAK8L,gBAAgBtH,EAAIxD,OAAQmG,QAEjC,IAAK,IAAItF,EAAE,EAAGA,EAAE2C,EAAIxD,OAAQa,IAC1B7B,KAAK+L,aAAavH,EAAI3C,GAAIsF,IAYhC1B,WAAWlD,UAAUoI,WAAa,SAAS5D,EAAGI,GAC5CnH,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUgF,SAAShM,KAAKsC,SAAUyE,EAAQ,MAALI,EAAYnH,KAAK2F,WAAawB,GACxEnH,KAAKsC,UAAY,GASnBmD,WAAWlD,UAAUuI,WAAa,SAAS/D,EAAGI,GAC5CnH,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUiF,SAASjM,KAAKsC,SAAUyE,EAAQ,MAALI,EAAYnH,KAAK2F,WAAawB,GACxEnH,KAAKsC,UAAY,GAQnBmD,WAAWlD,UAAU0I,UAAY,SAASlE,GACxC/G,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUkF,QAAQlM,KAAKsC,SAAUyE,GACtC/G,KAAKsC,UAAY,GASnBmD,WAAWlD,UAAU6I,YAAc,SAASrE,EAAGI,GAC7CnH,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUmF,UAAUnM,KAAKsC,SAAUyE,EAAQ,MAALI,EAAYnH,KAAK2F,WAAawB,GACzEnH,KAAKsC,UAAY,GASnBmD,WAAWlD,UAAUgJ,YAAc,SAASxE,EAAGI,GAC7CnH,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUoF,UAAUpM,KAAKsC,SAAUyE,EAAQ,MAALI,EAAYnH,KAAK2F,WAAawB,GACzEnH,KAAKsC,UAAY,GAQnBmD,WAAWlD,UAAUkJ,WAAa,SAAS1E,GACzC/G,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUqF,SAASrM,KAAKsC,SAAUyE,GACvC/G,KAAKsC,UAAY,GASnBmD,WAAWlD,UAAUwJ,aAAe,SAAShF,EAAGI,GAC9CnH,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUsF,WAAWtM,KAAKsC,SAAUyE,EAAQ,MAALI,EAAYnH,KAAK2F,WAAawB,GAC1EnH,KAAKsC,UAAY,GASnBmD,WAAWlD,UAAUqJ,aAAe,SAAS7E,EAAGI,GAC9CnH,KAAK+F,SAAS,GACd/F,KAAKgH,UAAUuF,WAAWvM,KAAKsC,SAAUyE,EAAQ,MAALI,EAAYnH,KAAK2F,WAAawB,GAC1EnH,KAAKsC,UAAY,GAanBmD,WAAWlD,UAAUiK,gBAAkB,SAAS5K,EAAK+D,EAAY8G,GACzC,MAAlBA,IACFA,EAAiB7K,EAAIZ,QAEvB,IAAK,IAAIa,EAAI,EAAGA,EAAID,EAAIZ,QAAUa,EAAI4K,EAAgB5K,IACpD7B,KAAKuL,YAAY3J,EAAI8K,WAAW7K,GAAI8D,GAEtC,KAAO9D,EAAE4K,EAAgB5K,IACvB7B,KAAKuL,YAAY,IAYrB9F,WAAWlD,UAAUoK,YAAc,SAASvI,EAAG8E,EAAUlI,GACvD,IAAIa,EAAI,EACR,GAAgB,MAAZqH,GAAgC,SAAZA,EACtB,GAAc,MAAVlI,EAAgB,CAElB,IADA,IAAIqI,EAAM/H,KAAK0B,IAAIoB,EAAEpD,OAAQA,GACxBa,EAAE,EAAGA,EAAEwH,EAAKxH,IACf7B,KAAKyL,WAAWrH,EAAEsI,WAAW7K,IAE/B,KAAOA,EAAEb,EAAQa,IACf7B,KAAKyL,WAAW,QAGlB,IAAK5J,EAAE,EAAGA,EAAEuC,EAAEpD,OAAQa,IACpB7B,KAAKyL,WAAWrH,EAAEsI,WAAW7K,SAIjC7B,KAAKwL,gBAAgB,IAAKoB,YAAY1D,GAAW2D,OAAOzI,EAAE0I,UAAU,EAAG9L,MAa3EyE,WAAWlD,UAAUwK,aAAe,SAAS3I,EAAGpD,GAC9C,IAAIa,EAAI,EACR,GAAc,MAAVb,EAAgB,CAElB,IADA,IAAIqI,EAAM/H,KAAK0B,IAAIoB,EAAEpD,OAAQA,GACxBa,EAAE,EAAGA,EAAEwH,EAAKxH,IACf7B,KAAKyL,WAAWrH,EAAEsI,WAAW7K,IAE/B,KAAOA,EAAEb,EAAQa,IACf7B,KAAKyL,WAAW,OAEb,CACL,IAAK5J,EAAE,EAAGA,EAAEuC,EAAEpD,OAAQa,IACpB7B,KAAKyL,WAAWrH,EAAEsI,WAAW7K,IAE/B7B,KAAKyL,WAAW,KAYpBhG,WAAWlD,UAAUyK,YAAc,SAASC,EAAkBC,GAC5D,IAAK,IAAIrL,EAAI,EAAGA,EAAIoL,EAAiBjM,OAAQa,GAAG,EAAG,CACjD,IAAIsL,EAAIF,EAAiBpL,EAAE,GAC3B7B,KAAKoN,UAAUD,EAAGD,EAAOD,EAAiBpL,IAAKqL,KAWnDzH,WAAWlD,UAAU6K,UAAY,SAASD,EAAGpG,EAAGmG,GAC9C,IAAIG,EACJ,GAAgB,mBAALF,EACT,OAAOA,EAAEnN,KAAM+G,GACV,GAAgB,iBAALoG,KAAmBA,aAAaG,OAChD,OAAOH,EAAE3G,IAAIxG,KAAM+G,EAAGmG,GAExB,IAAIT,EAAiB,KACjBc,EAAU,QACV1K,EAAM7C,KAAKsC,SAYf,OAXiB,iBAAP,GAAmB,IAAIkL,KAAKL,KAEpCA,GADAE,EAAKF,EAAEjM,MAAM,MACN,GACPuL,EAAiBgB,SAASJ,EAAG,KAEf,iBAALF,GAAiB,IAAIK,KAAKL,KAEnCA,GADAE,EAAKF,EAAEjM,MAAM,MACN,GACPqM,EAAUE,SAASJ,EAAG,KAGjBF,GACL,IAAK,QACHnN,KAAKyL,WAAW1E,GAChB,MACF,IAAK,OACH/G,KAAKiL,UAAUlE,GACf,MAEF,IAAK,SACH/G,KAAKuL,YAAYxE,EAAG/G,KAAK2F,YACzB,MACF,IAAK,QACH3F,KAAK8K,WAAW/D,EAAG/G,KAAK2F,YACxB,MACF,IAAK,SACH3F,KAAKoL,YAAYrE,EAAG/G,KAAK2F,YACzB,MACF,IAAK,QACH3F,KAAK2K,WAAW5D,EAAG/G,KAAK2F,YACxB,MACF,IAAK,UACH3F,KAAK+L,aAAahF,EAAG/G,KAAK2F,YAC1B,MACF,IAAK,UACH3F,KAAK4L,aAAa7E,EAAG/G,KAAK2F,YAC1B,MAEF,IAAK,WACH3F,KAAKuL,YAAYxE,EAAGtB,WAAWkB,YAC/B,MACF,IAAK,UACH3G,KAAK8K,WAAW/D,EAAGtB,WAAWkB,YAC9B,MACF,IAAK,WACH3G,KAAKoL,YAAYrE,EAAGtB,WAAWkB,YAC/B,MACF,IAAK,UACH3G,KAAK2K,WAAW5D,EAAGtB,WAAWkB,YAC9B,MACF,IAAK,YACH3G,KAAK+L,aAAahF,EAAGtB,WAAWkB,YAChC,MACF,IAAK,YACH3G,KAAK4L,aAAa7E,EAAGtB,WAAWkB,YAChC,MAEF,IAAK,WACH3G,KAAKuL,YAAYxE,EAAGtB,WAAWK,eAC/B,MACF,IAAK,UACH9F,KAAK8K,WAAW/D,EAAGtB,WAAWK,eAC9B,MACF,IAAK,WACH9F,KAAKoL,YAAYrE,EAAGtB,WAAWK,eAC/B,MACF,IAAK,UACH9F,KAAK2K,WAAW5D,EAAGtB,WAAWK,eAC9B,MACF,IAAK,YACH9F,KAAK+L,aAAahF,EAAGtB,WAAWK,eAChC,MACF,IAAK,YACH9F,KAAK4L,aAAa7E,EAAGtB,WAAWK,eAChC,MAEF,IAAK,UACH9F,KAAK+M,aAAahG,EAAG0F,GACrB,MAEF,IAAK,SACHzM,KAAK2M,YAAY5F,EAAGwG,EAASd,GAC7B,MAEF,IAAK,YACHzM,KAAKwM,gBAAgBzF,EAAG/G,KAAK2F,WAAY8G,GACzC,MAEF,IAAK,cACHzM,KAAKwM,gBAAgBzF,EAAGtB,WAAWK,cAAe2G,GAClD,MAEF,IAAK,cACHzM,KAAKwM,gBAAgBzF,EAAGtB,WAAWkB,WAAY8F,GAC/C,MAEF,QACE,GAAgB,GAAZU,EAAEnM,OAAa,CAEjB,IADA,IAAI0M,EAAKP,EAAE,GACFtL,EAAE,EAAGA,EAAEkF,EAAE/F,OAAQa,IACxB7B,KAAKoN,UAAUM,EAAI3G,EAAElF,IAEvB,MAEA7B,KAAKgN,YAAYG,EAAGpG,GAIJ,MAAlB0F,IACFzM,KAAKsC,SAAWO,EAChB7C,KAAK+F,SAAS0G,GACdzM,KAAKsC,SAAWO,EAAM4J,IAK1BhH,WAAWlD,UAAUoL,YAAc,SAAU5G,GAC5C,IAAI6G,EAAItM,KAAKC,MAAMwF,EAAIuC,UACvBtJ,KAAKoL,YAAYwC,GACjB5N,KAAKoL,YAAgB,WAAJrE,IAGlBtB,WAAWlD,UAAUsL,YAAc,SAAU9G,GAC5C/G,KAAKyL,YAAgB,SAAJ1E,IAAiB,IAClC/G,KAAKyL,YAAgB,MAAJ1E,IAAiB,GAClC/G,KAAKyL,WAAgB,IAAJ1E,IAGlBtB,WAAWlD,UAAUuL,aAAe,SAASxL,EAAUyL,GACtD,IAAIlL,EAAM7C,KAAKsC,SACftC,KAAK4C,KAAKN,GACVtC,KAAKoL,YAAY2C,GACjB/N,KAAK4C,KAAKC,IAeX4C,WAAWlD,UAAUmI,cAAgB,SAAS1J,EAAQmG,GACpDnH,KAAK+F,SAAkB,EAAT/E,GACd,IAAIwD,EAAM,IAAIgB,WAAWxF,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAGtE,OAFAyE,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAqB,EAATtB,EACVwD,GAeTiB,WAAWlD,UAAUsI,cAAgB,SAAS7J,EAAQmG,GACpDnH,KAAK+F,SAAkB,EAAT/E,GACd,IAAIwD,EAAM,IAAIW,WAAWnF,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAGtE,OAFAyE,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAqB,EAATtB,EACVwD,GAYTiB,WAAWlD,UAAUyI,aAAe,SAAShK,GAC3ChB,KAAK+F,UAAS/E,GACd,IAAIwD,EAAM,IAAIgD,UAAUxH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAErE,OADAhB,KAAKsC,WAAYtB,EACVwD,GAeTiB,WAAWlD,UAAU4I,eAAiB,SAASnK,EAAQmG,GACrDnH,KAAK+F,SAAkB,EAAT/E,GACd,IAAIwD,EAAM,IAAIc,YAAYtF,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAGvE,OAFAyE,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAqB,EAATtB,EACVwD,GAeTiB,WAAWlD,UAAU+I,eAAiB,SAAStK,EAAQmG,GACrDnH,KAAK+F,SAAkB,EAAT/E,GACd,IAAIwD,EAAM,IAAIiD,YAAYzH,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAGvE,OAFAyE,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAqB,EAATtB,EACVwD,GAeTiB,WAAWlD,UAAUoJ,gBAAkB,SAAS3K,EAAQmG,GACtDnH,KAAK+F,SAAkB,EAAT/E,GACd,IAAIwD,EAAM,IAAImD,aAAa3H,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAGxE,OAFAyE,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAqB,EAATtB,EACVwD,GAeTiB,WAAWlD,UAAUuJ,gBAAkB,SAAS9K,EAAQmG,GACtDnH,KAAK+F,SAAkB,EAAT/E,GACd,IAAIwD,EAAM,IAAIqD,aAAa7H,KAAKoG,QAASpG,KAAK0F,WAAW1F,KAAKsC,SAAUtB,GAGxE,OAFAyE,WAAW6B,cAAc9C,EAAU,MAAL2C,EAAYnH,KAAK2F,WAAawB,GAC5DnH,KAAKsC,UAAqB,EAATtB,EACVwD,GAcT,IAAIwJ,kBAAoB,SAAS7L,GAEhCnC,KAAKiO,QAAU,GACfjO,KAAKkO,aAAe,EAChB/L,IACHnC,KAAKmO,aAAahM,GAClBnC,KAAKkO,YAAc,IAGrBF,kBAAkBzL,UAAY,IAAIkD,WAAW,IAAIvD,YAAe,EAAGuD,WAAWkB,YAM9EqH,kBAAkBzL,UAAU6L,YAAc,WACzC,IAAIC,EACJ,OAAwB,EAApBrO,KAAKkO,cAEwB,EAAtBlO,KAAKiO,QAAQjN,OAEO,KAD9BqN,EAAcrO,KAAKiO,QAAQ,IACXK,WACftO,KAAKmC,OAASkM,EACdrO,KAAKkO,YAAc,EACnBxO,IAAIO,MAAM,oBAAqB,6BACxB,IAEPP,IAAIS,KAAK,oBAAqB,iDAC9BH,KAAKuO,kBACE,IAGR7O,IAAIS,KAAK,oBAAqB,mCAC9BH,KAAKuO,kBACE,KAUTrM,YAAYsM,OAAS,SAASC,EAASC,GACrChP,IAAIO,MAAM,cAAe,2CAA2CwO,EAAQ/L,WAAagM,EAAQhM,aACjG,IAAIoG,EAAM,IAAI7D,WAAWwJ,EAAQ/L,WAAagM,EAAQhM,YAGtD,OAFAoG,EAAItC,IAAI,IAAIvB,WAAWwJ,GAAU,GACjC3F,EAAItC,IAAI,IAAIvB,WAAWyJ,GAAUD,EAAQ/L,YAClCoG,EAAI3G,QAUb6L,kBAAkBzL,UAAUoM,aAAe,SAASxM,EAAQqI,EAAQoE,GACnE,IACAC,EAAS,IAAI5J,WAAW2J,GAIxB,OAHAC,EAAOrI,IAAI,IAAIvB,WAAW9C,EAAQqI,EAAQoE,IAC1CC,EAAO1M,OAAOmM,UAAYnM,EAAOmM,UAAU9D,EAC3CqE,EAAO1M,OAAO2M,UAAY,EACnBD,EAAO1M,QASf6L,kBAAkBzL,UAAU4L,aAAe,SAASY,GAGnD,IAFA,IAAIC,GAAS,EAEJnN,EAAI,EAAGA,EAAI7B,KAAKiO,QAAQjN,OAAQa,IAAK,CAC7C,IAAI4C,EAAIzE,KAAKiO,QAAQpM,GACrB,GAAIkN,EAAGT,WAAa7J,EAAE6J,UAAW,CAEhC,GAAIS,EAAGT,YAAc7J,EAAE6J,UAAW,CAEjC,GAAIS,EAAGrM,WAAc+B,EAAE/B,WAAY,CAIlC1C,KAAKiO,QAAQgB,OAAOpN,EAAG,GACvBA,IACA,SAGAnC,IAAIS,KAAK,oBAAqB,sBAAsB4O,EAAGT,UAAU,cAAcS,EAAGrM,WAAW,qCAK1FqM,EAAGT,UAAYS,EAAGrM,YAAc+B,EAAE6J,YAIrCS,EAAK/O,KAAK2O,aAAaI,EAAI,EAAGtK,EAAE6J,UAAYS,EAAGT,YAEhD5O,IAAIO,MAAM,oBAAqB,oCAAoC8O,EAAGT,UAAU,cAAcS,EAAGrM,WAAW,KAC5G1C,KAAKiO,QAAQgB,OAAOpN,EAAG,EAAGkN,GAGhB,IAANlN,IACH7B,KAAKmC,OAAS4M,GAGhBC,GAAS,EACT,MACM,GAAID,EAAGT,UAAY7J,EAAE6J,UAAY7J,EAAE/B,WAAY,CAErD,IAAI8H,EAAS/F,EAAE6J,UAAY7J,EAAE/B,WAAaqM,EAAGT,UACzCM,EAAYG,EAAGrM,WAAa8H,EAChC,KAAgB,EAAZoE,GAGG,CAENI,GAAS,EACT,MAJAD,EAAK/O,KAAK2O,aAAaI,EAAIvE,EAAQoE,IASlCI,IACHtP,IAAIO,MAAM,oBAAqB,oCAAoC8O,EAAGT,UAAU,cAAcS,EAAGrM,WAAW,KAC5G1C,KAAKiO,QAAQvJ,KAAKqK,GAGR,IAANlN,IACH7B,KAAKmC,OAAS4M,KASjBf,kBAAkBzL,UAAUgM,eAAiB,SAASrO,GASrD,IARA,IACIiC,EAGA+M,EADAvN,EAAS,GAETwN,EAAiB,GACrBC,EAAO,EACPC,EAAQ,EACHxN,EAAI,EAAGA,EAAI7B,KAAKiO,QAAQjN,OAAQa,IACpCM,EAASnC,KAAKiO,QAAQpM,GACZ,IAANA,GACHqN,EAAQ,GACRvN,EAAO+C,KAAKwK,GACZA,EAAMvP,MAAQwC,EAAOmM,UACrBY,EAAMpN,IAAMK,EAAOmM,UAAUnM,EAAOO,WACpCyM,GAAkB,IAAID,EAAMvP,MAAM,KACxBuP,EAAMpN,MAAQK,EAAOmM,UAC/BY,EAAMpN,IAAMK,EAAOmM,UAAUnM,EAAOO,aAEpCwM,EAAQ,IACFvP,MAAQwC,EAAOmM,UACrBa,GAAmBxN,EAAOA,EAAOX,OAAO,GAAGc,IAAI,EAAG,OAAOoN,EAAMvP,MAAM,IACrEuP,EAAMpN,IAAMK,EAAOmM,UAAUnM,EAAOO,WACpCf,EAAO+C,KAAKwK,IAEbE,GAAQjN,EAAO2M,UACfO,GAASlN,EAAOO,WAEG,EAAhBf,EAAOX,SACVmO,GAAmBD,EAAMpN,IAAI,EAAG,KAE7BrB,EAAOP,EAAOR,IAAIQ,KAAOR,IAAIO,MACL,IAAxBD,KAAKiO,QAAQjN,OAChBP,EAAI,oBAAqB,4BAEzBA,EAAI,oBAAwBT,KAAKiO,QAAQjN,OAAO,sBAAsBoO,EAAK,IAAIC,EAAM,+BAA+BF,IAItHnB,kBAAkBzL,UAAU+M,aAAe,WAG1C,IAFA,IACInN,EACCN,EAAI,EAAGA,EAAI7B,KAAKiO,QAAQjN,OAAQa,KACpCM,EAASnC,KAAKiO,QAAQpM,IACXiN,YAAc3M,EAAOO,aAC/BhD,IAAIO,MAAM,oBAAqB,oBAAoB4B,GACnD7B,KAAKiO,QAAQgB,OAAOpN,EAAG,GACvBA,MAKHmM,kBAAkBzL,UAAUgN,gBAAkB,WAC7C,IAAIC,EACJ,GAAIxP,KAAKkO,YAAY,EAAIlO,KAAKiO,QAAQjN,OAAQ,CAE7C,IADAwO,EAAcxP,KAAKiO,QAAQjO,KAAKkO,YAAY,IAC5BI,YAActO,KAAKmC,OAAOmM,UAAYtO,KAAKmC,OAAOO,WAYjE,OAAO,EAXP,IAAI+M,EAAYzP,KAAKmC,OAAOO,WACxBgN,EAAe1P,KAAKmC,OAAO2M,UAC3Ba,EAAe3P,KAAKmC,OAAOmM,UAO/B,OANAtO,KAAKiO,QAAQjO,KAAKkO,aAAehM,YAAYsM,OAAOxO,KAAKmC,OAAQqN,GACjExP,KAAKmC,OAASnC,KAAKiO,QAAQjO,KAAKkO,aAChClO,KAAKiO,QAAQgB,OAAOjP,KAAKkO,YAAY,EAAG,GACxClO,KAAKmC,OAAO2M,UAAYY,EACxB1P,KAAKmC,OAAOmM,UAAYqB,EACxBjQ,IAAIO,MAAM,UAAW,iDAAiDwP,EAAU,KAAKzP,KAAKmC,OAAOO,WAAW,MACrG,EAKR,OAAO,GAkBTsL,kBAAkBzL,UAAUqN,aAAe,SAASC,EAAWC,EAAcC,GAa5E,IAZA,IACIC,EAAU,KACVC,GAAS,EAKZpO,GAFiB,IAAdgO,EAEC,EAEA7P,KAAKkO,YAGHrM,EAAI7B,KAAKiO,QAAQjN,SACvBgP,EAAUhQ,KAAKiO,QAAQpM,IACXyM,WAAawB,GACxBG,EAAQpO,EACJkO,IACCC,EAAQ1B,UAAY0B,EAAQtN,YAAcoN,EAC7CE,EAAQlB,UAAYkB,EAAQtN,WAE5BsN,EAAQlB,UAAYgB,EAAeE,EAAQ1B,UAE5CtO,KAAKuO,kBAKP1M,IAGD,OAAe,IAAXoO,IACHD,EAAUhQ,KAAKiO,QAAQgC,IACX3B,UAAY0B,EAAQtN,YAAcoN,GAC7CpQ,IAAIO,MAAM,oBAAqB,sCAAsCgQ,GAC9DA,IAKA,GAWVjC,kBAAkBzL,UAAU2N,qBAAuB,SAASC,GAC3D,IAAItO,EAEAuO,EACAH,OAAwB1P,IAAf4P,EAA2BA,EAAanQ,KAAKkO,YAC1DmC,EAAarQ,KAAKiO,QAAQgC,GAE1B,GAAIjQ,KAAKiO,QAAQjN,OAASiP,EAAM,EAC/B,IAAKpO,EAAIoO,EAAM,EAAGpO,EAAI7B,KAAKiO,QAAQjN,SAClCoP,EAAUpQ,KAAKiO,QAAQpM,IACXyM,YAAc+B,EAAW/B,UAAY+B,EAAW3N,WAFlBb,IAGzCwO,EAAaD,EAOhB,OAAOC,EAAW/B,UAAY+B,EAAW3N,YAS1CsL,kBAAkBzL,UAAU+N,wBAA0B,SAASzN,GAC9D,IAAIoN,EAAQjQ,KAAK4P,cAAa,EAAM/M,GAAK,GACzC,OAAe,IAAXoN,EACIjQ,KAAKkQ,qBAAqBD,GAE1BpN,GAYTmL,kBAAkBzL,UAAUgO,aAAe,SAASC,GACnDxQ,KAAKmC,OAAO2M,WAAa0B,EACzBxQ,KAAKuO,kBAMNP,kBAAkBzL,UAAUkO,gBAAkB,WAC7CzQ,KAAKmC,OAAO2M,UAAY9O,KAAKmC,OAAOO,WACpC1C,KAAKuO,kBAkBNP,kBAAkBzL,UAAUK,KAAO,SAASkN,EAAcD,EAAWE,GAEpEE,EAAQjQ,KAAK4P,aAAaC,EAAWC,EAAcC,GACnD,OAAe,IAAXE,GACHjQ,KAAKmC,OAASnC,KAAKiO,QAAQgC,GAC3BjQ,KAAKkO,YAAc+B,EACnBjQ,KAAKsC,SAAWwN,EAAe9P,KAAKmC,OAAOmM,UAC3C5O,IAAIO,MAAM,oBAAqB,4CAA4CD,KAAKsC,WACzE,IAEP5C,IAAIO,MAAM,oBAAqB,YAAY6P,EAAa,gCACjD,IAQT9B,kBAAkBzL,UAAUC,YAAc,WACzC,IAA0B,IAAtBxC,KAAKkO,aAAyD,OAAnClO,KAAKiO,QAAQjO,KAAKkO,aAChD,KAAM,oDAEP,OAAOlO,KAAKiO,QAAQjO,KAAKkO,aAAaI,UAAUtO,KAAKsC,UAOtD0L,kBAAkBzL,UAAUI,UAAY,WACvC,OAAO3C,KAAK0C,YAGbsL,kBAAkBzL,UAAUE,eAAiB,WAC5C,IAA0B,IAAtBzC,KAAKkO,aAAyD,OAAnClO,KAAKiO,QAAQjO,KAAKkO,aAChD,KAAM,oDAEP,OAAOlO,KAAKiO,QAAQjO,KAAKkO,aAAaI,UAAUtO,KAAK0C,YAG/B,oBAAZX,UACVA,QAAQiM,kBAAoBA,mBAM7B,IAAI0C,sBAAwB,WAC3B,IAKIC,EAAgB,GACpBA,EANqB,GAMY,gBACjCA,EAN6B,GAMW,0BACxCA,EAN2B,GAMW,sBACtCA,EANyB,GAMW,qBAEpC3Q,KAAK4Q,kBAAoB,SAASC,GACjC,OAAOF,EAAcE,IAGtB,IAAIC,EAAO9Q,KACP+Q,EAAU,GAwId,OAtIA/Q,KAAKgR,mBAAqB,SAAUC,GACnC,IAIIC,EAHA7N,EAAO,EAIXwN,EAAMI,EAAOnN,YAIb,IAFAoN,EAAWD,EAAOnN,YAClBqN,EACkB,IAAXD,GACN7N,GAAmB,IAAX6N,IAAkB,EAC1BA,EAAWD,EAAOnN,YAClBqN,EAUD,OARA9N,GAAmB,IAAX6N,EACRxR,IAAIO,MAAM,wBAAyB,UAAU0Q,EAAcE,IAAQ,cAAcA,GAAK,UAAUxN,EAAK,gBAAgB4N,EAAOzO,gBAE3H4O,EAAO,IADJT,EAAcE,GACNE,EAAQJ,EAAcE,IAEtBE,EAAQM,YAFoBhO,IAInCiO,MAAML,GACJG,GAGRL,EAAQM,WAAa,SAASE,EAAMC,GACnCxR,KAAK6Q,IAAMU,EACXvR,KAAKqD,KAAOmO,EACZxR,KAAKyR,MAAQ,IAGdV,EAAQM,WAAW9O,UAAU+O,MAAQ,SAAUL,GAC9CjR,KAAK0R,KAAOT,EAAOjM,eAAehF,KAAKqD,OAGxC0N,EAAQM,WAAW9O,UAAUoP,eAAiB,SAAUd,GACvD,IAAK,IAAIhP,EAAI,EAAGA,EAAI7B,KAAKyR,MAAMzQ,OAAQa,IACtC,GAAI7B,KAAKyR,MAAM5P,GAAGgP,KAAOA,EACxB,OAAO7Q,KAAKyR,MAAM5P,GAGpB,OAAO,MAGRkP,EAAQM,WAAW9O,UAAUqP,0BAA4B,SAAUX,GAElE,IADA,IAAItR,EAAQsR,EAAO3O,SACZ2O,EAAO3O,SAAW3C,EAAMK,KAAKqD,MAAM,CACzC,IAAI+N,EAAON,EAAKE,mBAAmBC,GACnCjR,KAAKyR,MAAM/M,KAAK0M,KAIlBL,EAAQc,cAAgB,SAAUxO,GACjC0N,EAAQM,WAAWS,KAAK9R,KAxEJ,EAwEuBqD,IAG5C0N,EAAQc,cAActP,UAAY,IAAIwO,EAAQM,WAE9CN,EAAQc,cAActP,UAAU+O,MAAQ,SAASL,GAUhD,IACKc,EAVL/R,KAAKgS,MAAQf,EAAOlN,aACpB/D,KAAKiS,MAAQhB,EAAOnN,YACpB9D,KAAKqD,MAAQ,EACI,IAAbrD,KAAKiS,OACRjS,KAAKkS,gBAAkBjB,EAAOlN,aAC9B/D,KAAKqD,MAAQ,GAEbrD,KAAKkS,gBAAkB,EAEP,GAAblS,KAAKiS,OACJF,EAAId,EAAOnN,YACf9D,KAAK6J,IAAMoH,EAAO9M,WAAW4N,GAC7B/R,KAAKqD,MAAQ0O,EAAE,GAEf/R,KAAK6J,IAAM,GAEK,GAAb7J,KAAKiS,OACRjS,KAAKmS,UAAYlB,EAAOlN,aACxB/D,KAAKqD,MAAQ,GAEbrD,KAAKmS,UAAY,EAElBnS,KAAK4R,0BAA0BX,IAGhCF,EAAQc,cAActP,UAAU6P,OAAS,SAASnB,GACjD,IAAIoB,EAAMrS,KAAK2R,eAvGa,GAwG5B,OAAIU,EACIA,EAAIC,IAEJ,GAITvB,EAAQc,cAActP,UAAUgQ,eAAiB,SAAStB,GACzD,IAAIoB,EAAMrS,KAAK2R,eAhHa,GAiH5B,IAAKU,EAAK,OAAO,KACjB,IAAIG,EAAMH,EAAIV,eAjHY,GAkH1B,GAAIa,GAAOA,EAAId,KAAM,CAChBe,GAAgC,IAAbD,EAAId,KAAK,KAAa,EAI7C,OAHwB,KAApBe,GAA6C,GAAnBD,EAAId,KAAK1Q,SACtCyR,EAAkB,KAAqB,EAAdD,EAAId,KAAK,KAAa,KAAqB,IAAdc,EAAId,KAAK,KAAc,IAEvEe,EAEP,OAAO,MAIT1B,EAAQ2B,wBAA0B,SAAUrP,GAC3C0N,EAAQM,WAAWS,KAAK9R,KA/HI,EA+HyBqD,IAEtD0N,EAAQ2B,wBAAwBnQ,UAAY,IAAIwO,EAAQM,WAExDN,EAAQ2B,wBAAwBnQ,UAAU+O,MAAQ,SAASL,GAC1DjR,KAAKsS,IAAMrB,EAAOnN,YAClB9D,KAAK2S,WAAa1B,EAAOnN,YACzB9D,KAAK4S,WAAa3B,EAAOjN,aACzBhE,KAAK6S,WAAa5B,EAAOhN,aACzBjE,KAAK8S,WAAa7B,EAAOhN,aACzBjE,KAAKqD,MAAQ,GACbrD,KAAK4R,0BAA0BX,IAGhCF,EAAQgC,oBAAsB,SAAU1P,GACvC0N,EAAQM,WAAWS,KAAK9R,KA7IE,EA6IwBqD,IAEnD0N,EAAQgC,oBAAoBxQ,UAAY,IAAIwO,EAAQM,WAEpDN,EAAQiC,mBAAqB,SAAU3P,GACtC0N,EAAQM,WAAWS,KAAK9R,KAjJA,EAiJwBqD,IAEjD0N,EAAQiC,mBAAmBzQ,UAAY,IAAIwO,EAAQM,WAE5CrR,MAGe,oBAAZ+B,UACVA,QAAQ2O,sBAAwBA,uBAMjC,IAAIuC,UAAY,CACfC,kBAAoB,EACpBC,oBAAsB,EACtBC,GAAK,EAGLC,YAAa,CAAE,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QACvDC,WAAY,CAAE,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QAC9DC,gBAAiB,CAChB,CAAE,OAAQ,CAAE,OAAQ,SACpB,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,OAAQ,CAAE,OAAQ,SACpB,CAAE,OAAQ,CAAE,SACZ,CAAE,OAAQ,CAAE,SACZ,CAAE,OAAQ,CAAE,OAAQ,OAAQ,SAC5B,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,OAAQ,CAAE,SACZ,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,QACF,CAAE,OAAQ,CAAC,SACX,CAAE,OAAQ,CAAC,SACX,CAAE,SAGHC,SAAW,GACXC,aAAe,GACfC,kBAAoB,GACpBC,iBAAmB,GACnBC,sBAAuB,GACvBC,gBAAiB,GACjBC,UAAW,GACXC,MAAO,GACPC,WAAY,WACXf,UAAUgB,QAAQ1R,UAAY,IAAI0Q,UAAUiB,IAC5CjB,UAAUkB,aAAa5R,UAAY,IAAI0Q,UAAUiB,IACjDjB,UAAUmB,YAAY7R,UAAY,IAAI0Q,UAAUiB,IAChDjB,UAAUoB,kBAAkB9R,UAAY,IAAI0Q,UAAUgB,QAGtDhB,UAAUI,YAAYiB,QAAQ,SAASC,GACtCtB,UAAUuB,cAAcD,KAEzBtB,UAAUK,WAAWgB,QAAQ,SAASC,GACrCtB,UAAUwB,kBAAkBF,KAE7BtB,UAAUM,gBAAgBe,QAAQ,SAASI,GAC1CzB,UAAU0B,uBAAuBD,EAAM,GAAI,KAAMA,EAAM,OAGzDR,IAAK,SAASU,EAAOpD,EAAOqD,GAC3B7U,KAAKuU,KAAOK,EACZ5U,KAAKqD,KAAOmO,EACZxR,KAAK8U,KAAOD,GAEbZ,QAAS,SAASM,EAAMlR,EAAMyR,GAC7B7B,UAAUiB,IAAIpC,KAAK9R,KAAMuU,EAAMlR,EAAMyR,GACrC9U,KAAKiS,MAAQ,EACbjS,KAAK+U,QAAU,GAEhBZ,aAAc,SAASI,EAAMlR,EAAMyR,GAClC7B,UAAUiB,IAAIpC,KAAK9R,KAAMuU,EAAMlR,EAAMyR,GACrC9U,KAAKgV,MAAQ,IAEdZ,YAAa,SAASG,EAAMlR,EAAM4R,EAAUtV,GAC3CsT,UAAUkB,aAAarC,KAAK9R,KAAMuU,EAAMlR,GACxCrD,KAAKiV,SAAWA,EAChBjV,KAAKL,MAAQA,GAEduV,iBAAkB,SAASX,GAC1BvU,KAAKmV,cAAgBZ,GAEtBF,kBAAmB,SAASE,EAAMlR,GACjC4P,UAAUgB,QAAQnC,KAAK9R,KAAMuU,EAAMlR,IAEpCmR,cAAe,SAASD,EAAMa,GAC7BnC,UAAUO,SAAS9O,KAAK6P,GACxBtB,UAAUsB,EAAK,OAAS,SAASlR,GAChC4P,UAAUiB,IAAIpC,KAAK9R,KAAMuU,EAAMlR,IAEhC4P,UAAUsB,EAAK,OAAOhS,UAAY,IAAI0Q,UAAUiB,IAC5CkB,IAAanC,UAAUsB,EAAK,OAAOhS,UAAU+O,MAAQ8D,IAE1DX,kBAAmB,SAASF,EAAMa,GAEjCnC,UAAUsB,EAAK,OAAS,SAASlR,GAChC4P,UAAUgB,QAAQnC,KAAK9R,KAAMuU,EAAMlR,IAEpC4P,UAAUsB,EAAK,OAAOhS,UAAY,IAAI0Q,UAAUgB,QAChDhB,UAAUsB,EAAK,OAAOhS,UAAU+O,MAAQ,SAASL,GAChDjR,KAAKqV,gBAAgBpE,GACjBmE,GACHA,EAAYtD,KAAK9R,KAAMiR,KAI1BqE,gBAAiB,SAASC,GACzB,GAAIA,EAGH,IADA,IAAIC,GADJxV,KAAKuV,YAAcA,GACUvU,OACpB6H,EAAI,EAAGA,EAAE2M,EAAY3M,IAC7B7I,KAAKuV,EAAY1M,GAAG,KAAO,IAI9B8L,uBAAwB,SAASJ,EAAMa,EAAaG,GAEnDtC,UAAUsB,EAAK,OAAS,SAASlR,GAChC4P,UAAUkB,aAAarC,KAAK9R,KAAMuU,EAAMlR,GACxC4P,UAAUqC,gBAAgBxD,KAAK9R,KAAMuV,IAEtCtC,UAAUsB,EAAK,OAAOhS,UAAY,IAAI0Q,UAAUkB,aAC5CiB,IAAanC,UAAUsB,EAAK,OAAOhS,UAAU+O,MAAQ8D,IAE1DK,2BAA4B,SAASC,EAAWN,EAAaG,GAC5DtC,UAAUU,iBAAiB+B,GAAa,GACxCzC,UAAUyC,EAAU,eAAiB,SAASnB,EAAMlR,GACnD4P,UAAUmB,YAAYtC,KAAK9R,KAAMuU,EAAMlR,GACvC4P,UAAUqC,gBAAgBxD,KAAK9R,KAAMuV,IAEtCtC,UAAUyC,EAAU,eAAenT,UAAY,IAAI0Q,UAAUmB,YACzDgB,IAAanC,UAAUyC,EAAU,eAAenT,UAAW+O,MAAQ8D,IAExEO,sBAAuB,SAASD,EAAWnB,EAAMa,EAAaG,GAC7DtC,UAAUU,iBAAiB+B,GAAWhR,KAAK6P,GAC3CtB,UAAUsB,EAAK,eAAiB,SAASlR,GACxC4P,UAAUyC,EAAU,eAAe5D,KAAK9R,KAAMuU,EAAMlR,GACpD4P,UAAUqC,gBAAgBxD,KAAK9R,KAAMuV,IAEtCtC,UAAUsB,EAAK,eAAehS,UAAY,IAAI0Q,UAAUyC,EAAU,eAC9DN,IAAanC,UAAUsB,EAAK,eAAehS,UAAU+O,MAAQ8D,IAElEQ,+BAAgC,SAASF,EAAWnB,EAAMa,GACzDnC,UAAU0C,sBAAsB7D,KAAK9R,KAAM0V,EAAWnB,EAAMa,EAAa,CAAC,UAE3ES,sBAAuB,SAAStB,EAAMa,GAErCnC,UAAUsB,EAAK,oBAAsB,SAASlR,GAC7C4P,UAAUiC,iBAAiBpD,KAAK9R,KAAMuU,EAAMlR,IAE7C4P,UAAUsB,EAAK,oBAAoBhS,UAAY,IAAI0Q,UAAUiC,iBACzDE,IAAanC,UAAUsB,EAAK,oBAAoBhS,UAAU+O,MAAQ8D,IAEvEU,qBAAsB,SAASvB,EAAMa,GAEpCnC,UAAUsB,EAAK,qBAAuB,SAASlR,GAC9C4P,UAAUoB,kBAAkBvC,KAAK9R,KAAMuU,EAAMlR,IAE9C4P,UAAUsB,EAAK,qBAAqBhS,UAAY,IAAI0Q,UAAUoB,kBAC1De,IAAanC,UAAUsB,EAAK,qBAAqBhS,UAAU+O,MAAQ8D,IAExEW,cAAe,SAASjB,EAAMkB,EAAWC,EAAgBb,GACxDnC,UAAUc,MAAMrP,KAAKoQ,GACrB7B,UAAUa,UAAUgB,GAAQ,SAASzR,IAChC2S,EACH/C,UAAUgB,QAENgC,EACHhD,UAAUkB,aAEVlB,UAAUiB,KALOpC,KAAK9R,KAAM,OAAQqD,EAAMyR,IAS7C7B,UAAUa,UAAUgB,GAAMvS,UAAyB,IAAZyT,EAAgB/C,UAAUgB,QAAagC,EAAqBhD,UAAUkB,aAAqBlB,UAAUiB,KACxIkB,IAEFnC,UAAUa,UAAUgB,GAAMvS,UAAU+O,MADjC0E,EACyC,SAAS/E,GACpDjR,KAAKqV,gBAAgBpE,GACjBmE,GACHA,EAAYtD,KAAK9R,KAAMiR,IAImBmE,KAMhDnC,UAAUe,aAEVf,UAAUiD,kBAAuB,EACjCjD,UAAUkD,mBAAuB,EACjClD,UAAUmD,qBAAuB,EAEjCnD,UAAUoD,2BAA6B,EACvCpD,UAAUqD,sBAA0B,EACpCrD,UAAUsD,qBAAyB,EACnCtD,UAAUuD,sBAA0B,GACpCvD,UAAUwD,uBAA0B,GACpCxD,UAAUyD,oBAAwB,MAClCzD,UAAU0D,+BAAgC,OAE1C1D,UAAU2D,uBAAwB,EAClC3D,UAAU4D,sBAAwB,EAClC5D,UAAU6D,oBAAsB,IAChC7D,UAAU8D,gBAAmB,IAC7B9D,UAAU+D,iBAAoB,KAC9B/D,UAAUgE,sBAAwB,KAElChE,UAAUiB,IAAI3R,UAAU2U,IAAM,SAASC,GACtC,OAAOnX,KAAKoX,OAAO,IAAInE,UAAUkE,EAAK,SAGvClE,UAAUiB,IAAI3R,UAAU6U,OAAS,SAASC,GAOzC,OANArX,KAAKgV,MAAMtQ,KAAK2S,GACZrX,KAAKqX,EAAI9C,KAAK,KACjBvU,KAAKqX,EAAI9C,KAAK,KAAK7P,KAAK2S,GAExBrX,KAAKqX,EAAI9C,MAAQ8C,EAEXA,GAGRpE,UAAUiB,IAAI3R,UAAUiE,IAAM,SAAS8Q,EAAMvJ,GAE5C,OADA/N,KAAKsX,GAAQvJ,EACN/N,MAGRiT,UAAUiB,IAAI3R,UAAUgV,SAAW,SAASxJ,EAAOyJ,GAC9CF,EAAOE,GAAS,UAKpB,OAJKxX,KAAKsX,KACTtX,KAAKsX,GAAQ,IAEdtX,KAAKsX,GAAM5S,KAAKqJ,GACT/N,MAGe,oBAAZ+B,UACVA,QAAQkR,UAAYA,WAOrBA,UAAUwE,UAAY,SAASxG,GAC9B,OAAOgC,UAAUyE,WAAWzG,IAG7BgC,UAAUyE,WAAa,SAASzG,GAE/B,IADA,IAAI0G,EAAQ,GACH9V,EAAI,EAAGA,EAAG,GAAIA,IAAK,CAC3B,IAAI+V,EAAM3G,EAAOnN,YAAY+T,SAAS,IACtCF,GAAyB,IAAfC,EAAI5W,OAAe,IAAI4W,EAAMA,EAExC,OAAOD,GAGR1E,UAAU6E,YAAc,SAAS7G,EAAQ8G,EAAYC,GACpD,IAAIX,EAIAvC,EAHAnV,EAAQsR,EAAOzO,cACfyS,EAAW,EAGf,GAAIhE,EAAOxO,iBAAmB9C,EAAQ,EAErC,OADAD,IAAIO,MAAM,YAAa,mEAChB,CAAEgY,KAAMhF,UAAUE,qBAE1B,GAAI6E,GAAcA,EAAa,EAE9B,OADAtY,IAAIO,MAAM,YAAa,8DAChB,CAAEgY,KAAMhF,UAAUE,qBAE1B,IAAI9P,EAAO4N,EAAOhN,aACdsQ,EAAOtD,EAAO9M,WAAW,GACzB+T,EAAW3D,EAGf,GAFA7U,IAAIO,MAAM,YAAa,sBAAsBsU,EAAK,cAAclR,EAAK,gBAAgB1D,GACrFsV,EAAW,EACC,QAARV,EAAgB,CACnB,GAAKtD,EAAOxO,iBAAmBwO,EAAOzO,cAAgB,IAAQwV,EAAY/C,EAAW,GAGpF,OAFAhE,EAAOrO,KAAKjD,GACZD,IAAIO,MAAM,YAAa,+DAChB,CAAEgY,KAAMhF,UAAUE,qBAG1B8B,GAAY,GACZiD,EAFApD,EAAO7B,UAAUwE,UAAUxG,GAI5B,GAAY,GAAR5N,EAAW,CACd,GAAK4N,EAAOxO,iBAAmBwO,EAAOzO,cAAgB,GAAOwV,GAAeA,EAAa/C,EAAY,EAGpG,OAFAhE,EAAOrO,KAAKjD,GACZD,IAAIS,KAAK,YAAa,gEAAiEoU,EAAK,SACrF,CAAE0D,KAAMhF,UAAUE,qBAE1B9P,EAAO4N,EAAO/M,aACd+Q,GAAY,OACN,GAAa,IAAT5R,EAEV,GAAI2U,EACH3U,EAAO2U,OAGP,GAAa,SAATzD,EAGH,OAFA7U,IAAIU,MAAM,YAAa,+CAA+CmU,EAAK,KAC3E8C,EAAM,IAAIpE,UAAUiB,IAAIK,EAAMlR,GACvB,CAAE4U,KAAMhF,UAAUG,GAAIiE,IAAKA,EAAKhU,KAAMgU,EAAIhU,MAIpD,OAAIA,EAAO4R,GACVvV,IAAIU,MAAM,YAAa,eAAemU,EAAK,wBAAwBlR,EAAK,4BACjE,CAAE4U,KAAMhF,UAAUE,oBAAqBoB,KAAMA,EAAMlR,KAAMA,EAAM4R,SAAUA,EAAUtV,MAAOA,IAE9FqY,GAAqBA,EAAP3U,GACjB3D,IAAIU,MAAM,YAAa,gBAAgBmU,EAAK,gBAAgBlR,EAAK,oCAAoC2U,GAC9F,CAAEC,KAAMhF,UAAUE,oBAAqBoB,KAAMA,EAAMlR,KAAMA,EAAM4R,SAAUA,EAAUtV,MAAOA,IAE9FA,EAAQ0D,EAAO4N,EAAOxO,kBACzBwO,EAAOrO,KAAKjD,GACZD,IAAIQ,KAAK,YAAa,kDAAkDqU,EAAK,SACtE,CAAE0D,KAAMhF,UAAUE,oBAAqBoB,KAAMA,EAAMlR,KAAMA,EAAM4R,SAAUA,EAAUtV,MAAOA,IAE9FoY,EACI,CAAEE,KAAMhF,UAAUG,GAAImB,KAAMA,EAAMlR,KAAMA,EAAM4R,SAAUA,EAAUtV,MAAOA,IAE5EsT,UAAUsB,EAAK,OAClB8C,EAAM,IAAIpE,UAAUsB,EAAK,OAAOlR,GAEnB,SAATkR,GACH7U,IAAIS,KAAK,YAAa,sBAAsBoU,EAAK,MACjD8C,EAAM,IAAIpE,UAAUiB,IAAIK,EAAMlR,IAC1B8U,mBAAoB,GAEpBlF,UAAUa,UAAUgB,GACvBuC,EAAM,IAAIpE,UAAUa,UAAUgB,GAAMzR,IAEpC3D,IAAIS,KAAK,YAAa,uBAAuB2U,EAAK,MAClDuC,EAAM,IAAIpE,UAAUiB,IAAIK,EAAMlR,IAC1ByR,KAAOA,EACXuC,EAAIc,mBAAoB,GAK5Bd,EAAIpC,SAAWA,EAEfoC,EAAI1X,MAAQA,EACR0X,EAAIe,QAAUnF,UAAUiB,IAAI3R,UAAU6V,OAAsB,SAAbf,EAAI9C,OACtD7U,IAAIQ,KAAK,YAAa,IAAIgY,EAAS,sFACnCb,EAAIgB,mBAAmBpH,IAExBoG,EAAI/F,MAAML,IACVqH,EAAOrH,EAAOzO,eAAiB6U,EAAI1X,MAAM0X,EAAIhU,OAClC,GACV3D,IAAIS,KAAK,YAAa,mBAAmB+X,EAAS,+DAAgEI,EAAM,4BACxHrH,EAAOrO,KAAKyU,EAAI1X,MAAM0X,EAAIhU,OACT,EAAPiV,IACV5Y,IAAIU,MAAM,YAAa,mBAAmB8X,EAAS,UAAUI,EAAK,mEAClErH,EAAOrO,KAAKyU,EAAI1X,MAAM0X,EAAIhU,OAEpB,CAAE4U,KAAMhF,UAAUG,GAAIiE,IAAKA,EAAKhU,KAAMgU,EAAIhU,QAGlD4P,UAAUiB,IAAI3R,UAAU+O,MAAQ,SAASL,GACvB,QAAbjR,KAAKuU,KACRvU,KAAK0R,KAAOT,EAAOjM,eAAehF,KAAKqD,KAAKrD,KAAKiV,UAE/B,IAAdjV,KAAKqD,KACR4N,EAAOrO,KAAKqO,EAAOxO,kBAEnBwO,EAAOrO,KAAK5C,KAAKL,MAAMK,KAAKqD,OAO/B4P,UAAUiB,IAAI3R,UAAU8V,mBAAqB,SAASpH,GACrDjR,KAAK0R,KAAOT,EAAOjM,eAAehF,KAAKqD,KAAKrD,KAAKiV,UAEjDhE,EAAO3O,UAAYtC,KAAKqD,KAAKrD,KAAKiV,UAGnChC,UAAUgB,QAAQ1R,UAAU8V,mBAAqB,SAASpH,GACzDjR,KAAKqV,gBAAgBpE,GACrBjR,KAAK0R,KAAOT,EAAOjM,eAAehF,KAAKqD,KAAKrD,KAAKiV,UAEjDjV,KAAKiV,UAAY,EAEjBhE,EAAO3O,UAAYtC,KAAKqD,KAAKrD,KAAKiV,UAGnChC,UAAUgB,QAAQ1R,UAAU8S,gBAAkB,SAAUpE,GACvDjR,KAAK+U,QAAU9D,EAAOnN,YACtB9D,KAAKiS,MAAQhB,EAAOjN,aACpBhE,KAAKiV,UAAY,GAGlBhC,UAAUgB,QAAQ1R,UAAU+O,MAAQ,SAAUL,GAC7CjR,KAAKqV,gBAAgBpE,GACrBjR,KAAK0R,KAAOT,EAAOjM,eAAehF,KAAKqD,KAAKrD,KAAKiV,WAGlDhC,UAAUkB,aAAa5R,UAAU+O,MAAQ,SAASL,GAGjD,KAAOA,EAAOzO,cAAgBxC,KAAKL,MAAMK,KAAKqD,MAAM,CAEnD,IADAkV,EAAMtF,UAAU6E,YAAY7G,GAAQ,EAAOjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,SAC5EsY,OAAShF,UAAUG,GAe1B,OAXA,IAGK8E,EANLb,EAAMkB,EAAIlB,IAEVrX,KAAKgV,MAAMtQ,KAAK2S,GACZrX,KAAKuV,cAAsD,GAAvCvV,KAAKuV,YAAYiD,QAAQnB,EAAI9C,MACpDvU,KAAKA,KAAKuV,YAAYvV,KAAKuV,YAAYiD,QAAQnB,EAAI9C,OAAO,KAAK7P,KAAK2S,GAGhErX,KADAkY,EAAwB,SAAbb,EAAI9C,KAAkB8C,EAAI9C,KAAO8C,EAAIvC,MAEnDpV,IAAIS,KAAK,eAAe+X,EAAS,yCAEjClY,KAAKkY,GAAYb,IAStBpE,UAAUiB,IAAI3R,UAAUkW,cAAgB,SAASxH,GAChDjR,KAAK0Y,SAAWzH,EAAOlN,aACnB4U,EAAQ,GACZA,EAAM,GAAM3Y,KAAK0Y,UAAU,GAAI,GAC/BC,EAAM,GAAM3Y,KAAK0Y,UAAU,EAAG,GAC9BC,EAAM,GAAqB,GAAf3Y,KAAa,SACzBA,KAAK4Y,eAAiBvU,OAAOC,aAAaqU,EAAM,GAAG,GAAMA,EAAM,GAAG,GAAMA,EAAM,GAAG,KAIlF1F,UAAU4F,yBAA6B,SACvC5F,UAAU6F,wBAA4B,QACtC7F,UAAU8F,uBAA2B,OACrC9F,UAAU+F,2BAA8B,WACxC/F,UAAUgG,2BAA8B,WACxChG,UAAUiG,yBAA6B,SACvCjG,UAAUkG,uBAA2B,OAErClG,UAAUmB,YAAY7R,UAAU6W,YAAc,SAASnI,GACtDA,EAAOjM,eAAe,GACtBhF,KAAKqZ,qBAAuBpI,EAAOlN,aACnC/D,KAAKiV,UAAY,GAGlBhC,UAAUmB,YAAY7R,UAAU+O,MAAQ,SAASL,GAChDjR,KAAKoZ,YAAYnI,GACjBjR,KAAK0R,KAAOT,EAAOjM,eAAehF,KAAKqD,KAAOrD,KAAKiV,WAGpDhC,UAAUmB,YAAY7R,UAAU8V,mBAAqB,SAASpH,GAC7DjR,KAAKoZ,YAAYnI,GACjBjR,KAAK0R,KAAOT,EAAOjM,eAAehF,KAAKqD,KAAOrD,KAAKiV,UAEnDjV,KAAKiV,UAAY,EAEjBhE,EAAO3O,UAAYtC,KAAKqD,KAAKrD,KAAKiV,UAGnChC,UAAUmB,YAAY7R,UAAU+W,YAAc,SAASrI,GACtDgC,UAAUkB,aAAa5R,UAAU+O,MAAMQ,KAAK9R,KAAMiR,IAInDgC,UAAUwC,2BAA2BxC,UAAU8F,wBAC/C9F,UAAUwC,2BAA2BxC,UAAU+F,4BAC/C/F,UAAUwC,2BAA2BxC,UAAUgG,4BAC/ChG,UAAUwC,2BAA2BxC,UAAUiG,0BAC/CjG,UAAUwC,2BAA2BxC,UAAUkG,wBAG/ClG,UAAUwC,2BAA2BxC,UAAU4F,yBAA0B,SAAS5H,GACjF,IAAIsI,EACJvZ,KAAKoZ,YAAYnI,GACjBA,EAAOlN,aACPkN,EAAOlN,aACPkN,EAAO5L,gBAAgB,GACvBrF,KAAKwZ,MAAQvI,EAAOlN,aACpB/D,KAAKyZ,OAASxI,EAAOlN,aACrB/D,KAAK0Z,gBAAkBzI,EAAOhN,aAC9BjE,KAAK2Z,eAAiB1I,EAAOhN,aAC7BgN,EAAOhN,aACPjE,KAAK4Z,YAAc3I,EAAOlN,aAC1BwV,EAAwBjY,KAAK0B,IAAI,GAAIiO,EAAOnN,aAC5C9D,KAAK6Z,eAAiB5I,EAAO9M,WAAWoV,GACpCA,EAAwB,IAC3BtI,EAAO9M,WAAW,GAAKoV,GAExBvZ,KAAK8Z,MAAQ7I,EAAOlN,aACpBkN,EAAOlN,aACP/D,KAAKsZ,YAAYrI,KAGlBgC,UAAUwC,2BAA2BxC,UAAU6F,wBAAyB,SAAS7H,GAChFjR,KAAKoZ,YAAYnI,GACjBA,EAAO5L,gBAAgB,GACvBrF,KAAK+Z,cAAgB9I,EAAOlN,aAC5B/D,KAAKga,WAAa/I,EAAOlN,aACzBkN,EAAOlN,aACPkN,EAAOlN,aACP/D,KAAKia,WAAchJ,EAAOhN,aAAa,MACvCjE,KAAKsZ,YAAYrI,KAIlBgC,UAAU0C,sBAAsB1C,UAAU4F,yBAA0B,QACpE5F,UAAU0C,sBAAsB1C,UAAU4F,yBAA0B,QACpE5F,UAAU0C,sBAAsB1C,UAAU4F,yBAA0B,QACpE5F,UAAU0C,sBAAsB1C,UAAU4F,yBAA0B,QACpE5F,UAAU0C,sBAAsB1C,UAAU4F,yBAA0B,QACpE5F,UAAU0C,sBAAsB1C,UAAU4F,yBAA0B,QACpE5F,UAAU0C,sBAAsB1C,UAAU4F,yBAA0B,QACpE5F,UAAU0C,sBAAsB1C,UAAU6F,wBAA0B,QACpE7F,UAAU0C,sBAAsB1C,UAAU6F,wBAA0B,QACpE7F,UAAU0C,sBAAsB1C,UAAU6F,wBAA0B,QAGpE7F,UAAU2C,+BAA+B3C,UAAU4F,yBAA2B,QAC9E5F,UAAU2C,+BAA+B3C,UAAU6F,wBAA0B,QAC7E7F,UAAU2C,+BAA+B3C,UAAUgG,2BAA6B,QAChFhG,UAAU2C,+BAA+B3C,UAAUiG,yBAA2B,QAC9EjG,UAAU2C,+BAA+B3C,UAAUkG,uBAA0B,QAC7ElG,UAAU2C,+BAA+B3C,UAAU+F,2BAA6B,QAIhF/F,UAAUuB,cAAc,OAAQ,SAASvD,GACxC,IACIiJ,EAAuC,IAAL,GAAL,GADK,EAArBjJ,EAAOnN,eAExB9D,KAAKma,WAAa,GAClB,IAAK,IAAItY,EAAI,EAAGA,EAAI,EAAGA,IAErB7B,KAAKma,WAAWtY,GADE,IAAfqY,EACkBjJ,EAAOlN,aAEPkN,EAAOhN,eAI/BgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKoa,SAAWnJ,EAAOnN,cAExBmP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKqa,SAAWpJ,EAAO1M,cACvB,IAAI+V,EAAqBta,KAAKqD,KAAOrD,KAAKiV,UAAYjV,KAAKqa,SAASrZ,OAAS,GAC7EhB,KAAKua,YAActJ,EAAOjM,eAAesV,KAE1CrH,UAAUuB,cAAc,OAAQ,SAASvD,GACxC,IAEInI,EAAMmI,EAAOnN,YACjB,GAAKgF,GAAO,GAAK,EAChBpJ,IAAIU,MAAM,4BAIX,GADAJ,KAAK+U,QAAgB,IAANjM,EACM,IAAjB9I,KAAK+U,QAiBT,GAbAjM,EAAMmI,EAAOnN,YACb9D,KAAKwa,YAAe1R,GAAO,EAAK,EAChC9I,KAAKya,gBAAwB,GAAN3R,EACvBA,EAAMmI,EAAOnN,YACb9D,KAAK0a,WAAc5R,GAAO,EAAK,EAC/B9I,KAAK2a,cAAiB7R,GAAO,EAAK,EAClC9I,KAAK4a,WAAc9R,GAAO,EAAK,EAC/B9I,KAAK6a,WAAc/R,GAAO,EAAK,EAC/B9I,KAAK8a,qBAAwBhS,GAAO,EAAK,EACzC9I,KAAK+a,qBAAwBjS,GAAO,EAAK,EACzC9I,KAAKgb,uBAAgC,EAANlS,EAC/BA,EAAMmI,EAAOnN,YACb9D,KAAKib,WAAcnS,GAAO,EAAK,EACP,IAApB9I,KAAKib,WAAT,CAKA,GADAjb,KAAKkb,mCAAsCpS,GAAO,EAAK,EACP,IAA5C9I,KAAKkb,mCACRlb,KAAKmb,qCAA8C,GAANrS,OAG7C,GADA9I,KAAKob,WAAoB,GAANtS,EACK,IAApB9I,KAAKob,WAER,YADA1b,IAAIU,MAAM,mCAKRib,EAAoBrb,KAAKqD,KAAOrD,KAAKiV,SAAW,EACpDjV,KAAKsb,WAAarK,EAAOjM,eAAeqW,QAfvC3b,IAAIU,MAAM,wCAjBVV,IAAIU,MAAM,gBAAgBJ,KAAK+U,QAAQ,oBAoCzC9B,UAAUuB,cAAc,OAAQ,SAASvD,GACxC,IAAIpP,EACA0Z,EASJ,IARAvb,KAAKwb,qBAAuBvK,EAAOnN,YACnC9D,KAAKyb,qBAAuBxK,EAAOnN,YACnC9D,KAAK0b,sBAAwBzK,EAAOnN,YACpC9D,KAAK2b,mBAAqB1K,EAAOnN,YACjC9D,KAAK4b,mBAA2C,EAArB3K,EAAOnN,YAClC9D,KAAK6b,aAAqC,GAArB5K,EAAOnN,YAC5ByX,EAAUvb,KAAKqD,KAAOrD,KAAKiV,SAAW,EACtCjV,KAAK8b,IAAM,GACNja,EAAI,EAAGA,EAAI7B,KAAK6b,aAAcha,IAClC7B,KAAK8b,IAAIja,GAAK,GACd7B,KAAK8b,IAAIja,GAAGb,OAASiQ,EAAOlN,aAC5B/D,KAAK8b,IAAIja,GAAGka,KAAO9K,EAAOjM,eAAehF,KAAK8b,IAAIja,GAAGb,QACrDua,GAAW,EAAEvb,KAAK8b,IAAIja,GAAGb,OAK1B,IAHAhB,KAAKgc,aAAe/K,EAAOnN,YAC3ByX,IACAvb,KAAKic,IAAM,GACNpa,EAAI,EAAGA,EAAI7B,KAAKgc,aAAcna,IAClC7B,KAAKic,IAAIpa,GAAK,GACd7B,KAAKic,IAAIpa,GAAGb,OAASiQ,EAAOlN,aAC5B/D,KAAKic,IAAIpa,GAAGka,KAAO9K,EAAOjM,eAAehF,KAAKic,IAAIpa,GAAGb,QACrDua,GAAW,EAAEvb,KAAKic,IAAIpa,GAAGb,OAEd,EAARua,IACHvb,KAAKkc,IAAMjL,EAAOjM,eAAeuW,MAKnCtI,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKmc,aAAelL,EAAOhN,aAC3BjE,KAAK6S,WAAa5B,EAAOhN,aACzBjE,KAAK8S,WAAa7B,EAAOhN,eAI1BgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKoc,oBAAsBnL,EAAOhN,aAClCjE,KAAKqc,oBAAsBpL,EAAOhN,aAClCjE,KAAKsc,qBAAuBrL,EAAOhN,aACnCjE,KAAKuc,qBAAuBtL,EAAOhN,aACnCjE,KAAKwc,UAAYvL,EAAOhN,aACxBjE,KAAKyc,UAAYxL,EAAOhN,aACxBjE,KAAK0c,SAAWzL,EAAOhN,aACvBjE,KAAK2c,SAAW1L,EAAOhN,eAExBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAK4c,wBAA0B3L,EAAOlN,aACnC/D,KAAK6c,4BAA8B5L,EAAOlN,eAI9CkP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACIpP,EACJib,EAAc7L,EAAOhN,aAErB,GADAjE,KAAK+c,cAAgB,GACA,IAAjB/c,KAAK+U,QACR,IAAIlT,EAAE,EAAGA,EAAEib,EAAajb,IACvB7B,KAAK+c,cAAcrY,KAAKuM,EAAO/M,gBAMlC+O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKgd,OAAS/L,EAAOlN,aAClB/D,KAAKid,QAAUhM,EAAOlN,eAI1BkP,UAAUuB,cAAc,OAAQ,SAASvD,GAExC,IAIKnI,EALL9I,KAAKkd,YAAcjM,EAAO9M,WAAW,GACZ,SAArBnE,KAAKkd,aACRld,KAAKmd,iBAAmBlM,EAAOlN,aAC/B/D,KAAKod,yBAA2BnM,EAAOlN,aACvC/D,KAAKqd,oBAAsBpM,EAAOlN,aAC9B+E,EAAMmI,EAAOnN,YACjB9D,KAAKsd,gBAAkBxU,GAAO,GACC,SAArB9I,KAAKkd,aAEgB,SAArBld,KAAKkd,cADfld,KAAKud,YAActM,EAAOjM,eAAehF,KAAKqD,KAAO,MAKvD4P,UAAUwB,kBAAkB,OAAQ,SAAUxD,GAC7CjR,KAAKyY,cAAcxH,GACnBjR,KAAKwd,OAASvM,EAAO1M,gBAItB0O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAEvB,IAAjBjR,KAAK+U,UACR/U,KAAKyd,sBAAwBxM,EAAOnM,YACpC9E,KAAK0d,0BAA4BzM,EAAOnM,YACxC9E,KAAK2d,6BAA+B1M,EAAOnM,YAC3C9E,KAAK4d,qBAAuB3M,EAAOnM,YACnC9E,KAAK6d,mBAAqB5M,EAAOnM,eAKnCmO,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACIpP,EACJib,EAAc7L,EAAOhN,aAGrB,GAFAjE,KAAK8d,cAAgB,GACrB9d,KAAK+d,eAAiB,GACD,IAAjB/d,KAAK+U,QACR,IAAIlT,EAAE,EAAGA,EAAEib,EAAajb,IAAK,CAC5B7B,KAAK8d,cAAcpZ,KAAKuM,EAAOhN,cAI5B,IAAI8J,EAAQkD,EAAOnM,YACfiJ,EAAQ,GACVrO,IAAIS,KAAK,YAAa,yDAE3BH,KAAK+d,eAAerZ,KAAKqJ,QAEpB,GAAoB,GAAhB/N,KAAK+U,QACf,IAAIlT,EAAE,EAAGA,EAAEib,EAAajb,IACvB7B,KAAK8d,cAAcpZ,KAAKuM,EAAOhN,cAC/BjE,KAAK+d,eAAerZ,KAAKuM,EAAOnM,eAMnCmO,UAAUuB,cAAc,OAAQ,SAASvD,GACxC,IAAI+M,EAAY/M,EAAOnN,YACnBma,EAAYhN,EAAOnN,YACnBoa,EAAYjN,EAAOnN,YACvB9D,KAAKme,MAAQH,GAAa,EAC1Bhe,KAAKoe,KAAUJ,GAAa,EAAK,GACjChe,KAAKqe,OAAsB,EAAZL,IAAqB,EAAOC,GAAa,EAAK,EAC7Dje,KAAKse,MAAUL,GAAa,EAAK,EACjCje,KAAKue,MAAUN,GAAa,EAAK,EACjCje,KAAKwe,cAA6B,EAAZP,EAAqBC,GAAa,EAAK,IAI9DjL,UAAUuB,cAAc,OAAQ,SAASvD,GACxC,IAAIwN,EAASxN,EAAOlN,aACpB/D,KAAK0e,UAAYD,GAAU,EAC3Bze,KAAK2e,YAAuB,EAATF,EACnBze,KAAK4e,SAAW,GAChB,IAAK,IAAI/c,EAAI,EAAGA,EAAI7B,KAAK2e,YAAY,EAAG9c,IAAK,CAC5C,IAAIgd,EAAU,GACd7e,KAAK4e,SAASla,KAAKma,GACnB,IAAIb,EAAY/M,EAAOnN,YACnBma,EAAYhN,EAAOnN,YACnBoa,EAAYjN,EAAOnN,YACvB+a,EAAQV,MAAQH,GAAa,EAC7Ba,EAAQT,KAAUJ,GAAa,EAAK,GACpCa,EAAQR,OAAsB,EAAZL,IAAoB,EAAOC,GAAa,EAAK,GAC/DY,EAAQP,MAAUL,GAAa,EAAK,EACpCY,EAAQN,MAAqB,EAAZN,EACjBY,EAAQC,YAAgBZ,GAAa,EAAK,GAChB,EAAtBW,EAAQC,cACXD,EAAQE,UAAyB,EAAZb,IAAoB,EAAKjN,EAAOnN,gBAMxDmP,UAAUwB,kBAAkB,OAAQ,SAASxD,GACzC,IAGI+N,EAAa,GACbC,EAAkB,CAClB,aACA,UACA,cACA,YACA,iBACA,WACA,UACA,YAOJ,IAHAjf,KAAKqV,gBAAgBpE,KAGlB,CACC,IAAIiO,EAAcjO,EAAOnN,YAErByQ,EAAOjT,KAAK0B,IAtBC,IAuBZkc,EACAD,EAAgBje,OAAS,GAqB9B,GAhBK,EAWDiQ,EAAOjM,eAAeiM,EAAOjN,eAT7BiN,EAAOjM,eAAe,IAGtBhF,KAAKia,WAAchJ,EAAOhN,cAAgB,GAG1CgN,EAAOjM,eAAe,KAM1Bga,EAAWta,KAAKua,EAAgB1K,IA1CH,IA4CtB2K,EACH,MAIRlf,KAAKmf,kBACDH,EAAWhe,OAAS,KAAOge,EAAW7d,KAAK,MAAQ,MAG3D8R,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKof,UAAYnO,EAAO/M,eAIzB+O,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKqf,KAAOpO,EAAOhN,eAIpBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKof,UAAYnO,EAAO/M,eAIzB+O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACIoG,EACJrX,KAAKsf,QAAU,GAEf,IADA,IAAIxC,EAAc7L,EAAOhN,aAChBpC,EAAI,EAAGA,EAAIib,EAAajb,IAAK,CAErC,IADA0W,EAAMtF,UAAU6E,YAAY7G,GAAQ,EAAOjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,SAC5EsY,OAAShF,UAAUG,GAI1B,OAHAiE,EAAMkB,EAAIlB,IACVrX,KAAKsf,QAAQ5a,KAAK2S,MAQrBpE,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKof,UAAYnO,EAAO/M,eAIzB+O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKuf,kBAAoBtO,EAAO9M,WAAWnE,KAAKqD,KAAKrD,KAAKiV,YAI3DhC,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKsf,QAAU,GAEf,IADA,IAAIxC,EAAc7L,EAAOhN,aAChBpC,EAAI,EAAGA,EAAIib,EAAajb,IAAK,CACrC,IAAI2d,EAAQ,GACZxf,KAAKsf,QAAQ5a,KAAK8a,GACG,IAAjBxf,KAAK+U,SACRyK,EAAMC,iBAAmBxO,EAAO/M,aAChCsb,EAAME,WAAazO,EAAOlM,cAE1Bya,EAAMC,iBAAmBxO,EAAOhN,aAChCub,EAAME,WAAazO,EAAOnM,aAE3B0a,EAAMG,mBAAqB1O,EAAOpM,YAClC2a,EAAMI,oBAAsB3O,EAAOpM,eAKrCoO,UAAUwB,kBAAkB,OAAQ,SAASxD,GACxB,GAAhBjR,KAAK+U,SACR/U,KAAK6f,UAAiB5O,EAAOhN,aAC7BjE,KAAK8f,kBAAuB7O,EAAO/M,aACnClE,KAAK+f,eAAqB9O,EAAOhN,aACjCjE,KAAKggB,GAAW/O,EAAOhN,aACvBjE,KAAKigB,cAAoBhP,EAAO1M,cAChCvE,KAAK+N,MAAckD,EAAO1M,gBAE1BvE,KAAKigB,cAAoBhP,EAAO1M,cAChCvE,KAAK+N,MAAckD,EAAO1M,cAC1BvE,KAAK6f,UAAiB5O,EAAOhN,aAC7BjE,KAAKkgB,wBAA2BjP,EAAOhN,aACvCjE,KAAK+f,eAAqB9O,EAAOhN,aACjCjE,KAAKggB,GAAW/O,EAAOhN,cAExB,IAAIkc,EAAengB,KAAKqD,KAAOrD,KAAKiV,UAAY,IAAOjV,KAAKigB,cAAcjf,OAAO,IAAMhB,KAAK+N,MAAM/M,OAAO,IACrF,GAAhBhB,KAAK+U,UACRoL,GAAgB,GAEjBngB,KAAKogB,aAAenP,EAAOjM,eAAemb,KAI3ClN,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIoP,EAAWpP,EAAOjM,eAAehF,KAAKqD,KAAKrD,KAAKiV,eACf,IAA1BvE,wBACN4P,EAAa,IAAI5P,sBACrB1Q,KAAKugB,IAAMD,EAAWtP,mBAAmB,IAAIvL,WAAW4a,EAASle,OAAQ,EAAGsD,WAAWkB,gBAKzFsM,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKwgB,WAAavP,EAAOnN,YACzB9D,KAAKygB,cAAgBxP,EAAOnN,cAI7BmP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAK0gB,YAAczP,EAAO9M,WAAW,KAItC8O,UAAUuB,cAAc,OAAQ,SAASvD,GACxC,IAAIsK,EAAUvb,KAAKqD,KAAOrD,KAAKiV,SAC/BjV,KAAK2gB,YAAc1P,EAAO9M,WAAW,GACrCnE,KAAK4gB,cAAgB3P,EAAOhN,aAC5BsX,GAAW,EACXvb,KAAK6gB,kBAAoB,GAEzB,IADA,IAAIhf,EAAI,EACQ,GAAT0Z,GACNvb,KAAK6gB,kBAAkBhf,GAAKoP,EAAO9M,WAAW,GAC9CoX,GAAW,EACX1Z,MAKFoR,UAAUwB,kBAAkB,OAAQ,SAASxD,GACvB,IAAjBjR,KAAK+U,UACR9D,EAAOhN,aACPjE,KAAK8gB,QAAU7P,EAAO9M,WAAW,GACjC8M,EAAO5L,gBAAgB,GACvBrF,KAAKmX,KAAOlG,EAAO9M,WAAWnE,KAAKqD,KAAKrD,KAAKiV,SAAS,IAClB,OAAhCjV,KAAKmX,KAAKnX,KAAKmX,KAAKnW,OAAO,KAC9BhB,KAAKmX,KAAOnX,KAAKmX,KAAK4J,MAAM,GAAG,OAMlC9N,UAAUuB,cAAc,OAAQ,SAASvD,GACxC,IAEIjQ,EACAggB,EACJhhB,KAAKwb,qBAAuBvK,EAAOnN,YACnCkd,EAAW/P,EAAOnN,YAClB9D,KAAKihB,sBAAwBD,GAAY,EACzChhB,KAAKkhB,mBAAgC,GAAXF,IAAoB,EAC9ChhB,KAAKmhB,oBAAkC,GAAXH,EAC5BhhB,KAAKohB,8BAAgCnQ,EAAOhN,aAC5CjE,KAAKqhB,6BAA+BpQ,EAAOjM,eAAe,GAC1DhF,KAAKshB,kBAAoBrQ,EAAOnN,YAChC9D,KAAKuhB,6BAAqD,KAAtBtQ,EAAOlN,aAC3C/D,KAAKwhB,gBAAwC,EAArBvQ,EAAOnN,YAC/B9D,KAAKyhB,kBAA0C,EAArBxQ,EAAOnN,YACjC9D,KAAK0hB,sBAA8C,EAArBzQ,EAAOnN,YACrC9D,KAAK2hB,wBAAgD,EAArB1Q,EAAOnN,YACvC9D,KAAK4hB,aAAe3Q,EAAOlN,aAC3Bid,EAAW/P,EAAOnN,YAClB9D,KAAK6hB,kBAAqBb,GAAY,EACtChhB,KAAK8hB,mBAAgC,GAAXd,IAAmB,EAC7ChhB,KAAK+hB,kBAA+B,EAAXf,IAAmB,EAC5ChhB,KAAK4b,mBAAiC,EAAXoF,EAE3BhhB,KAAKgiB,YAAc,GAEnB,IADA,IAAIC,EAAchR,EAAOnN,YACpBjC,EAAI,EAAGA,EAAIogB,EAAapgB,IAAK,CACjC,IAAIqgB,EAAa,GACjBliB,KAAKgiB,YAAYtd,KAAKwd,GACtBlB,EAAW/P,EAAOnN,YAClBoe,EAAWC,cAA2B,IAAXnB,IAAoB,EAC/CkB,EAAWE,UAAuB,GAAXpB,EAEvB,IADA,IAAIqB,EAAWpR,EAAOlN,aACjB6E,EAAI,EAAGA,EAAIyZ,EAAUzZ,IAAK,CAC9B,IAAImT,EAAO,GACXmG,EAAWxd,KAAKqX,GAChB/a,EAASiQ,EAAOlN,aAChBgY,EAAKrK,KAAST,EAAOjM,eAAehE,OAMvCiS,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIsH,EACiB,IAAjBvY,KAAK+U,QACR/U,KAAK8c,YAAc7L,EAAOlN,aAE1B/D,KAAK8c,YAAc7L,EAAOhN,aAE3BjE,KAAKsiB,WAAa,GAClB,IAAK,IAAIzgB,EAAI,EAAGA,EAAI7B,KAAK8c,YAAajb,IAAK,CAE1C,IADA0W,EAAMtF,UAAU6E,YAAY7G,GAAQ,EAAOjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,SAC5EsY,OAAShF,UAAUG,GAM1B,OALqB,SAAjBmF,EAAIlB,IAAI9C,MACX7U,IAAIU,MAAM,YAAa,4BAA4BmY,EAAIlB,IAAI9C,MAE5DvU,KAAKsiB,WAAWzgB,GAAK0W,EAAIlB,OAQ5BpE,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACAsR,EAAOtR,EAAOnN,YACd9D,KAAKwiB,YAAeD,GAAQ,EAAK,GACjCviB,KAAKyiB,YAAqB,GAAPF,EACnBA,EAAOtR,EAAOnN,YACd9D,KAAK0iB,iBAAoBH,GAAQ,EAAK,GACjB,IAAjBviB,KAAK+U,SAAkC,IAAjB/U,KAAK+U,QAC9B/U,KAAK2iB,WAAoB,GAAPJ,EAElBviB,KAAK2iB,WAAa,EAGnB3iB,KAAK4iB,MAAQ,GACb,IAAIC,EAAa,EACjB,GAAI7iB,KAAK+U,QAAU,EAClB8N,EAAa5R,EAAOlN,iBACd,CAAA,GAAqB,IAAjB/D,KAAK+U,QAGf,KAAM,oCAFN8N,EAAa5R,EAAOhN,aAIrB,IAAK,IAAIpC,EAAI,EAAGA,EAAIghB,EAAYhhB,IAAK,CACpC,IAAIihB,EAAO,GAEX,GADA9iB,KAAK4iB,MAAMle,KAAKoe,GACZ9iB,KAAK+U,QAAU,EAClB+N,EAAKC,QAAU9R,EAAOlN,iBAChB,CAAA,GAAqB,IAAjB/D,KAAK+U,QAGf,KAAM,oCAFN+N,EAAKC,QAAU9R,EAAOlN,aAUvB,OANqB,IAAjB/D,KAAK+U,SAAkC,IAAjB/U,KAAK+U,QAC9B+N,EAAKE,oBAA6C,GAAtB/R,EAAOlN,aAEnC+e,EAAKE,oBAAsB,EAE5BF,EAAKzJ,qBAAuBpI,EAAOlN,aAC5B/D,KAAK0iB,kBACX,KAAK,EACJI,EAAKG,YAAc,EACnB,MACD,KAAK,EACJH,EAAKG,YAAchS,EAAOhN,aAC1B,MACD,KAAK,EACJ6e,EAAKG,YAAchS,EAAO/M,aAC1B,MACD,QACC,KAAM,iCAER,IAAIgf,EAAejS,EAAOlN,aAC1B+e,EAAKK,QAAU,GACf,IAAK,IAAIva,EAAE,EAAGA,EAAIsa,EAActa,IAAK,CACpC,IAAIwa,EAAS,GAEb,GADAN,EAAKK,QAAQze,KAAK0e,GACG,IAAjBpjB,KAAK+U,SAAkC,IAAjB/U,KAAK+U,QAC9B,OAAO/U,KAAK2iB,YACX,KAAK,EACJS,EAAOC,aAAe,EACtB,MACD,KAAK,EACJD,EAAOC,aAAepS,EAAOhN,aAC7B,MACD,KAAK,EACJmf,EAAOC,aAAepS,EAAO/M,aAC7B,MACD,QACC,KAAM,6BAGT,OAAOlE,KAAKwiB,aACX,KAAK,EACJY,EAAOE,cAAgB,EACvB,MACD,KAAK,EACJF,EAAOE,cAAgBrS,EAAOhN,aAC9B,MACD,KAAK,EACJmf,EAAOE,cAAgBrS,EAAO/M,aAC9B,MACD,QACC,KAAM,6BAER,OAAOlE,KAAKyiB,aACX,KAAK,EACJW,EAAOG,cAAgB,EACvB,MACD,KAAK,EACJH,EAAOG,cAAgBtS,EAAOhN,aAC9B,MACD,KAAK,EACJmf,EAAOG,cAAgBtS,EAAO/M,aAC9B,MACD,QACC,KAAM,kCAOX+O,UAAUuB,cAAc,OAAQ,SAASvD,GACpCnI,EAAMmI,EAAOnN,YACjB9D,KAAKwjB,SAAW1a,GAAO,EACvB9I,KAAKyjB,KAAa,EAAN3a,IAEbmK,UAAUwB,kBAAkB,OAAQ,SAASxD,GAQ5C,OAPqB,IAAjBjR,KAAK+U,SAAkC,IAAjB/U,KAAK+U,UAC9B/U,KAAK+iB,QAAU9R,EAAOlN,aACtB/D,KAAK0jB,sBAAwBzS,EAAOlN,aACpC/D,KAAK2jB,UAAY1S,EAAO1M,cACxBvE,KAAK4jB,aAAe3S,EAAO1M,cAC3BvE,KAAK6jB,iBAAmB5S,EAAO1M,eAEX,IAAjBvE,KAAK+U,SACR/U,KAAK8jB,eAAiB7S,EAAO9M,WAAW,GACxCzE,IAAIS,KAAK,YAAa,oCACtB8Q,EAAOrO,KAAK5C,KAAKL,MAAMK,KAAKqD,YAGT,GAAhBrD,KAAK+U,UACa,IAAjB/U,KAAK+U,QACR/U,KAAK+iB,QAAU9R,EAAOlN,aACK,IAAjB/D,KAAK+U,UACf/U,KAAK+iB,QAAU9R,EAAOhN,cAEvBjE,KAAK0jB,sBAAwBzS,EAAOlN,aACpC/D,KAAK+jB,UAAY9S,EAAO9M,WAAW,GACnCnE,KAAK2jB,UAAY1S,EAAO1M,cACD,SAAnBvE,KAAK+jB,WACR/jB,KAAK4jB,aAAe3S,EAAO1M,cAC3BvE,KAAK6jB,iBAAmB5S,EAAO1M,eACF,SAAnBvE,KAAK+jB,YACf/jB,KAAKgkB,cAAgB/S,EAAO1M,mBAK/B0O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIpP,EAAG+G,EAGP,IAFAkU,YAAc7L,EAAOhN,aACrBjE,KAAKikB,aAAe,GAChBpiB,EAAE,EAAGA,EAAEib,YAAajb,IAAK,CAC5B,IAAIqiB,EAAa,GACjBlkB,KAAKikB,aAAavf,KAAKwf,GACnBlkB,KAAK+U,QAAU,EAClBmP,EAAWlE,GAAK/O,EAAOlN,aAEvBmgB,EAAWlE,GAAK/O,EAAOhN,aAExB,IAAIkgB,EAAoBlT,EAAOnN,YAE/B,IADAogB,EAAWE,MAAQ,GACdxb,EAAI,EAAGA,EAAIub,EAAmBvb,IAAK,CACvC,IAAIE,EAAMmI,EAAOnN,YACbugB,EAAI,GACRH,EAAWE,MAAM1f,KAAK2f,GACtBA,EAAEC,WAAoB,IAANxb,IAAe,GAAO,EACrB,EAAb9I,KAAKiS,MACRoS,EAAEE,gBAAwB,IAANzb,IAAe,EAAImI,EAAOnN,YAE9CugB,EAAEE,eAAwB,IAANzb,MAOxBmK,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAEIoG,EAGJ,IAFArX,KAAKwkB,WAAa,GAEXvT,EAAOzO,cAAgBxC,KAAKL,MAAMK,KAAKqD,MAAM,CAEnD,IADAkV,EAAMtF,UAAU6E,YAAY7G,GAAQ,EAAMjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,SAC3EsY,OAAShF,UAAUG,GAa1B,QAXCiE,EAAM,IADc,IAAjBrX,KAAK+U,QACE9B,UAAUwR,2BAEVxR,UAAUyR,iCAF2BnM,EAAIhE,KAAMgE,EAAIlV,KAAMkV,EAAItD,SAAUsD,EAAI5Y,QAI9EyY,QAAUnF,UAAUiB,IAAI3R,UAAU6V,OAAsB,SAAbf,EAAI9C,OACtD7U,IAAIS,KAAK,YAAakX,EAAI9C,KAAK,qFAC/B8C,EAAIgB,mBAAmBpH,IAExBoG,EAAI/F,MAAML,GACVjR,KAAKwkB,WAAW9f,KAAK2S,MAOxBpE,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAK2kB,MAA6B,EAArB1T,EAAOnN,cAIrBmP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAK4kB,YAAc3T,EAAOhN,aAC1BjE,KAAK6kB,aAAe5T,EAAOhN,eAE5BgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAK8kB,UAAY7T,EAAO1M,cACxBvE,KAAK+N,MAAQkD,EAAO1M,gBAGrB0O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAI8T,EAAQ9T,EAAOnN,YACnB9D,KAAKglB,OAAS,GACd,IAAK,IAAInjB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAAK,CAC/B,IAAI9B,EAAQ,IACZC,KAAKglB,OAAOnjB,GAAK9B,GACXklB,SAAWhU,EAAOhN,aACxB,IAAI+c,EAAW/P,EAAOnN,YAGtB,OAFA/D,EAAMmlB,aAAelE,GAAY,EACjCjhB,EAAMolB,gBAA6B,IAAXnE,EAChBjhB,EAAMolB,iBACb,KAAK,EACJplB,EAAMoV,cAAgBlE,EAAO9M,WAAW,GACxC,MACD,KAAK,EACJpE,EAAMoV,cAAgBlE,EAAO9M,WAAW,GACxCpE,EAAMqlB,wBAA0BnU,EAAOhN,aACvC,MACD,KAAK,EAEL,KAAK,EACJ,MACD,KAAK,EACJlE,EAAMslB,aAAepU,EAAOhN,aAC5B,MACD,QACCvE,IAAIS,KAAK,YAAa,qCAM1B8S,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKslB,SAAWrU,EAAOlN,eAExBkP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKulB,OAAStU,EAAOhN,aACrBjE,KAAKwlB,MAAQvU,EAAOhN,eAIrBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACrCjR,KAAKylB,kBAAoB,GACzBzlB,KAAKylB,kBAAkB,GAAK,GAC5BzlB,KAAKylB,kBAAkB,GAAGC,EAAIzU,EAAOlN,aACrC/D,KAAKylB,kBAAkB,GAAGE,EAAI1U,EAAOlN,aACrC/D,KAAKylB,kBAAkB,GAAK,GAC5BzlB,KAAKylB,kBAAkB,GAAGC,EAAIzU,EAAOlN,aACrC/D,KAAKylB,kBAAkB,GAAGE,EAAI1U,EAAOlN,aACrC/D,KAAKylB,kBAAkB,GAAK,GAC5BzlB,KAAKylB,kBAAkB,GAAGC,EAAIzU,EAAOlN,aACrC/D,KAAKylB,kBAAkB,GAAGE,EAAI1U,EAAOlN,aACrC/D,KAAK4lB,YAAc,GACnB5lB,KAAK4lB,YAAYF,EAAIzU,EAAOlN,aAC5B/D,KAAK4lB,YAAYD,EAAI1U,EAAOlN,aAC5B/D,KAAK6lB,gCAAkC5U,EAAOhN,aAC9CjE,KAAK8lB,gCAAkC7U,EAAOhN,eAIlDgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GACxB,GAAhBjR,KAAK+U,SACR/U,KAAK+lB,cAAgB9U,EAAO/M,aAC5BlE,KAAKgmB,kBAAoB/U,EAAO/M,aAChClE,KAAK6f,UAAY5O,EAAOhN,aACxBjE,KAAKW,SAAWsQ,EAAO/M,eAEvBlE,KAAK+lB,cAAgB9U,EAAOhN,aAC5BjE,KAAKgmB,kBAAoB/U,EAAOhN,aAChCjE,KAAK6f,UAAY5O,EAAOhN,aACxBjE,KAAKW,SAAWsQ,EAAOhN,cAExBjE,KAAKyY,cAAcxH,GACnBA,EAAOlN,eAIRkP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC3B,EAAbjR,KAAKiS,QACRvS,IAAIS,KAAK,YAAa,qEACtBH,KAAK+U,QAAU,GAEI,GAAhB/U,KAAK+U,QACR/U,KAAKimB,kBAAoBhV,EAAO/M,aAEhClE,KAAKimB,kBAAoBhV,EAAOhN,eAKlCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKgV,MAAQ,GACb/B,UAAUkB,aAAa5R,UAAU+O,MAAMQ,KAAK9R,KAAMiR,KAGnDgC,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKkmB,gBAAkBjV,EAAOhN,eAI/BgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKwR,MAAQP,EAAOhN,eAIrBgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GACxB,GAAhBjR,KAAK+U,SACR/U,KAAK+lB,cAAgB9U,EAAO/M,aAC5BlE,KAAKgmB,kBAAoB/U,EAAO/M,aAChClE,KAAK6f,UAAY5O,EAAOhN,aACxBjE,KAAKW,SAAWsQ,EAAO/M,eAEvBlE,KAAK+lB,cAAgB9U,EAAOhN,aAC5BjE,KAAKgmB,kBAAoB/U,EAAOhN,aAChCjE,KAAK6f,UAAY5O,EAAOhN,aACxBjE,KAAKW,SAAWsQ,EAAOhN,cAExBjE,KAAKmmB,KAAOlV,EAAOhN,aACnBjE,KAAKomB,OAASnV,EAAOlN,cAAc,EACnCkN,EAAOlN,aACPkN,EAAO5L,gBAAgB,GACvBrF,KAAKqmB,OAASpV,EAAO5L,gBAAgB,GACrC4L,EAAO5L,gBAAgB,GACvBrF,KAAKsmB,cAAgBrV,EAAOhN,eAG7BgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKumB,YAActV,EAAOhN,eAI3BgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKumB,YAActV,EAAO/M,eAI3B+O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIuV,EAAevV,EAAOhN,aAC1BjE,KAAKymB,QAAU,GACf,IAAK,IAAI5kB,EAAI,EAAGA,EAAIP,KAAKC,OAAOilB,EAAa,GAAG,GAAI3kB,IACnD7B,KAAKymB,QAAUxV,EAAOnN,cAKxBmP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAK0mB,SAAWzV,EAAOhN,aACvBjE,KAAK2mB,SAAW1V,EAAOhN,eAExBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAK4mB,KAAO3V,EAAO9M,WAAWnE,KAAKqD,KAAOrD,KAAKiV,YAIhDhC,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAK6mB,UAAY5V,EAAOhN,aACxB,IAAI8gB,EAAQ9T,EAAOnN,YACnB9D,KAAK8mB,cAAgB7V,EAAO9M,WAAW4gB,KAIxC9R,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAI8T,GAAS/kB,KAAKqD,KAAOrD,KAAKiV,UAAU,EACxCjV,KAAKmmB,KAAO,GACZnmB,KAAK+mB,cAAgB,GACrB,IAAK,IAAIllB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1B7B,KAAKmmB,KAAKtkB,GAAKoP,EAAOhN,aACtBjE,KAAK+mB,cAAcllB,GAAKoP,EAAOhN,eAKjCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GACvB,IAAjBjR,KAAK+U,QACR/U,KAAKgnB,QAAU/V,EAAOlN,aAEtB/D,KAAKgnB,QAAU/V,EAAOhN,eAKxBgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIpP,EAGJ,IAFA7B,KAAKinB,aAAehW,EAAOnN,YAC3B9D,KAAKknB,kBAAoB,GACpBrlB,EAAI,EAAGA,EAAI7B,KAAKinB,aAAcplB,IAClC7B,KAAKknB,kBAAkBrlB,GAAKoP,EAAOnN,cAKrCmP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKwlB,MAAQvU,EAAOhN,eAIrBgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKmnB,aAAelW,EAAOhN,aAC3BjE,KAAKonB,cAAgBnW,EAAO/M,aACP,IAAjBlE,KAAK+U,QACR/U,KAAK0f,WAAazO,EAAOhN,aAEzBjE,KAAK0f,WAAazO,EAAO/M,eAK3B+O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAE5C,GADAjR,KAAKqnB,UAAYpU,UAAUyE,WAAWzG,GACnB,EAAfjR,KAAK+U,QAAa,CACrB,IAAIgQ,EAAQ9T,EAAOhN,aACnBjE,KAAKsnB,IAAM,GACX,IAAK,IAAIzlB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1B7B,KAAKsnB,IAAIzlB,GAAKoR,UAAUyE,WAAWzG,GAGrC,IAAIsW,EAAWtW,EAAOhN,aACP,EAAXsjB,IACHvnB,KAAK0R,KAAOT,EAAOjM,eAAeuiB,MAKpCtU,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKwZ,MAAQvI,EAAOhN,aACpBjE,KAAKyZ,OAASxI,EAAOhN,eAEtBgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKwZ,MAAQvI,EAAOhN,aACpBjE,KAAKyZ,OAASxI,EAAOhN,eAEtBgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKwZ,MAAQvI,EAAOhN,aACpBjE,KAAKyZ,OAASxI,EAAOhN,eAEtBgP,UAAU0B,uBAAuB,OAAQ,KAAM,CAAE,OAAQ,OAAQ,SACjE1B,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKwnB,kBAAoBvW,EAAO9M,WAAW,GAC3CnE,KAAKynB,QAAUxW,EAAO9M,WAAWnE,KAAKqD,KAAOrD,KAAKiV,SAAW,KAI9DhC,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC3B,EAAbjR,KAAKiS,QACRjS,KAAK0nB,cAAgBzW,EAAOhN,aAC5BjE,KAAK2nB,wBAA0B1W,EAAOhN,cAEvC,IAAI8gB,EAAQ9T,EAAOhN,aACnBjE,KAAKwK,OAAS,GACd,IAAK,IAAI3I,EAAI,EAAGA,EAAIkjB,EAAOljB,IACL,IAAjB7B,KAAK+U,QACR/U,KAAKwK,OAAO3I,GAAKoP,EAAOhN,aAExBjE,KAAKwK,OAAO3I,GAAKoP,EAAO/M,eAK3B+O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC3B,EAAbjR,KAAKiS,QACRjS,KAAK0nB,cAAgBzW,EAAOhN,aAC5BjE,KAAK2nB,wBAA0B1W,EAAOhN,cAEvCjE,KAAK4nB,yBAA2B3W,EAAOnN,YACvC,IAAIihB,EAAQ9T,EAAOhN,aAEnB,GADAjE,KAAK6nB,iBAAmB,GACc,IAAlC7nB,KAAK4nB,yBACR,IAAK,IAAI/lB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1B7B,KAAK6nB,iBAAiBhmB,GAAKoP,EAAOnN,cAMrCmP,UAAU0C,sBAAsB1C,UAAU+F,2BAA4B,OAAQ,SAAS/H,GACtFjR,KAAKoZ,YAAYnI,GACjBjR,KAAK6jB,iBAAmB5S,EAAO1M,cAC/BvE,KAAK8nB,YAAc7W,EAAO1M,cAC1BvE,KAAKsZ,YAAYrI,KAIlBgC,UAAU0C,sBAAsB1C,UAAU+F,2BAA4B,OAAQ,SAAS/H,GACtFjR,KAAKoZ,YAAYnI,GACjBjR,KAAK6jB,iBAAmB5S,EAAO1M,cAC/BvE,KAAK+nB,UAAY9W,EAAO1M,cACxBvE,KAAKgoB,gBAAkB/W,EAAO1M,cAC9BvE,KAAKsZ,YAAYrI,KAIlBgC,UAAU0C,sBAAsB1C,UAAUgG,2BAA4B,OAAQ,SAAShI,GACtFjR,KAAKoZ,YAAYnI,GACjBjR,KAAK6jB,iBAAmB5S,EAAO1M,cAC/BvE,KAAK8nB,YAAc7W,EAAO1M,cAC1BvE,KAAKsZ,YAAYrI,KAIlBgC,UAAU0C,sBAAsB1C,UAAUgG,2BAA4B,OAAQ,SAAShI,GACtFjR,KAAKoZ,YAAYnI,GACjBjR,KAAK+nB,UAAY9W,EAAO1M,cACxBvE,KAAKgoB,gBAAkB/W,EAAO1M,cAC9BvE,KAAKioB,qBAAuBhX,EAAO1M,cACnCvE,KAAKsZ,YAAYrI,KAIlBgC,UAAU0C,sBAAsB1C,UAAUgG,2BAA4B,OAAQ,SAAShI,GACtFjR,KAAKoZ,YAAYnI,GACjBjR,KAAK6jB,iBAAmB5S,EAAO1M,cAC/BvE,KAAK8nB,YAAc7W,EAAO1M,cAC1BvE,KAAKsZ,YAAYrI,KAIlBgC,UAAU0C,sBAAsB1C,UAAUgG,2BAA4B,OAAQ,SAAShI,GACtFjR,KAAKoZ,YAAYnI,GACjBjR,KAAKkoB,aAAejX,EAAOhN,aAC3BjE,KAAKmoB,yBAA2BlX,EAAOrM,WACvC5E,KAAKooB,uBAAyBnX,EAAOrM,WACrC5E,KAAKqoB,cAAgBpX,EAAOjM,eAAe,GAC3ChF,KAAKsoB,WAAarX,EAAO/L,eAAe,GACxClF,KAAKuoB,aAAetX,EAAOjM,eAAe,IAC1ChF,KAAKsZ,YAAYrI,KAGlBgC,UAAU0C,sBAAsB1C,UAAU+F,2BAA4B,OAAQ,SAAS/H,GACtFjR,KAAKoZ,YAAYnI,GACjBjR,KAAKsZ,YAAYrI,KAIlBgC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChD,IAAIpP,EACA2mB,EAAavX,EAAOlN,aAGxB,IAFA/D,KAAKyoB,oBAAsBxX,EAAOlN,aAClC/D,KAAK0oB,cAAgB,GAChB7mB,EAAI,EAAGA,EAAI2mB,EAAY3mB,IAC3B7B,KAAK0oB,cAAc7mB,GAAKoP,EAAOhN,aAEhC,IAAI0kB,EAAY3oB,KAAK4oB,mBAAqB,EAAI,EAAEJ,EAGhD,IAFAxoB,KAAK6oB,mBAAqB,GAC1B7oB,KAAK8oB,kBAAoB,GACpBjnB,EAAI,EAAGA,EAAI8mB,EAAU,EAAG9mB,IAC5B7B,KAAK6oB,mBAAmBhnB,GAAKoP,EAAOlN,aACpC/D,KAAK8oB,kBAAkBjnB,GAAKoP,EAAOlN,eAKrCkP,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDjR,KAAK+oB,YAAc9X,EAAOnN,YAC1B9D,KAAKgpB,uBAAyB/X,EAAOnN,YACrC9D,KAAKipB,WAAahY,EAAOlN,aACzB/D,KAAK4hB,aAAe3Q,EAAOlN,eAI5BkP,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDjR,KAAKkpB,sBAAwBjY,EAAOlN,aACpC/D,KAAK+oB,YAAc9X,EAAOnN,YAC1B,IAAIkd,EAAW/P,EAAOnN,YACtB9D,KAAKmpB,aAAenI,GAAY,EAChChhB,KAAKopB,YAAepI,GAAY,EAAK,EACjChhB,KAAKmpB,eACRnpB,KAAKW,SAAWsQ,EAAOhN,cAEpBjE,KAAKopB,cACRppB,KAAKgpB,uBAAyB/X,EAAOnN,YACrC9D,KAAKipB,WAAahY,EAAOlN,aACzB/D,KAAK4hB,aAAe3Q,EAAOlN,cAE5B/D,KAAKqpB,WAAa,GAElB,IADA,IAAIC,EAAgBrY,EAAOnN,YAClBjC,EAAI,EAAGA,EAAIynB,EAAeznB,IAAK,CACvC,IAAI0nB,EAAiB,GACrBvpB,KAAKqpB,WAAW3kB,KAAK6kB,GACrBA,EAAeC,oBAAsBvY,EAAOnN,YAC5CylB,EAAeR,YAAc9X,EAAOnN,YACpCylB,EAAeL,sBAAwBjY,EAAOlN,gBAKhDkP,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDjR,KAAKypB,cAAgBxY,EAAOpM,cAI7BoO,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAC5C+P,EAAW/P,EAAOnN,YACtB9D,KAAK0pB,0BAA4B1I,GAAY,EAC7ChhB,KAAK2pB,oBAAiC,IAAX3I,IAI5B/N,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAEhD,GADAjR,KAAK4pB,sBAAwB3Y,EAAOlN,aAChC/D,KAAK4oB,qBAAuB,GAAkC,IAA/B5oB,KAAK4pB,sBAA4B,EAA6B,EAA3B5pB,KAAK4pB,uBAAyB,EACnGlqB,IAAIS,KAAK,YAAa,eAAeH,KAAKmV,cAAc,wBACxDnV,KAAK0R,KAAQT,EAAOjM,eAAehF,KAAK4oB,mBAAmB,OACrD,CACN,GAAmC,IAA/B5oB,KAAK4pB,sBACR5pB,KAAK6pB,kBAAoB5Y,EAAOlN,iBAC1B,CACN/D,KAAK6pB,kBAAoB,GACzB7pB,KAAK8pB,kBAAoB,GACzB,IAAK,IAAIjoB,EAAI,EAAGA,EAAI7B,KAAK4pB,sBAAuB/nB,IAC/C7B,KAAK8pB,kBAAkBjoB,GAAKoP,EAAOhN,aACnCjE,KAAK6pB,kBAAkBhoB,GAAKoP,EAAOlN,aAGrC/D,KAAK+pB,gBAAkB9Y,EAAOhN,aAC9BjE,KAAKgqB,gBAAkB/Y,EAAOhN,aAC9BjE,KAAKiqB,iBAAmBhZ,EAAOnN,eAKjCmP,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDjR,KAAKypB,cAAgBxY,EAAOpM,cAI7BoO,UAAUiC,iBAAiB3S,UAAU+O,MAAQ,SAASL,GACrDvR,IAAIS,KAAK,YAAa,8BAA8BH,KAAKmV,eACzDnV,KAAK0R,KAAQT,EAAOjM,eAAehF,KAAK4oB,qBAIzC3V,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDjR,KAAKwjB,SAAWvS,EAAOnN,YACvB,IAAIgF,EAAMmI,EAAOnN,YACjB9D,KAAKkqB,iBAAmBphB,GAAO,EAC/B9I,KAAKmqB,gBAAwB,GAANrhB,EACvB9I,KAAKoqB,YAAcnZ,EAAOnN,YAC1B9D,KAAKqqB,mBAAqBpZ,EAAOnN,YACjC9D,KAAKsqB,IAAMrX,UAAUyE,WAAWzG,GAChCjR,KAAKuqB,iBAAmB,EACxBvqB,KAAKwqB,YAAc,EACM,IAArBxqB,KAAKoqB,aAAiD,IAA5BpqB,KAAKqqB,qBAClCrqB,KAAKuqB,iBAAmBtZ,EAAOnN,YAC/B9D,KAAKwqB,YAAcvZ,EAAOjM,eAAehF,KAAKuqB,qBAKhDtX,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAC5C+P,EAAW/P,EAAOnN,YACtB9D,KAAKyqB,cAA2B,GAAXzJ,IAItB/N,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAC5C+P,EAAW/P,EAAOnN,YACtB9D,KAAK0qB,8BAAgC1J,GAAY,IAIlD/N,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAU4C,sBAAsB,OAAQ,SAAS5E,GAChDvR,IAAIS,KAAK,YAAa,sBAAsBH,KAAKmV,cAAc,uBAIhElC,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKmV,cAAgBlE,EAAO9M,WAAW,GAClB,IAAjBnE,KAAK+U,QACR/U,KAAKolB,wBAA0BnU,EAAOhN,aAEtCjE,KAAKolB,wBAA0B,EAEhCplB,KAAKsf,QAAU,GAEf,IADA,IAAIxC,EAAc7L,EAAOhN,aAChBpC,EAAI,EAAGA,EAAIib,EAAajb,IAAK,CACrC,IAAI2d,EAAQ,GACZxf,KAAKsf,QAAQ5a,KAAK8a,GAClBA,EAAMgH,aAAevV,EAAOnM,YAC5B0a,EAAMmL,wBAA0B1Z,EAAOnM,eAKzCmO,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAK4qB,YAAc3Z,EAAO9M,WAAW,GACrCnE,KAAK6qB,eAAiB5Z,EAAOhN,aACZ,EAAbjE,KAAKiS,QACRjS,KAAK8qB,WAAa7Z,EAAO9M,WAAWnE,KAAKqD,KAAOrD,KAAKiV,SAAW,MAKlEhC,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKynB,QAAUxW,EAAO9M,WAAWnE,KAAKqD,KAAOrD,KAAKiV,YAInDhC,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAI+P,EACA+D,EAAS/kB,KAAKqD,KAAOrD,KAAKiV,SAC9BjV,KAAK+qB,WAAa,GAClB/qB,KAAKgrB,kBAAoB,GACzBhrB,KAAKirB,sBAAwB,GAC7BjrB,KAAKkrB,sBAAwB,GAC7B,IAAK,IAAIrpB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1Bmf,EAAW/P,EAAOnN,YAClB9D,KAAK+qB,WAAWlpB,GAAKmf,GAAY,EACjChhB,KAAKgrB,kBAAkBnpB,GAAMmf,GAAY,EAAK,EAC9ChhB,KAAKirB,sBAAsBppB,GAAMmf,GAAY,EAAK,EAClDhhB,KAAKkrB,sBAAsBrpB,GAAgB,EAAXmf,IAMlC/N,UAAUwB,kBAAkB,QAuB5BxB,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKmV,cAAgBlE,EAAO9M,WAAW,GACvCzE,IAAIO,MAAM,YAAa,+BAA+BD,KAAKmV,eACtC,IAAjBnV,KAAK+U,QACR/U,KAAKmrB,eAAiBla,EAAOhN,aAE7BjE,KAAKmrB,eAAiB,EAEH,GAAhBnrB,KAAK+U,UACR/U,KAAKorB,gCAAkCna,EAAOhN,cAE/CjE,KAAKsf,QAAU,GAEf,IADA,IAAIxC,EAAc7L,EAAOhN,aAChBpC,EAAI,EAAGA,EAAIib,EAAajb,IAAK,CACrC,IAEC2d,EAAQ,IADLvM,UAAUjT,KAAKmV,cAAc,oBACpBlC,UAAUjT,KAAKmV,cAAc,oBAE7BlC,UAAUiC,kBAFuClV,KAAKmV,eAInEnV,KAAKsf,QAAQ5a,KAAK8a,GACG,IAAjBxf,KAAK+U,SACoB,IAAxB/U,KAAKmrB,eACR3L,EAAMoJ,mBAAqB3X,EAAOhN,aAKnCub,EAAMoJ,mBAAqB5oB,KAAKmrB,eAE7B3L,EAAMpH,QAAUnF,UAAUiC,iBAAiB3S,UAAU6V,QACxD1Y,IAAIQ,KAAK,YAAa,wBAAwBF,KAAKmV,cAAc,iFAEjEqK,EAAM9N,KAAOT,EAAOjM,eAAewa,EAAMoJ,oBAEzC3X,EAAO3O,UAAYkd,EAAMoJ,oBAE1BpJ,EAAMlO,MAAML,MAKdgC,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKqrB,aAAepa,EAAOhN,aAC3BjE,KAAK6f,UAAY5O,EAAOhN,aACH,IAAjBjE,KAAK+U,SACR/U,KAAKsrB,2BAA6Bra,EAAOhN,aACzCjE,KAAKurB,aAAeta,EAAOhN,eAE3BjE,KAAKsrB,2BAA6Bra,EAAO/M,aACzClE,KAAKurB,aAAeta,EAAO/M,cAE5B+M,EAAOlN,aACP/D,KAAKwkB,WAAa,GAElB,IADA,IAAIO,EAAQ9T,EAAOlN,aACVlC,EAAI,EAAGA,EAAIkjB,EAAOljB,IAAK,CAC/B,IAAI2pB,EAAM,GACVxrB,KAAKwkB,WAAW9f,KAAK8mB,GACrB,IAAIC,EAASxa,EAAOhN,aACpBunB,EAAIE,eAAkBD,GAAU,GAAM,EACtCD,EAAIG,gBAA2B,WAATF,EACtBD,EAAII,oBAAsB3a,EAAOhN,aACjCwnB,EAASxa,EAAOhN,aAChBunB,EAAIK,gBAAmBJ,GAAU,GAAM,EACvCD,EAAIM,SAAYL,GAAU,GAAM,EAChCD,EAAIO,eAA0B,UAATN,KAKvBxY,UAAUwR,2BAA6B,SAASlQ,EAAMlR,EAAM4R,EAAUtV,GACrEsT,UAAUiB,IAAIpC,KAAK9R,KAAMuU,EAAMlR,GAC/BrD,KAAKiV,SAAWA,EAChBjV,KAAKL,MAAQA,GAEdsT,UAAUwR,2BAA2BliB,UAAY,IAAI0Q,UAAUiB,IAC/DjB,UAAUwR,2BAA2BliB,UAAU+O,MAAQ,SAASL,GAC/DjR,KAAKgsB,aAAe/a,EAAOlN,aAC3B,IAAIghB,EAAS9T,EAAOlN,aACpB/D,KAAKwkB,WAAa,GAClB,IAAI,IAAI3iB,EAAI,EAAGA,EAAIkjB,EAAOljB,IACzB7B,KAAKwkB,WAAW3iB,GAAKoP,EAAOlN,cAK9BkP,UAAUyR,gCAAkC,SAASnQ,EAAMlR,EAAM4R,EAAUtV,GAC1EsT,UAAUiB,IAAIpC,KAAK9R,KAAMuU,EAAMlR,GAC/BrD,KAAKiV,SAAWA,EAChBjV,KAAKL,MAAQA,GAEdsT,UAAUyR,gCAAgCniB,UAAY,IAAI0Q,UAAUiB,IACpEjB,UAAUyR,gCAAgCniB,UAAU+O,MAAQ,SAASL,GACpEjR,KAAKgsB,aAAe/a,EAAOhN,aAC3B,IAAI8gB,EAAS9T,EAAOlN,aACpB/D,KAAKwkB,WAAa,GAClB,IAAI,IAAI3iB,EAAI,EAAGA,EAAIkjB,EAAOljB,IACzB7B,KAAKwkB,WAAW3iB,GAAKoP,EAAOhN,cAK9BgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKisB,uBAAyBhb,EAAOlN,aAClC/D,KAAKksB,uBAAyBjb,EAAOlN,aACrC/D,KAAKmsB,uBAAyBlb,EAAOlN,aACrC/D,KAAKosB,uBAAyBnb,EAAOlN,aACrC/D,KAAKqsB,uBAAyBpb,EAAOlN,aACrC/D,KAAKssB,uBAAyBrb,EAAOlN,aACrC/D,KAAKusB,yBAA2Btb,EAAOlN,aACvC/D,KAAKwsB,yBAA2Bvb,EAAOlN,aACvC/D,KAAKysB,aAAexb,EAAOhN,aAC3BjE,KAAK0sB,aAAezb,EAAOhN,eAI/BgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAK2sB,QAAU1b,EAAOlN,aACtBkN,EAAOlN,eAIRkP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAK4sB,YAAc,GAEnB,IADA,IAAIC,EAAmB5b,EAAOhN,aACrBpC,EAAI,EAAGA,EAAIgrB,EAAkBhrB,IAAK,CAC1C,IAAIirB,EAAa,GACjB9sB,KAAK4sB,YAAYloB,KAAKooB,GACtBA,EAAWnrB,OAAS,GAEpB,IADA,IAAIorB,EAAc9b,EAAOhN,aAChB2E,EAAI,EAAGA,EAAImkB,EAAankB,IAAK,CACrC,IAAIsG,EAAQ,GACZ4d,EAAWnrB,OAAO+C,KAAKwK,GACvBA,EAAMnP,MAAQkR,EAAOnN,YACrBoL,EAAM8d,WAAa/b,EAAOjN,iBAM7BiP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACA6L,EAAc7L,EAAOhN,aAErB,GADAjE,KAAK+c,cAAgB,GACA,IAAjB/c,KAAK+U,QACR,IAAK,IAAIlT,EAAI,EAAGA,EAAIib,EAAajb,IAChC7B,KAAK+c,cAAcrY,KAAKuM,EAAOhN,gBAMlCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAI8T,GAAS/kB,KAAKqD,KAAOrD,KAAKiV,UAAU,EACxCjV,KAAKitB,SAAW,GAChB,IAAK,IAAIprB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1B7B,KAAKitB,SAASprB,GAAKoP,EAAOlN,eAK5BkP,UAAUwB,kBAAkB,QAG5BxB,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKktB,aAAejc,EAAOlN,aAC3B/D,KAAKmtB,gBAAkBlc,EAAOlN,aAC9B/D,KAAKqlB,aAAepU,EAAOhN,aAC3B,IAAI8gB,GAAS/kB,KAAKqD,KAAOrD,KAAKiV,SAAW,GAAG,EAC5CjV,KAAKotB,eAAiB,GACtB,IAAK,IAAIvrB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1B7B,KAAKotB,eAAevrB,GAAKoP,EAAOhN,eAKlCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACIpP,EACJib,EAAc7L,EAAOhN,aAIrB,GAHAjE,KAAKqtB,YAAc,GACnBrtB,KAAKstB,kBAAoB,GACzBttB,KAAKutB,yBAA2B,GACX,IAAjBvtB,KAAK+U,QACR,IAAIlT,EAAE,EAAGA,EAAEib,EAAajb,IACvB7B,KAAKqtB,YAAY3oB,KAAKuM,EAAOhN,cAC7BjE,KAAKstB,kBAAkB5oB,KAAKuM,EAAOhN,cACnCjE,KAAKutB,yBAAyB7oB,KAAKuM,EAAOhN,gBAM7CgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIpP,EACA0W,EACAiV,EACAnW,EAGJ,IAFArX,KAAKsf,QAAU,GACfkO,EAAavc,EAAOhN,aACfpC,EAAI,EAAGA,GAAK2rB,EAAY3rB,IAAK,CAEjC,IADA0W,EAAMtF,UAAU6E,YAAY7G,GAAQ,EAAMjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,SAC3EsY,OAAShF,UAAUG,GAgB1B,OAfIH,UAAUsF,EAAIhE,KAAK,iBACtB8C,EAAM,IAAIpE,UAAUsF,EAAIhE,KAAK,eAAegE,EAAIlV,OAC5C4R,SAAWsD,EAAItD,SACnBoC,EAAI1X,MAAQ4Y,EAAI5Y,QAEhBD,IAAIS,KAAK,YAAa,8BAA8BoY,EAAIhE,MACxD8C,EAAM,IAAIpE,UAAUmB,YAAYmE,EAAIhE,KAAMgE,EAAIlV,KAAMkV,EAAItD,SAAUsD,EAAI5Y,QAEnE0X,EAAIe,QAAUnF,UAAUmB,YAAY7R,UAAU6V,QACjD1Y,IAAIQ,KAAK,YAAa,eAAemX,EAAI9C,KAAK,qFAC9C8C,EAAIgB,mBAAmBpH,IAExBoG,EAAI/F,MAAML,GACVjR,KAAKsf,QAAQ5a,KAAK2S,MAQrBpE,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKmV,cAAgBlE,EAAOhN,aAC5B,IAAI8gB,EAAQ9T,EAAOlN,aACnB/D,KAAK2qB,wBAA0B,GAC/B,IAAK,IAAI9oB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1B7B,KAAK2qB,wBAAwB9oB,GAAKoP,EAAOhN,eAK3CgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACIpP,EACJib,EAAc7L,EAAOhN,aAGrB,GAFAjE,KAAKytB,wBAA0B,GAC/BztB,KAAK0tB,oBAAsB,GACN,IAAjB1tB,KAAK+U,QACR,IAAIlT,EAAE,EAAGA,EAAEib,EAAajb,IACvB7B,KAAKytB,wBAAwB/oB,KAAKuM,EAAOhN,cACzCjE,KAAK0tB,oBAAoBhpB,KAAKuM,EAAOhN,gBAMxCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIpP,EAEJib,EAAc7L,EAAOhN,aACrB,GAAqB,IAAjBjE,KAAK+U,QAER,IADA/U,KAAK2tB,eAAiB,GAClB9rB,EAAE,EAAGA,EAAEib,EAAajb,IACvB7B,KAAK2tB,eAAejpB,KAAKuM,EAAOhN,gBAMnCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIpP,EAEJ,GADA7B,KAAK4tB,aAAe,GACC,IAAjB5tB,KAAK+U,QAGR,IAFA/U,KAAK6tB,YAAc5c,EAAOhN,aAC1BjE,KAAKwmB,aAAevV,EAAOhN,aACtBpC,EAAI,EAAGA,EAAI7B,KAAKwmB,aAAc3kB,IACT,IAArB7B,KAAK6tB,YACR7tB,KAAK4tB,aAAalpB,KAAKuM,EAAOhN,cAE9BjE,KAAK4tB,aAAa/rB,GAAK7B,KAAK6tB,cAOhC5a,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IACIpP,EACAisB,EACJhR,EAAc7L,EAAOhN,aAGrB,GAFAjE,KAAK8d,cAAgB,GACrB9d,KAAK+tB,cAAgB,GACA,IAAjB/tB,KAAK+U,QACR,IAAIlT,EAAE,EAAGA,EAAEib,EAAajb,IACvB7B,KAAK8d,cAAcpZ,KAAKuM,EAAOhN,eAC/B6pB,EAAQ7c,EAAOnM,aACH,IACXpF,IAAIS,KAAK,YAAa,kFACtB2tB,EAAQ,GAET9tB,KAAK+tB,cAAcrpB,KAAKopB,KAM3B7a,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAI+c,EAAQ/c,EAAOhN,aACnBjE,KAAKiuB,oBAA8B,EAARD,EAC3BhuB,KAAKkuB,cAAgBjd,EAAOhN,aAC5B,IAGIoT,EAHArW,EAASiQ,EAAOhN,aAKpB,IAJAjE,KAAKmuB,uBAAyBld,EAAO9M,WAAWnD,GAGhDhB,KAAKgV,MAAQ,GACN/D,EAAOzO,cAAgBxC,KAAKL,MAAMK,KAAKqD,MAAM,CAEnD,IADAkV,EAAMtF,UAAU6E,YAAY7G,GAAQ,EAAOjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,SAC5EsY,OAAShF,UAAUG,GAK1B,OAJAiE,EAAMkB,EAAIlB,IACVrX,KAAKgV,MAAMtQ,KAAK2S,GAChBrX,KAAKqX,EAAI9C,MAAQ8C,KAQpBpE,UAAUuB,cAAc,OAAQ,SAASvD,GACxCgC,UAAUmb,QAAQ7rB,UAAU+O,MAAMQ,KAAK9R,KAAMiR,KAI9CgC,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIpP,EAEA2kB,EAEJ,GADAxmB,KAAK4tB,aAAe,GACC,IAAjB5tB,KAAK+U,QAIR,GAHA/U,KAAKwjB,SAAWvS,EAAOjN,aACvBhE,KAAKquB,WAAapd,EAAOnN,YACzB0iB,EAAevV,EAAOhN,aACE,IAApBjE,KAAKquB,WACR,IAAKxsB,EAAI,EAAGA,EAAI2kB,EAAc3kB,GAAG,EAAG,CACnC,IAAIiH,EAAMmI,EAAOnN,YACjB9D,KAAK4tB,aAAa/rB,GAAMiH,GAAO,EAAK,GACpC9I,KAAK4tB,aAAa/rB,EAAE,GAAW,GAANiH,OAEpB,GAAwB,IAApB9I,KAAKquB,WACf,IAAKxsB,EAAI,EAAGA,EAAI2kB,EAAc3kB,IAC7B7B,KAAK4tB,aAAa/rB,GAAKoP,EAAOnN,iBAEzB,GAAwB,KAApB9D,KAAKquB,WACf,IAAKxsB,EAAI,EAAGA,EAAI2kB,EAAc3kB,IAC7B7B,KAAK4tB,aAAa/rB,GAAKoP,EAAOlN,kBAG/BrE,IAAIU,MAAM,YAAa,uCAM1B6S,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIpP,EAAE+G,EAEF0lB,EACJxR,EAAc7L,EAAOhN,aAErB,IADAjE,KAAKsf,QAAU,GACVzd,EAAI,EAAGA,EAAIib,EAAajb,IAAK,CACjC,IAAI0sB,EAAa,GAKjB,IAJAvuB,KAAKsf,QAAQzd,GAAK0sB,GACPC,aAAevd,EAAOhN,aACjCsqB,EAAWE,WAAa,GAEJ,GADpBH,EAAkBrd,EAAOlN,cAExB,IAAK6E,EAAI,EAAGA,EAAI0lB,EAAiB1lB,IAAK,CACrC,IAAI8lB,EAAY,GAChBH,EAAWE,WAAW/pB,KAAKgqB,GACP,GAAhB1uB,KAAK+U,QACR2Z,EAAUrrB,KAAO4N,EAAOhN,aAExByqB,EAAUrrB,KAAO4N,EAAOlN,aAEzB2qB,EAAUzB,SAAWhc,EAAOnN,YAC5B4qB,EAAUC,YAAc1d,EAAOnN,YAC/B4qB,EAAUE,0BAA4B3d,EAAOhN,iBAOjDgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAE5C,IAGKnI,EAJLmI,EAAOnN,YACc,IAAjB9D,KAAK+U,QACR9D,EAAOnN,aAEHgF,EAAMmI,EAAOnN,YACjB9D,KAAK6uB,yBAA4B/lB,GAAO,EAAK,GAC7C9I,KAAK8uB,wBAAgC,GAANhmB,GAEhC9I,KAAK+uB,oBAAsB9d,EAAOnN,YAClC9D,KAAKgvB,2BAA6B/d,EAAOnN,YACzC9D,KAAKivB,YAAchc,UAAUyE,WAAWzG,GACP,IAA7BjR,KAAK+uB,qBAAiE,IAApC/uB,KAAKgvB,6BAC1ChvB,KAAKkvB,yBAA2Bje,EAAOnN,YACvC9D,KAAKmvB,oBAAsBle,EAAOjM,eAAehF,KAAKkvB,6BAGxDjc,UAAUwB,kBAAkB,OAAQ,SAASxD,GACxB,GAAhBjR,KAAK+U,QACR/U,KAAKovB,oBAAsBne,EAAO/M,aAElClE,KAAKovB,oBAAsBne,EAAOhN,eAKpCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIoe,EAAY,EAChBrvB,KAAKsvB,SAAWre,EAAOhN,aACnBjE,KAAKqD,KAAOrD,KAAKiV,SAAWoa,GAAcrvB,KAAKiS,MAAQgB,UAAUoD,4BACpErW,KAAKuvB,iBAAmBte,EAAO/M,aAC/BmrB,GAAa,GAEbrvB,KAAKuvB,iBAAmB,EAErBvvB,KAAKqD,KAAOrD,KAAKiV,SAAWoa,GAAcrvB,KAAKiS,MAAQgB,UAAUqD,uBACpEtW,KAAKwvB,iCAAmCve,EAAOhN,aAC/CorB,GAAa,GAEbrvB,KAAKwvB,iCAAmC,EAErCxvB,KAAKqD,KAAOrD,KAAKiV,SAAWoa,GAAcrvB,KAAKiS,MAAQgB,UAAUsD,sBACpEvW,KAAKyvB,wBAA0Bxe,EAAOhN,aACtCorB,GAAa,GAEbrvB,KAAKyvB,wBAA0B,EAE5BzvB,KAAKqD,KAAOrD,KAAKiV,SAAWoa,GAAcrvB,KAAKiS,MAAQgB,UAAUuD,uBACpExW,KAAK0vB,oBAAsBze,EAAOhN,aAClCorB,GAAa,GAEbrvB,KAAK0vB,oBAAsB,EAExB1vB,KAAKqD,KAAOrD,KAAKiV,SAAWoa,GAAcrvB,KAAKiS,MAAQgB,UAAUwD,wBACpEzW,KAAK2vB,qBAAuB1e,EAAOhN,aACnCorB,GAAa,GAEbrvB,KAAK2vB,qBAAuB,IAK9B1c,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKilB,SAAWhU,EAAOhN,aACvBgN,EAAOjN,aACP,IAAIgd,EAAW/P,EAAOnN,YACtB9D,KAAK4vB,wBAA2B5O,GAAY,EAAK,EACjDhhB,KAAK6vB,wBAA2B7O,GAAY,EAAK,EACjDhhB,KAAK8vB,0BAAyC,EAAb,EACjC9vB,KAAKsf,QAAU,GAEf,IADA,IAAIyQ,EAAoB9e,EAAOhN,aACtBpC,EAAI,EAAGA,EAAIkuB,EAAmBluB,IACjB,IAAjB7B,KAAK+U,SACR/U,KAAKqf,KAAOpO,EAAO/M,aACnBlE,KAAKgwB,YAAc/e,EAAO/M,eAE1BlE,KAAKqf,KAAOpO,EAAOhN,aACnBjE,KAAKgwB,YAAc/e,EAAOhN,cAE3BjE,KAAKiwB,YAAchf,EAAO,WAAY,GAAGjR,KAAK4vB,wBAAwB,MACtE5vB,KAAKkwB,YAAcjf,EAAO,WAAY,GAAGjR,KAAK6vB,wBAAwB,MACtE7vB,KAAKmwB,cAAgBlf,EAAO,WAAY,GAAGjR,KAAK8vB,0BAA0B,QAK5E7c,UAAUwB,kBAAkB,OAAQ,SAASxD,GACxB,GAAhBjR,KAAK+U,SACR/U,KAAK+lB,cAAgB9U,EAAO/M,aAC5BlE,KAAKgmB,kBAAoB/U,EAAO/M,aAChClE,KAAKsvB,SAAWre,EAAOhN,aACvBgN,EAAOhN,aACPjE,KAAKW,SAAWsQ,EAAO/M,eAEvBlE,KAAK+lB,cAAgB9U,EAAOhN,aAC5BjE,KAAKgmB,kBAAoB/U,EAAOhN,aAChCjE,KAAKsvB,SAAWre,EAAOhN,aACvBgN,EAAOhN,aACPjE,KAAKW,SAAWsQ,EAAOhN,cAExBgN,EAAO5L,gBAAgB,GACvBrF,KAAKowB,MAAQnf,EAAOpM,YACpB7E,KAAKmtB,gBAAkBlc,EAAOpM,YAC9B7E,KAAKomB,OAASnV,EAAOpM,aAAa,EAClCoM,EAAOlN,aACP/D,KAAKqmB,OAASpV,EAAO1L,eAAe,GACpCvF,KAAKwZ,MAAQvI,EAAOhN,aACpBjE,KAAKyZ,OAASxI,EAAOhN,eAItBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKqf,KAAOpO,EAAOhN,eAIpBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKqf,KAAOpO,EAAOhN,eAIpBgP,UAAUuB,cAAc,OAAO,SAASvD,GACvCjR,KAAKof,UAAYnO,EAAOhN,eAIzBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKof,UAAYnO,EAAOhN,eAIzBgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKof,UAAYnO,EAAO/M,eAIzB+O,UAAUoB,kBAAkB9R,UAAU+O,MAAQ,SAASL,GACtDjR,KAAKqV,gBAAgBpE,GACrBjR,KAAKqwB,eAAiBpf,EAAOhN,cAI9BgP,UAAU6C,qBAAqB,QAC/B7C,UAAUqd,sBAAwB,SAAS/b,EAAMlR,EAAM4R,EAAUtV,GAChEsT,UAAUiB,IAAIpC,KAAK9R,KAAMuU,EAAMlR,GAC/BrD,KAAKiV,SAAWA,EAChBjV,KAAKL,MAAQA,GAEdsT,UAAUqd,sBAAsB/tB,UAAY,IAAI0Q,UAAUiB,IAC1DjB,UAAUqd,sBAAsB/tB,UAAU+O,MAAQ,SAASL,GAC1DjR,KAAKuwB,UAAYtf,EAAO5L,iBAAiBrF,KAAKqD,KAAKrD,KAAKiV,UAAU,IAInEhC,UAAUud,QAAQjuB,UAAU+O,MAAQ,SAASL,GAG5C,IAFA,IACIoG,EACGpG,EAAOzO,cAAgBxC,KAAKL,MAAMK,KAAKqD,MAAM,CAEnD,IADAkV,EAAMtF,UAAU6E,YAAY7G,GAAQ,EAAMjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,SAC3EsY,OAAShF,UAAUG,GAS1B,QARAiE,EAAM,IAAIpE,UAAUqd,sBAAsB/X,EAAIhE,KAAMgE,EAAIlV,KAAMkV,EAAItD,SAAUsD,EAAI5Y,QACxEyY,QAAUnF,UAAUiB,IAAI3R,UAAU6V,OAAsB,SAAbf,EAAI9C,OACtD7U,IAAIQ,KAAK,YAAa,kBAAkBmX,EAAI9C,KAAK,qFACjD8C,EAAIgB,mBAAmBpH,IAExBoG,EAAI/F,MAAML,GACVjR,KAAKgV,MAAMtQ,KAAK2S,KAQnBpE,UAAUwB,kBAAkB,OAAQ,SAASxD,GAG5C,IAFAjR,KAAKilB,SAAWhU,EAAOhN,aACvBjE,KAAKgV,MAAQ,GACN/D,EAAOzO,cAAgBxC,KAAKL,MAAMK,KAAKqD,MAAM,CAEnD,GADAkV,IAAMtF,UAAU6E,YAAY7G,GAAQ,EAAOjR,KAAKqD,MAAQ4N,EAAOzO,cAAgBxC,KAAKL,QAChF4Y,IAAIN,OAAShF,UAAUG,GAI1B,OAHAiE,IAAMkB,IAAIlB,IACVrX,KAAKgV,MAAMtQ,KAAK2S,QAQnBpE,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKsvB,SAAWre,EAAOhN,aACvBjE,KAAKwvB,iCAAmCve,EAAOhN,aAC/CjE,KAAKyvB,wBAA0Bxe,EAAOhN,aACtCjE,KAAK0vB,oBAAsBze,EAAOhN,aAClCjE,KAAK2vB,qBAAuB1e,EAAOhN,eAIpCgP,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAKof,UAAYnO,EAAO/M,eAIzB+O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5C,IAAIoe,EAAY,EAmBhB,GAlBArvB,KAAKwmB,aAAevV,EAAOhN,aAC3BorB,GAAY,EACRrvB,KAAKqD,KAAOrD,KAAKiV,SAAWoa,GAAcrvB,KAAKiS,MAAQgB,UAAU2D,wBACpE5W,KAAKywB,YAAcxf,EAAOnM,YAC1BuqB,GAAa,GAEbrvB,KAAKywB,YAAc,EAEhBzwB,KAAKqD,KAAOrD,KAAKiV,SAAWoa,GAAcrvB,KAAKiS,MAAQgB,UAAU4D,uBACpE7W,KAAK0wB,mBAAqBzf,EAAOhN,aACjCorB,GAAa,GAEbrvB,KAAK0wB,mBAAqB,EAE3B1wB,KAAK2wB,gBAAkB,GACvB3wB,KAAK6tB,YAAc,GACnB7tB,KAAK4wB,aAAe,GACpB5wB,KAAK6wB,+BAAiC,GAClC7wB,KAAKqD,KAAOrD,KAAKiV,SAAWoa,EAC/B,IAAK,IAAIxtB,EAAI,EAAGA,EAAI7B,KAAKwmB,aAAc3kB,IAClC7B,KAAKiS,MAAQgB,UAAU6D,sBAC1B9W,KAAK2wB,gBAAgB9uB,GAAKoP,EAAOhN,cAE9BjE,KAAKiS,MAAQgB,UAAU8D,kBAC1B/W,KAAK6tB,YAAYhsB,GAAKoP,EAAOhN,cAE1BjE,KAAKiS,MAAQgB,UAAU+D,mBAC1BhX,KAAK4wB,aAAa/uB,GAAKoP,EAAOhN,cAE3BjE,KAAKiS,MAAQgB,UAAUgE,wBACL,IAAjBjX,KAAK+U,QACR/U,KAAK6wB,+BAA+BhvB,GAAKoP,EAAOhN,aAEhDjE,KAAK6wB,+BAA+BhvB,GAAKoP,EAAOnM,eAQrDmO,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKktB,aAAejc,EAAOhN,aAC3B,IAAI8gB,GAAS/kB,KAAKqD,KAAOrD,KAAKiV,SAAW,GAAG,EAC5CjV,KAAKotB,eAAiB,GACtB,IAAK,IAAIvrB,EAAI,EAAGA,EAAIkjB,EAAOljB,IAC1B7B,KAAKotB,eAAevrB,GAAKoP,EAAOhN,eAKlCgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAK8wB,OAAS7f,EAAO1M,gBAItB0O,UAAUwB,kBAAkB,OAAQ,SAASxD,GACzB,IAAfjR,KAAKiS,QACRjS,KAAK+wB,SAAW9f,EAAO1M,iBAKzB0O,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKmX,KAAOlG,EAAO1M,cACoC,EAAnDvE,KAAKqD,KAAOrD,KAAKiV,SAAWjV,KAAKmX,KAAKnW,OAAS,IAClDhB,KAAK+wB,SAAW9f,EAAO1M,iBAKzB0O,UAAU8C,cAAc,oCAAoC,GAAM,EAAO,SAAS9E,GAC9EjR,KAAKgxB,mBAAqB/f,EAAO9M,WAAWnE,KAAKqD,KAAOrD,KAAKiV,UACxDgc,QAAQ,KAAM,SACdA,QAAQ,KAAM,QACdA,QAAQ,KAAM,QACdA,QAAQ,KAAM,UACdA,QAAQ,KAAM,YAEvBhe,UAAU8C,cAAc,oCAAoC,GAAM,EAAO,SAAS9E,GACjFjR,KAAKqnB,UAAYpU,UAAUyE,WAAWzG,GACtC,IAAIsW,EAAWtW,EAAOhN,aACP,EAAXsjB,IACHvnB,KAAK0R,KAAOT,EAAOjM,eAAeuiB,MAKpCtU,UAAU8C,cAAc,oCAAoC,GAAM,GAyBlE9C,UAAU8C,cAAc,oCAAoC,GAAM,EAAO,SAAS9E,GACjFjR,KAAKkxB,oBAAsBjgB,EAAOjN,aAClChE,KAAKmxB,gBAAkBlgB,EAAOnN,YAC9B9D,KAAKivB,YAAchc,UAAUyE,WAAWzG,KAEzCgC,UAAU8C,cAAc,oCAAoC,GAAM,EAAO,SAAS9E,GAC9EjR,KAAKoxB,eAAiBngB,EAAOnN,YAC7B9D,KAAKsf,QAAU,GAEf,IAAK,IAAIzd,EAAI,EAAGA,EAAI7B,KAAKoxB,eAAgBvvB,IAAK,CAC1C,IAAI2d,EAAQ,GACR6R,EAAgB,EAChBC,EAAoB,EAIpBA,EAFiB,IAAjBtxB,KAAK+U,SACLsc,EAAgBpgB,EAAO/M,aACH+M,EAAO/M,eAE3BmtB,EAAgBpgB,EAAOhN,aACHgN,EAAOhN,cAG/Bub,EAAM6R,cAAgBA,EACtB7R,EAAM8R,kBAAoBA,EAE1BtxB,KAAKsf,QAAQ5a,KAAK8a,MAG1BvM,UAAU8C,cAAc,oCAAoC,GAAM,EAAO,SAAS9E,GACzD,IAAjBjR,KAAK+U,SACN/U,KAAKqxB,cAAgBpgB,EAAO/M,aAC5BlE,KAAKW,SAAWsQ,EAAO/M,eAEvBlE,KAAKqxB,cAAgBpgB,EAAOhN,aAC5BjE,KAAKW,SAAWsQ,EAAOhN,gBAG9BgP,UAAUwB,kBAAkB,OAAQ,SAASxD,GAC5CjR,KAAKuxB,aAAetgB,EAAOlN,aAC3B/D,KAAKwxB,QAAUvgB,EAAO7L,gBAAgB,KAIvC6N,UAAUwB,kBAAkB,OAAQ,SAAUxD,GAC7C,IAAInI,EACiB,IAAjB9I,KAAK+U,SACR/U,KAAKyxB,QAAUxgB,EAAOnN,YACtB9D,KAAKD,MAAQkR,EAAOnN,YACpBgF,EAAMmI,EAAOnN,YACb9D,KAAK0xB,SAAW5oB,GAAO,EACvB9I,KAAK2xB,kBAAqB7oB,GAAO,EAAK,EACtC9I,KAAK4xB,mBAA2B,EAAN9oB,EAC1B9I,KAAK6xB,gBAAkB5gB,EAAOnN,YAC9B9D,KAAK8xB,wBAA0B7gB,EAAOnN,YACtC9D,KAAK+xB,mBAAqB9gB,EAAOnN,cAIjC9D,KAAKyxB,QAAUxgB,EAAOnN,YACtB9D,KAAKD,MAAQkR,EAAOnN,YACpBgF,EAAMmI,EAAOnN,YACb9D,KAAK0xB,SAAY5oB,GAAO,EAAK,GAC7B9I,KAAKgyB,WAAmB,GAANlpB,EAClBA,EAAMmI,EAAOnN,YACb9D,KAAK2xB,kBAAqB7oB,GAAO,EAAK,GACtC9I,KAAKiyB,iBAAoBnpB,GAAO,EAAK,EACrC9I,KAAK4xB,mBAA2B,EAAN9oB,GAX1B9I,KAAKkyB,2BAA6BjhB,EAAOlN,aACzC/D,KAAKmyB,uBAAyBlhB,EAAOjM,eAAehF,KAAKkyB,8BAe3Djf,UAAUuB,cAAc,OAAQ,SAASvD,GACxCjR,KAAK4mB,KAAO3V,EAAO9M,WAAWnE,KAAKqD,KAAOrD,KAAKiV,YAIhDhC,UAAUmB,YAAY7R,UAAU6vB,QAAU,WACzC,OAAO,GAGRnf,UAAUmB,YAAY7R,UAAU8vB,QAAU,WACzC,OAAO,GAGRpf,UAAUmB,YAAY7R,UAAU+vB,WAAa,WAC5C,OAAO,GAGRrf,UAAUmB,YAAY7R,UAAUgwB,WAAa,WAC5C,OAAO,GAGRtf,UAAUmB,YAAY7R,UAAUiwB,OAAS,WACxC,OAAO,GAGRvf,UAAUmB,YAAY7R,UAAUkwB,SAAW,WAC1C,OAAOzyB,KAAKuU,KAAK0c,QAAQ,IAAI,KAG9Bhe,UAAUmB,YAAY7R,UAAUmwB,SAAW,WAC1C,MAAO,IAGRzf,UAAUmB,YAAY7R,UAAUowB,UAAY,WAC3C,MAAO,IAGR1f,UAAUmB,YAAY7R,UAAUqwB,gBAAkB,WACjD,MAAO,IAGR3f,UAAUmB,YAAY7R,UAAUswB,cAAgB,WAC/C,MAAO,IAGR5f,UAAUmB,YAAY7R,UAAUuwB,cAAgB,WAC/C,MAAO,IAGR7f,UAAU8f,kBAAkBxwB,UAAU6vB,QAAU,WAC/C,OAAO,GAGRnf,UAAU8f,kBAAkBxwB,UAAUmwB,SAAW,WAChD,OAAO1yB,KAAKwZ,OAGbvG,UAAU8f,kBAAkBxwB,UAAUowB,UAAY,WACjD,OAAO3yB,KAAKyZ,QAGbxG,UAAU+f,iBAAiBzwB,UAAU8vB,QAAU,WAC9C,OAAO,GAGRpf,UAAU+f,iBAAiBzwB,UAAUqwB,gBAAkB,WACtD,OAAO5yB,KAAK+Z,eAGb9G,UAAU+f,iBAAiBzwB,UAAUswB,cAAgB,WACpD,OAAO7yB,KAAKia,YAGbhH,UAAU+f,iBAAiBzwB,UAAUuwB,cAAgB,WACpD,OAAO9yB,KAAKga,YAGb/G,UAAUggB,oBAAoB1wB,UAAU+vB,WAAa,WACpD,OAAO,GAGRrf,UAAUigB,oBAAoB3wB,UAAUgwB,WAAa,WACpD,OAAO,GAIRtf,UAAUkgB,aAAe,SAASC,EAAGC,GACpC,IAAIzb,EAAM0b,OAAOF,GAAGvb,SAAS,IAE7B,IADAwb,EAAU,MAAO,EAAgDA,EAAU,EAAIA,EACxEzb,EAAI5W,OAASqyB,GACnBzb,EAAM,IAAMA,EAEb,OAAOA,GAGR3E,UAAUsgB,gBAAgBhxB,UAAUkwB,SACpCxf,UAAUugB,gBAAgBjxB,UAAUkwB,SACpCxf,UAAUwgB,gBAAgBlxB,UAAUkwB,SACpCxf,UAAUygB,gBAAgBnxB,UAAUkwB,SAAW,WAC9C,IAAIkB,EAAY1gB,UAAUmB,YAAY7R,UAAUkwB,SAAS3gB,KAAK9R,MAC9D,OAAIA,KAAK4zB,KACDD,EAAU,IAAI1gB,UAAUkgB,aAAanzB,KAAK4zB,KAAKnY,sBAC7CxI,UAAUkgB,aAAanzB,KAAK4zB,KAAKlY,uBACjCzI,UAAUkgB,aAAanzB,KAAK4zB,KAAKjY,oBAEnCgY,GAIT1gB,UAAU4gB,gBAAgBtxB,UAAUkwB,SACpCxf,UAAU6gB,gBAAgBvxB,UAAUkwB,SAAW,WAC9C,IACIkB,EAAY1gB,UAAUmB,YAAY7R,UAAUkwB,SAAS3gB,KAAK9R,MAC9D,GAAIA,KAAK+zB,KAAM,CAEd,OADAJ,GAAa,IACL3zB,KAAK+zB,KAAK9S,uBACjB,KAAK,EACJ0S,GAAa,GACb,MACD,KAAK,EACJA,GAAa,IACb,MACD,KAAK,EACJA,GAAa,IACb,MACD,KAAK,EACJA,GAAa,IAGfA,GAAa3zB,KAAK+zB,KAAK5S,oBACvBwS,GAAa,IAGb,IAFA,IAAIK,EAAMh0B,KAAK+zB,KAAK3S,8BAChB6S,EAAW,EACVpyB,EAAE,EAAGA,EAAE,KACXoyB,GAAkB,EAAND,EACL,IAAHnyB,GAFWA,IAGfoyB,IAAa,EACbD,IAAO,EAERL,GAAa1gB,UAAUkgB,aAAac,EAAU,GAC9CN,GAAa,IACuB,IAAhC3zB,KAAK+zB,KAAK7S,kBACbyS,GAAa,IAEbA,GAAa,IAEdA,GAAa3zB,KAAK+zB,KAAKzS,kBACvB,IAAI4S,GAAU,EACVC,EAAoB,GACxB,IAAKtyB,EAAI,EAAQ,GAALA,EAAQA,KACf7B,KAAK+zB,KAAK1S,6BAA6Bxf,IAAMqyB,KAChDC,EAAoB,IAAIlhB,UAAUkgB,aAAanzB,KAAK+zB,KAAK1S,6BAA6Bxf,GAAI,GAAGsyB,EAC7FD,GAAU,GAGZP,GAAaQ,EAEd,OAAOR,GAGR1gB,UAAUmhB,gBAAgB7xB,UAAUkwB,SAAW,WAC9C,IAAIkB,EAAY1gB,UAAUmB,YAAY7R,UAAUkwB,SAAS3gB,KAAK9R,MAC9D,GAAIA,KAAKq0B,MAAQr0B,KAAKq0B,KAAK9T,IAAK,CAC/B,IAAIjO,EAAMtS,KAAKq0B,KAAK9T,IAAInO,SACpBI,EAAMxS,KAAKq0B,KAAK9T,IAAIhO,iBACxB,OAAOohB,EAAU,IAAI1gB,UAAUkgB,aAAa7gB,IAAME,EAAM,IAAIA,EAAK,IAEjE,OAAOmhB,GAIT1gB,UAAUqhB,gBAAgB/xB,UAAUkwB,SAAW,WAC9C,IAAIkB,EAAY1gB,UAAUmB,YAAY7R,UAAUkwB,SAAS3gB,KAAK9R,MAC9D,OAAGA,KAAK8nB,YACA6L,EAAY,IAAM3zB,KAAK8nB,YAEvB6L,GAIT1gB,UAAUshB,gBAAgBhyB,UAAUkwB,SAAW,WAC9C,IACI+B,EADAb,EAAY1gB,UAAUmB,YAAY7R,UAAUkwB,SAAS3gB,KAAK9R,MAQ9D,OAN8B,IAA1BA,KAAKy0B,KAAKja,aAAiD,IAA5Bxa,KAAKy0B,KAAK9Z,cAC5C6Z,EAAqC,IAAzBx0B,KAAKy0B,KAAK7Z,WAAoB,KAAO,KACtC5a,KAAKy0B,KAAKja,aAAe,IACpCga,EAAwC,IAA5Bx0B,KAAKy0B,KAAK9Z,cAAuB,KAAO,MAG9CgZ,EAAU,IAAI3zB,KAAKy0B,KAAKja,YAAY,IAAIxa,KAAKy0B,KAAKha,iBAAiBza,KAAKy0B,KAAK/Z,WAAW,IAAI,KAAK,IAAI8Z,GAS7GvhB,UAAUiB,IAAI3R,UAAUmyB,YAAc,SAASzjB,EAAQ3Q,GACtDN,KAAKqD,MAAQ,EACTrD,KAAKqD,KAAOiG,WACftJ,KAAKqD,MAAQ,GAEI,SAAdrD,KAAKuU,OACRvU,KAAKqD,MAAQ,IAEd3D,IAAIO,MAAM,YAAa,eAAeD,KAAKuU,KAAK,aAAavU,KAAKqD,KAAK,gBAAgB4N,EAAOzO,eAAelC,GAAO,KAChHN,KAAKqD,KAAOiG,SACf2H,EAAO7F,YAAY,IAEnBpL,KAAK20B,aAAe1jB,EAAOzO,cAC3ByO,EAAO7F,YAAYpL,KAAKqD,OAEzB4N,EAAOtE,YAAY3M,KAAKuU,KAAM,KAAM,GAClB,SAAdvU,KAAKuU,MACRtD,EAAOzF,gBAAgBxL,KAAK8U,MAEzB9U,KAAKqD,KAAOiG,UACf2H,EAAOtD,YAAY3N,KAAKqD,OAI1B4P,UAAUgB,QAAQ1R,UAAUmyB,YAAc,SAASzjB,GAClDjR,KAAKqD,MAAQ,EACb4P,UAAUiB,IAAI3R,UAAUmyB,YAAY5iB,KAAK9R,KAAMiR,EAAQ,MAAMjR,KAAK+U,QAAQ,MAAM/U,KAAKiS,OACrFhB,EAAOxF,WAAWzL,KAAK+U,SACvB9D,EAAOpD,YAAY7N,KAAKiS,QAGzBgB,UAAUiB,IAAI3R,UAAU6V,MAAQ,SAASnH,GACtB,SAAdjR,KAAKuU,KAEJvU,KAAK0R,OACR1R,KAAKqD,KAAOrD,KAAK0R,KAAK1Q,OACtBhB,KAAK00B,YAAYzjB,GACjBA,EAAOzF,gBAAgBxL,KAAK0R,QAG7B1R,KAAKqD,KAAQrD,KAAK0R,KAAO1R,KAAK0R,KAAK1Q,OAAS,EAC5ChB,KAAK00B,YAAYzjB,GACbjR,KAAK0R,MACRT,EAAOzF,gBAAgBxL,KAAK0R,QAK/BuB,UAAUkB,aAAa5R,UAAU6V,MAAQ,SAASnH,GACjDjR,KAAKqD,KAAO,EACZrD,KAAK00B,YAAYzjB,GACjB,IAAK,IAAIpP,EAAE,EAAGA,EAAE7B,KAAKgV,MAAMhU,OAAQa,IAC9B7B,KAAKgV,MAAMnT,KACd7B,KAAKgV,MAAMnT,GAAGuW,MAAMnH,GACpBjR,KAAKqD,MAAQrD,KAAKgV,MAAMnT,GAAGwB,MAI7B3D,IAAIO,MAAM,YAAa,iBAAiBD,KAAKuU,KAAK,kBAAkBvU,KAAKqD,MACzE4N,EAAOnD,aAAa9N,KAAK20B,aAAc30B,KAAKqD,OAG7C4P,UAAUqd,sBAAsB/tB,UAAU6V,MAAQ,SAASnH,GAC1DjR,KAAKqD,KAA6B,EAAtBrD,KAAKuwB,UAAUvvB,OAC3BhB,KAAK00B,YAAYzjB,GACjBA,EAAO/F,iBAAiBlL,KAAKuwB,YAI9Btd,UAAU2hB,QAAQryB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EAEJ,IADA7B,KAAKqD,KAAO,EACPxB,EAAI,EAAGA,EAAI7B,KAAK8b,IAAI9a,OAAQa,IAChC7B,KAAKqD,MAAQ,EAAErD,KAAK8b,IAAIja,GAAGb,OAE5B,IAAKa,EAAI,EAAGA,EAAI7B,KAAKic,IAAIjb,OAAQa,IAChC7B,KAAKqD,MAAQ,EAAErD,KAAKic,IAAIpa,GAAGb,OAY5B,IAVIhB,KAAKkc,MACRlc,KAAKqD,MAAQrD,KAAKkc,IAAIlb,QAEvBhB,KAAK00B,YAAYzjB,GACjBA,EAAOxF,WAAWzL,KAAKwb,sBACvBvK,EAAOxF,WAAWzL,KAAKyb,sBACvBxK,EAAOxF,WAAWzL,KAAK0b,uBACvBzK,EAAOxF,WAAWzL,KAAK2b,oBACvB1K,EAAOxF,WAAWzL,KAAK4b,mBAAqB,KAC5C3K,EAAOxF,WAAWzL,KAAK8b,IAAI9a,OAAS,KAC/Ba,EAAI,EAAGA,EAAI7B,KAAK8b,IAAI9a,OAAQa,IAChCoP,EAAO1F,YAAYvL,KAAK8b,IAAIja,GAAGb,QAC/BiQ,EAAOzF,gBAAgBxL,KAAK8b,IAAIja,GAAGka,MAGpC,IADA9K,EAAOxF,WAAWzL,KAAKic,IAAIjb,QACtBa,EAAI,EAAGA,EAAI7B,KAAKic,IAAIjb,OAAQa,IAChCoP,EAAO1F,YAAYvL,KAAKic,IAAIpa,GAAGb,QAC/BiQ,EAAOzF,gBAAgBxL,KAAKic,IAAIpa,GAAGka,MAEhC/b,KAAKkc,KACRjL,EAAOzF,gBAAgBxL,KAAKkc,MAK9BjJ,UAAU4hB,QAAQtyB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EAMJ,IALA7B,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,EAAErD,KAAK+c,cAAc/b,OACnChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK+c,cAAc/b,QAClCa,EAAE,EAAGA,EAAE7B,KAAK+c,cAAc/b,OAAQa,IACrCoP,EAAOtD,YAAY3N,KAAK+c,cAAclb,KAKxCoR,UAAU6hB,QAAQvyB,UAAU6V,MAAQ,SAASnH,GAE5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GACZrD,KAAK00B,YAAYzjB,GACjBA,EAAOtG,WAAW3K,KAAKyd,uBACvBxM,EAAOtG,WAAW3K,KAAK0d,2BACvBzM,EAAOtG,WAAW3K,KAAK2d,8BACvB1M,EAAOtG,WAAW3K,KAAK4d,sBACvB3M,EAAOtG,WAAW3K,KAAK6d,qBAIxB5K,UAAU8hB,QAAQxyB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EAMJ,IALA7B,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,EAAErD,KAAK8d,cAAc9c,OACnChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK8d,cAAc9c,QAClCa,EAAE,EAAGA,EAAE7B,KAAK8d,cAAc9c,OAAQa,IACrCoP,EAAO7F,YAAYpL,KAAK8d,cAAcjc,IACjB,IAAjB7B,KAAK+U,QACR9D,EAAOtG,WAAW3K,KAAK+d,eAAelc,IAEtCoP,EAAO7F,YAAYpL,KAAK+d,eAAelc,KAM1CoR,UAAU+hB,QAAQzyB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKsf,QAAQte,QAChC,IAAK,IAAIa,EAAI,EAAGA,EAAI7B,KAAKsf,QAAQte,OAAQa,IACxC7B,KAAKsf,QAAQzd,GAAGuW,MAAMnH,GACtBjR,KAAKqD,MAAQrD,KAAKsf,QAAQzd,GAAGwB,KAG9B3D,IAAIO,MAAM,YAAa,iBAAiBD,KAAKuU,KAAK,kBAAkBvU,KAAKqD,MACzE4N,EAAOnD,aAAa9N,KAAK20B,aAAc30B,KAAKqD,OAI7C4P,UAAUgiB,QAAQ1yB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAOrD,KAAKuf,kBAAkBve,OACnChB,KAAK00B,YAAYzjB,GACjBA,EAAOtE,YAAY3M,KAAKuf,oBAIzBtM,UAAUiiB,QAAQ3yB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,GAAGrD,KAAKsf,QAAQte,OAC9BhB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKsf,QAAQte,QAChC,IAAK,IAAIa,EAAI,EAAGA,EAAI7B,KAAKsf,QAAQte,OAAQa,IAAK,CAC7C,IAAI2d,EAAQxf,KAAKsf,QAAQzd,GACzBoP,EAAO7F,YAAYoU,EAAMC,kBACzBxO,EAAOtG,WAAW6U,EAAME,YACxBzO,EAAOnG,WAAW0U,EAAMG,oBACxB1O,EAAOnG,WAAW0U,EAAMI,uBAK1B3M,UAAUkiB,QAAQ5yB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GAAIrD,KAAKogB,aAAapf,QAAQhB,KAAKigB,cAAcjf,OAAO,IAAIhB,KAAK+N,MAAM/M,OAAO,GAC1FhB,KAAK00B,YAAYzjB,GACjBA,EAAOlE,aAAa/M,KAAKigB,eACzBhP,EAAOlE,aAAa/M,KAAK+N,OACzBkD,EAAO7F,YAAYpL,KAAK6f,WACxB5O,EAAO7F,YAAYpL,KAAKkgB,yBACxBjP,EAAO7F,YAAYpL,KAAK+f,gBACxB9O,EAAO7F,YAAYpL,KAAKggB,IACxB/O,EAAOzF,gBAAgBxL,KAAKogB,eAI7BnN,UAAUmb,QAAQ7rB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAKqD,KAAO,EAAE,EAAErD,KAAK6gB,kBAAkB7f,OACvChB,KAAK00B,YAAYzjB,GACjBA,EAAOtE,YAAY3M,KAAK2gB,YAAa,KAAM,GAC3C1P,EAAO7F,YAAYpL,KAAK4gB,eACxB,IAAK,IAAI/e,EAAI,EAAGA,EAAI7B,KAAK6gB,kBAAkB7f,OAAQa,IAClDoP,EAAOtE,YAAY3M,KAAK6gB,kBAAkBhf,GAAI,KAAM,IAKtDoR,UAAUmiB,QAAQ7yB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAKqD,KAAO,GAAIrD,KAAKmX,KAAKnW,OAAO,EACjChB,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAY,GACnB6F,EAAOtE,YAAY3M,KAAK8gB,QAAS,KAAM,GACvC7P,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAOlE,aAAa/M,KAAKmX,OAI1BlE,UAAUoiB,QAAQ9yB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAQrD,KAAK8kB,UAAU9jB,OAAO,GAAIhB,KAAK+N,MAAM/M,OAAO,GACzDhB,KAAK00B,YAAYzjB,GACjBA,EAAOlE,aAAa/M,KAAK8kB,WACzB7T,EAAOlE,aAAa/M,KAAK+N,QAI1BkF,UAAUqiB,QAAQ/yB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAKqD,KAAO,GACZrD,KAAKiS,MAAQ,EACbjS,KAAK+U,QAAU,EACf/U,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK+lB,eACxB9U,EAAO7F,YAAYpL,KAAKgmB,mBACxB/U,EAAO7F,YAAYpL,KAAK6f,WACxB5O,EAAO7F,YAAYpL,KAAKW,UACxBsQ,EAAO1F,YAAYvL,KAAK0Y,UACxBzH,EAAO1F,YAAY,IAIpB0H,UAAUsiB,QAAQhzB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKimB,oBAIzBhT,UAAUuiB,QAAQjzB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKkmB,kBAIzBjT,UAAUwiB,QAAQlzB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK+lB,eACxB9U,EAAO7F,YAAYpL,KAAKgmB,mBACxB/U,EAAO7F,YAAYpL,KAAK6f,WACxB5O,EAAO7F,YAAYpL,KAAKW,UACxBsQ,EAAO7F,YAAYpL,KAAKmmB,MACxBlV,EAAO1F,YAAYvL,KAAKomB,QAAQ,GAChCnV,EAAO1F,YAAY,GACnB0F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO/F,iBAAiBlL,KAAKqmB,QAC7BpV,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAYpL,KAAKsmB,gBAIzBrT,UAAUmB,YAAY7R,UAAUmyB,YAAc,SAASzjB,GACtDjR,KAAKqD,KAAO,EACZ4P,UAAUiB,IAAI3R,UAAUmyB,YAAY5iB,KAAK9R,KAAMiR,GAC/CA,EAAOxF,WAAW,GAClBwF,EAAOxF,WAAW,GAClBwF,EAAOxF,WAAW,GAClBwF,EAAOxF,WAAW,GAClBwF,EAAOxF,WAAW,GAClBwF,EAAOxF,WAAW,GAClBwF,EAAO1F,YAAYvL,KAAKqZ,uBAGzBpG,UAAUmB,YAAY7R,UAAUmzB,YAAc,SAASzkB,GACtD,IAAK,IAAIpP,EAAE,EAAGA,EAAE7B,KAAKgV,MAAMhU,OAAQa,IAClC7B,KAAKgV,MAAMnT,GAAGuW,MAAMnH,GACpBjR,KAAKqD,MAAQrD,KAAKgV,MAAMnT,GAAGwB,KAE5B3D,IAAIO,MAAM,YAAa,iBAAiBD,KAAKuU,KAAK,kBAAkBvU,KAAKqD,MACzE4N,EAAOnD,aAAa9N,KAAK20B,aAAc30B,KAAKqD,OAG7C4P,UAAUmB,YAAY7R,UAAU6V,MAAQ,SAASnH,GAChDjR,KAAK00B,YAAYzjB,GACjBA,EAAOzF,gBAAgBxL,KAAK0R,MAC5B1R,KAAKqD,MAAQrD,KAAK0R,KAAK1Q,OACvBtB,IAAIO,MAAM,YAAa,iBAAiBD,KAAKuU,KAAK,kBAAkBvU,KAAKqD,MACzE4N,EAAOnD,aAAa9N,KAAK20B,aAAc30B,KAAKqD,OAG7C4P,UAAU8f,kBAAkBxwB,UAAU6V,MAAQ,SAASnH,GACtDjR,KAAK00B,YAAYzjB,GACjBjR,KAAKqD,MAAQ,GACb4N,EAAO1F,YAAY,GACnB0F,EAAO1F,YAAY,GACnB0F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO1F,YAAYvL,KAAKwZ,OACxBvI,EAAO1F,YAAYvL,KAAKyZ,QACxBxI,EAAO7F,YAAYpL,KAAK0Z,iBACxBzI,EAAO7F,YAAYpL,KAAK2Z,gBACxB1I,EAAO7F,YAAY,GACnB6F,EAAO1F,YAAYvL,KAAK4Z,aACxB3I,EAAOxF,WAAWnK,KAAK0B,IAAI,GAAIhD,KAAK6Z,eAAe7Y,SACnDiQ,EAAOtE,YAAY3M,KAAK6Z,eAAgB,KAAM,IAC9C5I,EAAO1F,YAAYvL,KAAK8Z,OACxB7I,EAAOnG,YAAY,GACnB9K,KAAK01B,YAAYzkB,IAGlBgC,UAAU+f,iBAAiBzwB,UAAU6V,MAAQ,SAASnH,GACrDjR,KAAK00B,YAAYzjB,GACjBjR,KAAKqD,MAAQ,GACb4N,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAO1F,YAAYvL,KAAK+Z,eACxB9I,EAAO1F,YAAYvL,KAAKga,YACxB/I,EAAO1F,YAAY,GACnB0F,EAAO1F,YAAY,GACnB0F,EAAO7F,YAAYpL,KAAKia,YAAY,IACpCja,KAAK01B,YAAYzkB,IAGlBgC,UAAU0iB,gBAAgBpzB,UAAU6V,MAAQ,SAASnH,GACpDjR,KAAK00B,YAAYzjB,GACjBjR,KAAKqD,MAAQrD,KAAK+nB,UAAU/mB,OAAO,EAC/BhB,KAAKgoB,gBAAgBhnB,OAAO,EAC5BhB,KAAKioB,qBAAqBjnB,OAAO,EACrCiQ,EAAOlE,aAAa/M,KAAK+nB,WACzB9W,EAAOlE,aAAa/M,KAAKgoB,iBACzB/W,EAAOlE,aAAa/M,KAAKioB,sBACzBjoB,KAAK01B,YAAYzkB,IAIlBgC,UAAUiC,iBAAiB3S,UAAU6V,MAAQ,SAASnH,GACrDA,EAAOzF,gBAAgBxL,KAAK0R,OAI7BuB,UAAU2iB,QAAQrzB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GAAG,EAAErD,KAAKsf,QAAQte,OAC9BhB,KAAK00B,YAAYzjB,GACjBA,EAAOtE,YAAY3M,KAAKmV,cAAe,KAAM,GAC7ClE,EAAO7F,YAAYpL,KAAKolB,yBACxBnU,EAAO7F,YAAYpL,KAAKsf,QAAQte,QAChC,IAAK,IAAIa,EAAI,EAAGA,EAAI7B,KAAKsf,QAAQte,OAAQa,IAAK,CAC7C,IAAI2d,EAAQxf,KAAKsf,QAAQzd,GACzBoP,EAAOtG,WAAW6U,EAAMgH,cACxBvV,EAAOtG,WAAW6U,EAAMmL,2BAK1B1X,UAAU4iB,QAAQtzB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EACA2d,EAKJ,IAFAxf,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GACPxB,EAAI,EAAGA,EAAI7B,KAAKsf,QAAQte,OAAQa,IACpC2d,EAAQxf,KAAKsf,QAAQzd,GACA,IAAjB7B,KAAK+U,UACoB,IAAxB/U,KAAKmrB,iBACRnrB,KAAKqD,MAAQ,GAEdrD,KAAKqD,MAAQmc,EAAM9N,KAAK1Q,QAY1B,IATAhB,KAAK00B,YAAYzjB,GACjBA,EAAOtE,YAAY3M,KAAKmV,cAAe,KAAM,GACxB,IAAjBnV,KAAK+U,SACR9D,EAAO7F,YAAYpL,KAAKmrB,gBAEL,GAAhBnrB,KAAK+U,SACR9D,EAAO7F,YAAYpL,KAAKwvB,kCAEzBve,EAAO7F,YAAYpL,KAAKsf,QAAQte,QAC3Ba,EAAI,EAAGA,EAAI7B,KAAKsf,QAAQte,OAAQa,IACpC2d,EAAQxf,KAAKsf,QAAQzd,GACA,IAAjB7B,KAAK+U,SACoB,IAAxB/U,KAAKmrB,gBACRla,EAAO7F,YAAYoU,EAAMoJ,oBAG3BpJ,EAAMpH,MAAMnH,IAMdgC,UAAU6iB,QAAQvzB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GAAQ,GAAGrD,KAAKwkB,WAAWxjB,OACvChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKqrB,cACxBpa,EAAO7F,YAAYpL,KAAK6f,WACxB5O,EAAO7F,YAAYpL,KAAKsrB,4BACxBra,EAAO7F,YAAYpL,KAAKurB,cACxBta,EAAO1F,YAAY,GACnB0F,EAAO1F,YAAYvL,KAAKwkB,WAAWxjB,QACnC,IAAK,IAAIa,EAAI,EAAGA,EAAI7B,KAAKwkB,WAAWxjB,OAAQa,IAAK,CAChD,IAAI2pB,EAAMxrB,KAAKwkB,WAAW3iB,GAC1BoP,EAAO7F,YAAYogB,EAAIE,gBAAkB,GAAKF,EAAIG,iBAClD1a,EAAO7F,YAAYogB,EAAII,qBACvB3a,EAAO7F,YAAYogB,EAAIK,iBAAmB,GAAKL,EAAIM,UAAY,GAAKN,EAAIO,kBAK1E9Y,UAAU8iB,QAAQxzB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,EAAErD,KAAK+c,cAAc/b,OACnChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK+c,cAAc/b,QACtCiQ,EAAO/F,iBAAiBlL,KAAK+c,gBAI9B9J,UAAU+iB,QAAQzzB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EAMJ,IALA7B,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,GAAGrD,KAAKqtB,YAAYrsB,OAClChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKqtB,YAAYrsB,QAChCa,EAAE,EAAGA,EAAE7B,KAAKqtB,YAAYrsB,OAAQa,IACnCoP,EAAO7F,YAAYpL,KAAKqtB,YAAYxrB,IACpCoP,EAAO7F,YAAYpL,KAAKstB,kBAAkBzrB,IAC1CoP,EAAO7F,YAAYpL,KAAKutB,yBAAyB1rB,KAKnDoR,UAAUgjB,QAAQ1zB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EAOJ,IANA7B,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKsf,QAAQte,QAChChB,KAAKqD,MAAQ,EACRxB,EAAI,EAAGA,EAAI7B,KAAKsf,QAAQte,OAAQa,IACpC7B,KAAKsf,QAAQzd,GAAGuW,MAAMnH,GACtBjR,KAAKqD,MAAQrD,KAAKsf,QAAQzd,GAAGwB,KAG9B3D,IAAIO,MAAM,YAAa,iBAAiBD,KAAKuU,KAAK,kBAAkBvU,KAAKqD,MACzE4N,EAAOnD,aAAa9N,KAAK20B,aAAc30B,KAAKqD,OAI7C4P,UAAUijB,QAAQ3zB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EAMJ,IALA7B,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,EAAErD,KAAKytB,wBAAwBzsB,OAC7ChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKytB,wBAAwBzsB,QAC5Ca,EAAE,EAAGA,EAAE7B,KAAKytB,wBAAwBzsB,OAAQa,IAC/CoP,EAAO7F,YAAYpL,KAAKytB,wBAAwB5rB,IAChDoP,EAAO7F,YAAYpL,KAAK0tB,oBAAoB7rB,KAK9CoR,UAAUkjB,QAAQ5zB,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,EAAErD,KAAK2tB,eAAe3sB,OACpChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK2tB,eAAe3sB,QACvCiQ,EAAO/F,iBAAiBlL,KAAK2tB,iBAI9B1a,UAAUmjB,QAAQ7zB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EACAw0B,GAAW,EAGf,GAFAr2B,KAAK+U,QAAU,GACf/U,KAAKiS,MAAQ,GACTjS,KAAK4tB,aAAa5sB,OAErB,IADAa,EAAI,EACGA,EAAE,EAAI7B,KAAK4tB,aAAa5sB,QAAQ,CACtC,GAAIhB,KAAK4tB,aAAa/rB,EAAE,KAAQ7B,KAAK4tB,aAAa,GAAI,CACrDyI,GAAW,EACX,MAEAx0B,SAIFw0B,GAAW,EAEZr2B,KAAKqD,KAAO,EACPgzB,IACJr2B,KAAKqD,MAAQ,EAAErD,KAAK4tB,aAAa5sB,QAElChB,KAAK00B,YAAYzjB,GACZolB,EAGJplB,EAAO7F,YAAYpL,KAAK4tB,aAAa,IAFrC3c,EAAO7F,YAAY,GAIpB6F,EAAO7F,YAAYpL,KAAK4tB,aAAa5sB,QAChCq1B,GACJplB,EAAO/F,iBAAiBlL,KAAK4tB,eAK/B3a,UAAUqjB,QAAQ/zB,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIpP,EAMJ,IALA7B,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EAAE,EAAErD,KAAK8d,cAAc9c,OACnChB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK8d,cAAc9c,QAClCa,EAAE,EAAGA,EAAE7B,KAAK8d,cAAc9c,OAAQa,IACrCoP,EAAO7F,YAAYpL,KAAK8d,cAAcjc,IACtCoP,EAAO7F,YAAYpL,KAAK+tB,cAAclsB,KAKxCoR,UAAUsjB,QAAQh0B,UAAU6V,MAAQ,SAASnH,GAC5C,IAAIulB,EAAal1B,KAAKiI,IAAI,EAAG,IAAM,EAEnCvJ,KAAK+U,QAAU/U,KAAKovB,oBAAsBoH,EAAa,EAAI,EAC3Dx2B,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EACS,IAAjBrD,KAAK+U,UACR/U,KAAKqD,MAAQ,GAEdrD,KAAK00B,YAAYzjB,GACI,IAAjBjR,KAAK+U,QACR9D,EAAOtD,YAAY3N,KAAKovB,qBAExBne,EAAO7F,YAAYpL,KAAKovB,sBAK1Bnc,UAAUwjB,QAAQl0B,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKqD,KAAO,EACRrD,KAAKiS,MAAQgB,UAAUoD,6BAC1BrW,KAAKqD,MAAQ,GAEVrD,KAAKiS,MAAQgB,UAAUqD,wBAC1BtW,KAAKqD,MAAQ,GAEVrD,KAAKiS,MAAQgB,UAAUsD,uBAC1BvW,KAAKqD,MAAQ,GAEVrD,KAAKiS,MAAQgB,UAAUuD,wBAC1BxW,KAAKqD,MAAQ,GAEVrD,KAAKiS,MAAQgB,UAAUwD,yBAC1BzW,KAAKqD,MAAQ,GAEdrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKsvB,UACpBtvB,KAAKiS,MAAQgB,UAAUoD,4BAC1BpF,EAAOtD,YAAY3N,KAAKuvB,kBAErBvvB,KAAKiS,MAAQgB,UAAUqD,uBAC1BrF,EAAO7F,YAAYpL,KAAKwvB,kCAErBxvB,KAAKiS,MAAQgB,UAAUsD,sBAC1BtF,EAAO7F,YAAYpL,KAAKyvB,yBAErBzvB,KAAKiS,MAAQgB,UAAUuD,uBAC1BvF,EAAO7F,YAAYpL,KAAK0vB,qBAErB1vB,KAAKiS,MAAQgB,UAAUwD,wBAC1BxF,EAAO7F,YAAYpL,KAAK2vB,uBAK1B1c,UAAUyjB,QAAQn0B,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EAEf/U,KAAKqD,KAAO,GACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAK+lB,eACxB9U,EAAO7F,YAAYpL,KAAKgmB,mBACxB/U,EAAO7F,YAAYpL,KAAKsvB,UACxBre,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAYpL,KAAKW,UACxBsQ,EAAO7F,YAAY,GACnB6F,EAAO7F,YAAY,GACnB6F,EAAOnG,WAAW9K,KAAKowB,OACvBnf,EAAOnG,WAAW9K,KAAKmtB,iBACvBlc,EAAOnG,WAAW9K,KAAKomB,QAAQ,GAC/BnV,EAAO1F,YAAY,GACnB0F,EAAOxG,gBAAgBzK,KAAKqmB,QAC5BpV,EAAO7F,YAAYpL,KAAKwZ,OACxBvI,EAAO7F,YAAYpL,KAAKyZ,SAIzBxG,UAAU0jB,QAAQp0B,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKsvB,UACxBre,EAAO7F,YAAYpL,KAAKwvB,kCACxBve,EAAO7F,YAAYpL,KAAKyvB,yBACxBxe,EAAO7F,YAAYpL,KAAK0vB,qBACxBze,EAAO7F,YAAYpL,KAAK2vB,uBAIzB1c,UAAU2jB,QAAQr0B,UAAU6V,MAAQ,SAASnH,GAC5CjR,KAAK+U,QAAU,EACf/U,KAAKqD,KAAO,EACRrD,KAAKiS,MAAQgB,UAAU2D,yBAC1B5W,KAAKqD,MAAQ,GAEVrD,KAAKiS,MAAQgB,UAAU4D,wBAC1B7W,KAAKqD,MAAQ,GAEVrD,KAAKiS,MAAQgB,UAAU6D,sBAC1B9W,KAAKqD,MAAQ,EAAErD,KAAK2wB,gBAAgB3vB,QAEjChB,KAAKiS,MAAQgB,UAAU8D,kBAC1B/W,KAAKqD,MAAQ,EAAErD,KAAK6tB,YAAY7sB,QAE7BhB,KAAKiS,MAAQgB,UAAU+D,mBAC1BhX,KAAKqD,MAAQ,EAAErD,KAAK4wB,aAAa5vB,QAE9BhB,KAAKiS,MAAQgB,UAAUgE,wBAC1BjX,KAAKqD,MAAQ,EAAErD,KAAK6wB,+BAA+B7vB,QAEpDhB,KAAK00B,YAAYzjB,GACjBA,EAAO7F,YAAYpL,KAAKwmB,cACpBxmB,KAAKiS,MAAQgB,UAAU2D,yBAC1B5W,KAAK62B,qBAAuB5lB,EAAOzO,cACnCyO,EAAOtG,WAAW3K,KAAKywB,cAEpBzwB,KAAKiS,MAAQgB,UAAU4D,uBAC1B5F,EAAO7F,YAAYpL,KAAK0wB,oBAEzB,IAAK,IAAI7uB,EAAI,EAAGA,EAAI7B,KAAKwmB,aAAc3kB,IAClC7B,KAAKiS,MAAQgB,UAAU6D,qBAC1B7F,EAAO7F,YAAYpL,KAAK2wB,gBAAgB9uB,IAErC7B,KAAKiS,MAAQgB,UAAU8D,iBAC1B9F,EAAO7F,YAAYpL,KAAK6tB,YAAYhsB,IAEjC7B,KAAKiS,MAAQgB,UAAU+D,kBAC1B/F,EAAO7F,YAAYpL,KAAK4wB,aAAa/uB,IAElC7B,KAAKiS,MAAQgB,UAAUgE,wBACL,IAAjBjX,KAAK+U,QACR9D,EAAO7F,YAAYpL,KAAK6wB,+BAA+BhvB,IAEvDoP,EAAOtG,WAAW3K,KAAK6wB,+BAA+BhvB,MAO1DoR,UAAU,WAAW1Q,UAAU6V,MAAQ,SAASnH,GAC/CjR,KAAK+U,QAAU,EACX/U,KAAK+wB,UACR/wB,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAOrD,KAAK+wB,SAAS/vB,OAAO,IAEjChB,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,GAEbrD,KAAK00B,YAAYzjB,GACbjR,KAAK+wB,UACR9f,EAAOlE,aAAa/M,KAAK+wB,WAK3B9d,UAAU,WAAW1Q,UAAU6V,MAAQ,SAASnH,GAC/CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAOrD,KAAKmX,KAAKnW,OAAO,GAAGhB,KAAK+wB,SAAW/wB,KAAK+wB,SAAS/vB,OAAO,EAAI,GACzEhB,KAAK00B,YAAYzjB,GACjBA,EAAOlE,aAAa/M,KAAKmX,MACrBnX,KAAK+wB,UACR9f,EAAOlE,aAAa/M,KAAK+wB,WAK3B9d,UAAU6jB,QAAQv0B,UAAU6V,MAAQ,SAASnH,GAE5CjR,KAAK+U,QAAU,EACf/U,KAAKiS,MAAQ,EACbjS,KAAKqD,KAAO,EACZrD,KAAK00B,YAAYzjB,GACjBA,EAAO1F,YAAYvL,KAAKuxB,cACxBtgB,EAAO5F,iBAAiBrL,KAAKwxB,UAQ9Bve,UAAU8hB,QAAQxyB,UAAUw0B,OAAS,SAASC,GAG7C,IAFA,IAAOpuB,EACPC,EAAI,EACChH,EAAI,EAAGA,EAAI7B,KAAK8d,cAAc9c,OAAQa,IAC1C,IAAK+G,EAAI,EAAGA,EAAI5I,KAAK8d,cAAcjc,GAAI+G,IACtCouB,EAAQnuB,GAAGouB,IAAMD,EAAQnuB,GAAGquB,IAAMl3B,KAAK+d,eAAelc,GACtDgH,KAKHoK,UAAUqjB,QAAQ/zB,UAAUw0B,OAAS,SAASC,GAG7C,IAFA,IAAOpuB,EACPC,EAAI,EACChH,EAAI,EAAGA,EAAI7B,KAAK8d,cAAc9c,OAAQa,IAC1C,IAAK+G,EAAI,EAAGA,EAAI5I,KAAK8d,cAAcjc,GAAI+G,IAErCouB,EAAQnuB,GAAGquB,IADF,IAANruB,EACc,EAEAmuB,EAAQnuB,EAAE,GAAGquB,IAAMl3B,KAAK+tB,cAAclsB,GAExDgH,KAKHoK,UAAU8iB,QAAQxzB,UAAUw0B,OAAS,SAASC,GAE7C,IADA,IACKn1B,EAAI,EAAGA,EAAI7B,KAAK+c,cAAc/b,OAAQa,IAC1Cm1B,EAAQn1B,GAAG2I,OAASxK,KAAK+c,cAAclb,IAIzCoR,UAAU+iB,QAAQzzB,UAAUw0B,OAAS,SAASC,GAI7C,IAHA,IAAOpuB,EAAGC,EACVkJ,EAAI,EACJolB,EAAI,EACCt1B,EAAI,EAAGA,EAAI7B,KAAKqtB,YAAYrsB,OAAQa,IACxC,IAAK+G,EAAI,EAAGA,GAAK/G,EAAE,EAAI7B,KAAKqtB,YAAYrsB,OAAShB,KAAKqtB,YAAYxrB,EAAE,GAAKu1B,EAAAA,GAAWxuB,IAEnF,IADAuuB,IACKtuB,EAAI,EAAGA,EAAI7I,KAAKstB,kBAAkBzrB,GAAIgH,IAAK,CAC/C,IAAImuB,EAAQjlB,GAIX,OAHAilB,EAAQjlB,GAAGslB,kBAAoBr3B,KAAKutB,yBAAyB1rB,GAC7Dm1B,EAAQjlB,GAAGulB,YAAcH,EAI1BplB,MAMJkB,UAAUmjB,QAAQ7zB,UAAUw0B,OAAS,SAASC,GAE7C,IADA,IACKn1B,EAAI,EAAGA,EAAI7B,KAAK4tB,aAAa5sB,OAAQa,IACzCm1B,EAAQn1B,GAAGwB,KAAOrD,KAAK4tB,aAAa/rB,IAKtCoR,UAAUskB,sBAAwB,CAAE,QAAS,UAAW,aAAc,aAC9D,QAAS,aAAc,UAAW,eAClC,cAAe,SAAU,YAAa,aACtC,MAAO,UAEftkB,UAAUukB,gCAAkC,CAAE,oBAAqB,SAAU,UAAW,gBAAiB,gBAAiB,gBAC1H,cAAe,oBAAqB,eAAgB,gBAAiB,iBAAkB,2BAA4B,mBAEnHvkB,UAAUwkB,eAAiB,SAASC,EAAOC,GAC1C,GAAID,IAAUC,EAAO,OAAO,EAE5B,IADA,IAAIrgB,KACSogB,EACZ,MAAqD,EAAjDzkB,UAAUskB,sBAAsB/e,QAAQlB,IAIjCogB,EAAMpgB,aAAiBrE,UAAUiB,KAAOyjB,EAAMrgB,aAAiBrE,UAAUiB,UAElD,IAAhBwjB,EAAMpgB,SAAgD,IAAhBqgB,EAAMrgB,IAE5B,mBAAhBogB,EAAMpgB,IAA+C,mBAAhBqgB,EAAMrgB,IAG3DogB,EAAMniB,cAA6D,EAA9CmiB,EAAMniB,YAAYiD,QAAQlB,EAAKyJ,MAAM,EAAE,KAC5D4W,EAAMpiB,cAA6D,EAA9CoiB,EAAMpiB,YAAYiD,QAAQlB,EAAKyJ,MAAM,EAAE,KAGhD,SAATzJ,GAA4B,UAATA,GAA6B,SAATA,GAA4B,kBAATA,GAAqC,sBAATA,IAEpB,EAA3DrE,UAAUukB,gCAAgChf,QAAQlB,IAGxDogB,EAAMpgB,KAAUqgB,EAAMrgB,IACzB,OAAO,EAKX,OAAO,GAGRrE,UAAU2kB,SAAW,SAASF,EAAOC,GACpC,IAAK1kB,UAAUwkB,eAAeC,EAAOC,GACpC,OAAO,EAER,IAAK,IAAI/uB,EAAI,EAAGA,EAAIqK,UAAUskB,sBAAsBv2B,OAAQ4H,IAAK,CAChE,IAAIuO,EAAOlE,UAAUskB,sBAAsB3uB,GAC3C,GAAI8uB,EAAMvgB,IAASwgB,EAAMxgB,KACnBlE,UAAU2kB,SAASF,EAAMvgB,GAAOwgB,EAAMxgB,IAC1C,OAAO,EAIV,OAAO,GAMR,IAAI0gB,aAAe,aAGnBA,aAAat1B,UAAUu1B,YAAc,SAASpmB,GAI7C,IAHA,IAAUqmB,EACN9mB,EAAS,IAAIjP,aAAa0P,EAAKvP,QACnC61B,EAAO,IACC/mB,EAAO9N,UACd40B,EAAM9kB,UAAU6E,YAAY7G,GAAQ,IAC5BgH,OAAShF,UAAUG,IAAuB,SAAjB2kB,EAAI1gB,IAAI9C,MACxCyjB,EAAKtzB,KAAKqzB,EAAI1gB,KAGhB,OAAO2gB,GAGRH,aAAat1B,UAAU01B,QAAU,SAAUC,EAAWC,EAASzmB,GAC9D,SAAS5Q,EAAIs3B,EAAG5e,EAAO6e,GAGrB,OAFAA,EAAIA,GAAK,KACTD,GAAQ,IACCp3B,QAAUwY,EAAQ4e,EAAI,IAAI9qB,MAAMkM,EAAQ4e,EAAEp3B,OAAS,GAAGG,KAAKk3B,GAAKD,EAE3E,SAASE,EAAeC,GACvB,IAAI3qB,EAAItM,KAAKC,MAAMg3B,EAAM,MACrBpB,EAAI71B,KAAKC,OAAOg3B,EAAU,KAAF3qB,GAAQ,IAChCxJ,EAAI9C,KAAKC,MAAMg3B,EAAU,KAAF3qB,EAAW,GAAFupB,GAChCqB,EAAKl3B,KAAKC,MAAkC,KAA3Bg3B,EAAU,KAAF3qB,EAAW,GAAFupB,EAAO/yB,IAC7C,OAAUtD,EAAI8M,EAAG,GAAG,IAAI9M,EAAIq2B,EAAE,GAAG,IAAIr2B,EAAIsD,EAAG,GAAG,IAAItD,EAAI03B,EAAI,GAI5D,IAFA,IAAIR,EAAOh4B,KAAK83B,YAAYpmB,GACxB+mB,EAAS,GACJ52B,EAAI,EAAGA,EAAIm2B,EAAKh3B,OAAQa,IAAK,CACrC,IAAI62B,EAASV,EAAKn2B,GAClB42B,GAAUH,EAAeJ,GAAW,WAAQI,EAAeH,GAAS,OACpEM,GAAUC,EAAOC,KAAK/R,KAEvB,OAAO6R,GAGR,IAAIG,qBAAuB,aAG3BA,qBAAqBr2B,UAAUu1B,YAAc,SAASe,GACrD,IACIh3B,EADA0B,EAAM,CAEVu1B,UAAgB,IACZ7nB,EAAS,IAAIjP,aAAa62B,EAAOnnB,KAAKvP,QAC1C,GAAK02B,EAAOpK,YAA2C,IAA7BoK,EAAOpK,WAAWztB,QAI3C,GADAuC,EAAIw1B,eAAiB9nB,EAAO9M,WAAW00B,EAAOpK,WAAW,GAAGprB,MAC7B,EAA3Bw1B,EAAOpK,WAAWztB,OACrB,IAAKa,EAAI,EAAGA,EAAIg3B,EAAOpK,WAAWztB,OAAQa,IACzC0B,EAAIu1B,UAAUj3B,GAAKoP,EAAOjM,eAAe6zB,EAAOpK,WAAW5sB,GAAGwB,WALhEE,EAAIw1B,eAAiB9nB,EAAO9M,WAAW00B,EAAOnnB,KAAK1Q,QAYpD,MAH2B,oBAAhB,YACVuC,EAAIyG,UAAW,IAAKgvB,WAAaC,gBAAgB11B,EAAIw1B,eAAgB,oBAE/Dx1B,GAGR,IAAI21B,cAAgB,aAGpBA,cAAc32B,UAAUu1B,YAAc,SAASe,GAI9C,OAFa,IAAI72B,aAAa62B,EAAOnnB,KAAKvP,QACtBgC,WAAW00B,EAAOnnB,KAAK1Q,SAI5Ck4B,cAAc32B,UAAU42B,YAAc,SAASznB,GAE1CT,EAAS,IAAIjP,aAAa0P,EAAKvP,QAGnC,OAFA8O,EAAOhN,aACMgN,EAAO1M,eAIE,oBAAZxC,UACVA,QAAQ62B,qBAAuBA,qBAC/B72B,QAAQm3B,cAAgBA,eAOzB,IAAIE,QAAU,SAAUnoB,GAEvBjR,KAAKiR,OAASA,GAAU,IAAIjD,kBAE5BhO,KAAKgV,MAAQ,GAEbhV,KAAKq5B,MAAQ,GAEbr5B,KAAKs5B,MAAQ,GAEbt5B,KAAKu5B,eAAgB,EAErBv5B,KAAKw5B,gBAAiB,EAEtBx5B,KAAKy5B,YAAc,KAEnBz5B,KAAK05B,eAAgB,EAErB15B,KAAK25B,QAAU,KAEf35B,KAAK45B,WAAY,EAEjB55B,KAAK65B,UAAY,KAEjB75B,KAAK85B,UAAY,KAEjB95B,KAAK+5B,QAAU,KAEf/5B,KAAKg6B,iBAAkB,EAEvBh6B,KAAKi6B,iBAAmB,GAExBj6B,KAAKk6B,gBAAkB,GAEvBl6B,KAAKm6B,4BAA6B,EAElCn6B,KAAKo6B,yBAA0B,EAE/Bp6B,KAAKq6B,eAAiB,EAEtBr6B,KAAKs6B,eAAgB,EAErBt6B,KAAKu6B,OAAS,KAEdv6B,KAAKw6B,UAAW,GAGjBpB,QAAQ72B,UAAUk4B,kBAAoB,SAASza,EAAI0a,EAAMC,GACxD,IAEKC,EAFDC,EAAO76B,KAAK86B,aAAa9a,GACzB6a,IACCD,EAAY,GAChB56B,KAAKi6B,iBAAiBv1B,KAAKk2B,GAC3BA,EAAU5a,GAAKA,EACf4a,EAAUF,KAAOA,GACjBE,EAAUC,KAAOA,GACZE,WAAa,EAClBH,EAAUI,cAAgB,KAC1BJ,EAAUK,WAAa,IACvBL,EAAUM,eAAgB,EACtBP,IACCA,EAAQQ,YAAWP,EAAUK,WAAaN,EAAQQ,WAClDR,EAAQO,gBAAeN,EAAUM,cAAgBP,EAAQO,kBAKhE9B,QAAQ72B,UAAU64B,oBAAsB,SAASpb,GAEhD,IADA,IAAI/P,GAAS,EACJpO,EAAI,EAAGA,EAAI7B,KAAKi6B,iBAAiBj5B,OAAQa,IACjC7B,KAAKi6B,iBAAiBp4B,GACxBme,IAAMA,IACnB/P,EAAQpO,IAGG,EAAToO,GACHjQ,KAAKi6B,iBAAiBhrB,OAAOgB,EAAO,IAItCmpB,QAAQ72B,UAAU84B,qBAAuB,SAASrb,EAAI0a,EAAMC,GAC3D,IAEKW,EAFDT,EAAO76B,KAAK86B,aAAa9a,GACzB6a,IACCS,EAAe,GACnBt7B,KAAKk6B,gBAAgBx1B,KAAK42B,GAC1BA,EAAatb,GAAKA,EAClBsb,EAAaZ,KAAOA,GACpBY,EAAaT,KAAOA,GACfE,WAAa,EAClBO,EAAaL,WAAa,IAC1BK,EAAatE,QAAU,GACnB2D,GACCA,EAAQQ,YAAWG,EAAaL,WAAaN,EAAQQ,aAK5D/B,QAAQ72B,UAAUg5B,uBAAyB,SAASvb,GAEnD,IADA,IAAI/P,GAAS,EACJpO,EAAI,EAAGA,EAAI7B,KAAKk6B,gBAAgBl5B,OAAQa,IAC7B7B,KAAKk6B,gBAAgBr4B,GACvBme,IAAMA,IACtB/P,EAAQpO,IAGG,EAAToO,GACHjQ,KAAKk6B,gBAAgBjrB,OAAOgB,EAAO,IAIrCmpB,QAAQ72B,UAAU+O,MAAQ,WACzB,IACIiH,EAIJ,IAAIvY,KAAKw7B,sBACHx7B,KAAKw7B,uBAKX,OAEC,GAAIx7B,KAAKy7B,mBAAqBz7B,KAAKy7B,qBAClC,IAAIz7B,KAAK07B,wBAGR,YAOD,GAJI17B,KAAK27B,mBACR37B,KAAK27B,qBAENpjB,EAAMtF,UAAU6E,YAAY9X,KAAKiR,QApBT,IAqBhBgH,OAAShF,UAAUE,oBAAqB,CAC/C,IAAInT,KAAK47B,qBAOR,OANA,IAAI57B,KAAK47B,qBAAqBrjB,GAG7B,WAKI,CACN,IAEAlB,EACAa,EAAyB,UADzBb,EAAMkB,EAAIlB,KACM9C,KAAkB8C,EAAI9C,KAAO8C,EAAIvC,KAIjD,OAFA9U,KAAKgV,MAAMtQ,KAAK2S,GAERa,GACP,IAAK,OACJlY,KAAKq5B,MAAM30B,KAAK2S,GAChB,MACD,IAAK,OACJrX,KAAKs5B,MAAM50B,KAAK2S,GAChB,MACD,IAAK,OACJrX,KAAKw5B,gBAAiB,EACI,IAAtBx5B,KAAKq5B,MAAMr4B,SACdhB,KAAKu5B,eAAgB,GAIvB,aACwBh5B,IAAnBP,KAAKkY,IACRxY,IAAIS,KAAK,UAAW,0BAA0B+X,EAAS,oCAExDlY,KAAKkY,GAAYb,EAGfrX,KAAK67B,iBACR77B,KAAK67B,gBAAgBxkB,EAAKkB,KAO/B6gB,QAAQ72B,UAAUu5B,YAAc,SAAU/sB,GACzC,GAAIA,MAAAA,EACH,KAAK,uCAEN,QAAqBxO,IAAjBwO,EAAGT,UACN,KAAK,wCAEN,OAAsB,IAAlBS,EAAGrM,YACNhD,IAAIS,KAAK,UAAW,qCAAqC4O,EAAGT,UAAU,KACtEtO,KAAKiR,OAAO1C,kBACL,IAER7O,IAAIQ,KAAK,UAAW,iCAAiC6O,EAAGT,UAAU,KAGlES,EAAGD,UAAY,EACf9O,KAAKiR,OAAO9C,aAAaY,GACzB/O,KAAKiR,OAAO1C,mBAEPvO,KAAKiR,OAAO7C,gBAChB1O,IAAIS,KAAK,UAAW,+BACb,KAOTi5B,QAAQ72B,UAAUw5B,aAAe,SAAShtB,EAAIitB,GAC7C,IAAIC,EACJ,GAAKj8B,KAAK87B,YAAY/sB,GA8EtB,OAzEA/O,KAAKsR,QAGDtR,KAAKw5B,iBAAmBx5B,KAAK05B,gBAChC15B,KAAK05B,eAAgB,EACjB15B,KAAKy5B,aAAaz5B,KAAKy5B,eAGxBz5B,KAAKk8B,MAIHl8B,KAAKg6B,kBACTh6B,KAAKm8B,mBACLn8B,KAAKg6B,iBAAkB,GAIxBh6B,KAAKo8B,oBAIDp8B,KAAK25B,UAAY35B,KAAK45B,YACzB55B,KAAK45B,WAAY,EACjB55B,KAAK25B,QAAQ35B,KAAKq8B,YAInBr8B,KAAKs8B,eAAeN,GAGhBh8B,KAAKu8B,kBACRN,EAAgBj8B,KAAKu8B,iBACrBv8B,KAAKu8B,sBAAmBh8B,GAExB07B,EAAgBj8B,KAAKw8B,kBAElBx8B,KAAKiR,OAAOX,0BACf2rB,EAAgBj8B,KAAKiR,OAAOX,wBAAwB2rB,KAMpDA,EAHGj8B,KAAKw8B,mBAMQ,EAGdx8B,KAAKy8B,MACJz8B,KAAKu6B,SAAWv6B,KAAKw6B,WACxBx6B,KAAKu6B,OAAOv6B,KAAKy8B,MACjBz8B,KAAKw6B,UAAW,GAGdx6B,KAAK08B,OACJ18B,KAAK28B,kBAAoB38B,KAAKs6B,gBACjCt6B,KAAK28B,kBACL38B,KAAKs6B,eAAgB,GAElBt6B,KAAK48B,cACR58B,KAAK48B,aAAa58B,KAAK68B,SAIrB78B,KAAKiR,OAAO3B,eACf5P,IAAIQ,KAAK,UAAW,sCAAsC6O,EAAGT,UAAU,gEAAgE2tB,GACvIj8B,KAAKiR,OAAO1C,iBACZvO,KAAKiR,OAAO3B,eACZtP,KAAKiR,OAAO1C,gBAAe,GAC3B7O,IAAIQ,KAAK,UAAW,+BAA+BF,KAAK88B,+BAElDb,GAGR7C,QAAQ72B,UAAU85B,QAAU,WAC3B,IAAIx6B,EAAG+G,EAEHiyB,EACAkC,EACAC,EAHAC,EAAQ,GAIRC,EAAS,IAAIt9B,KAAK,wBAAwBu9B,UAE9C,GAAIn9B,KAAKk8B,KAsBR,IArBAe,EAAMG,SAAU,EAChBH,EAAMt8B,SAAWX,KAAKk8B,KAAKmB,KAAK18B,SAChCs8B,EAAMpd,UAAY7f,KAAKk8B,KAAKmB,KAAKxd,UACjCod,EAAMK,aAAkC,MAAlBt9B,KAAKk8B,KAAKqB,KAC5BN,EAAMK,cAAgBt9B,KAAKk8B,KAAKqB,KAAKC,OACxCP,EAAMhX,kBAAoBjmB,KAAKk8B,KAAKqB,KAAKC,KAAKvX,mBAE/CgX,EAAM1D,cAAgBv5B,KAAKu5B,cAC3B0D,EAAMQ,OAA4B,MAAlBz9B,KAAKk8B,KAAKwB,KAC1BT,EAAMU,OAAS,GACfV,EAAMU,OAAOj5B,KAAK1E,KAAK49B,KAAKjd,aAC5Bsc,EAAMU,OAASV,EAAMU,OAAOnvB,OAAOxO,KAAK49B,KAAK/c,mBAC7Coc,EAAMY,QAAU,IAAIj+B,KAAKs9B,EAAmC,IAA7Bl9B,KAAKk8B,KAAKmB,KAAKtX,eAC9CkX,EAAMa,SAAW,IAAIl+B,KAAKs9B,EAAuC,IAAjCl9B,KAAKk8B,KAAKmB,KAAKrX,mBAC/CiX,EAAMc,OAAS,GACfd,EAAMe,YAAc,GACpBf,EAAMgB,YAAc,GACpBhB,EAAMiB,eAAiB,GACvBjB,EAAMkB,eAAiB,GACvBlB,EAAMmB,WAAa,GACnBnB,EAAMoB,YAAc,GACfx8B,EAAI,EAAGA,EAAI7B,KAAKk8B,KAAKoC,MAAMt9B,OAAQa,IAAK,CAQ5C,GANAm7B,GADAnC,EAAO76B,KAAKk8B,KAAKoC,MAAMz8B,IACJ08B,KAAKC,KAAKC,KAAKC,KAAKpf,QAAQ,GAC/Cyd,EAAQ,GACRE,EAAMc,OAAOr5B,KAAKq4B,GAClBA,EAAM/c,GAAK6a,EAAK8D,KAAKrP,SACrByN,EAAM5lB,KAAO0jB,EAAK0D,KAAKK,KAAKznB,KAC5B4lB,EAAMvY,WAAa,GACfqW,EAAKgE,KACR,IAAKj2B,EAAI,EAAGA,EAAIiyB,EAAKgE,KAAK7pB,MAAMhU,OAAQ4H,IACvC4iB,IAAM,GACNuR,EAAMvY,WAAW9f,KAAK8mB,KACtBA,IAAIjX,KAAOsmB,EAAKgE,KAAK7pB,MAAMpM,GAAG2L,KAC9BiX,IAAI+E,UAAYsK,EAAKgE,KAAK7pB,MAAMpM,GAAG2nB,UAGjCsK,EAAKiE,OACR/B,EAAMgC,MAAQlE,EAAKiE,KAAKE,KAAK1f,SAE9Byd,EAAMc,QAAU,IAAIj+B,KAAKs9B,EAA8B,IAAxBrC,EAAK8D,KAAK5Y,eACzCgX,EAAMe,SAAW,IAAIl+B,KAAKs9B,EAAkC,IAA5BrC,EAAK8D,KAAK3Y,mBAC1C+W,EAAMkC,eAAiBpE,EAAK8D,KAAKh+B,SACjCo8B,EAAMmC,gBAAkBjC,EAAMpd,UAC9Bkd,EAAM3M,MAAQyK,EAAK8D,KAAKvO,MACxB2M,EAAM5P,gBAAkB0N,EAAK8D,KAAKxR,gBAClC4P,EAAM3W,OAASyU,EAAK8D,KAAKvY,OACzB2W,EAAM1W,OAASwU,EAAK8D,KAAKtY,OACzB0W,EAAMoC,YAActE,EAAK8D,KAAKnlB,MAAM,MACpCujB,EAAMqC,aAAevE,EAAK8D,KAAKllB,OAAO,MACtCsjB,EAAMld,UAAYgb,EAAK0D,KAAKc,KAAKxf,UACjCkd,EAAMuC,UAAYzE,EAAK0D,KAAKC,KAAKC,KAAKc,KACtCxC,EAAMp8B,SAAWk6B,EAAK0D,KAAKc,KAAK1+B,SAChCo8B,EAAMyC,iBAAmB3E,EAAK2E,iBAC9BzC,EAAM0C,MAAQzC,EAAYvK,WAC1BsK,EAAM2C,KAAQ7E,EAAK8E,MAAQ9E,EAAK8E,KAAKC,MAAM5+B,OAAS65B,EAAK8E,KAAKC,MAAM,GAAK,CAAE9a,UAAW,GAAI/W,MAAO,IACjGgvB,EAAMrkB,SAAYmiB,EAAK0D,KAAKsB,KAAOhF,EAAK0D,KAAKsB,KAAKtgB,kBAAoBsb,EAAK0D,KAAKc,KAAKzmB,eACrFmkB,EAAM9B,WAAaJ,EAAK7D,QAAQh2B,OAChC+7B,EAAM15B,KAAOw3B,EAAKiF,aAClB/C,EAAMgD,QAAsB,EAAXhD,EAAM15B,KAAO05B,EAAMld,UAAWkd,EAAMyC,iBACjDxC,EAAY3K,WACf0K,EAAMxoB,KAAO,QACb0oB,EAAMe,YAAYt5B,KAAKq4B,GACvBA,EAAMiD,MAAQ,GACdjD,EAAMiD,MAAMC,YAAcjD,EAAYnK,gBACtCkK,EAAMiD,MAAMjmB,cAAgBijB,EAAYpK,kBACxCmK,EAAMiD,MAAMnS,YAAcmP,EAAYlK,iBAC5BkK,EAAY5K,WACtB2K,EAAMxoB,KAAO,QACb0oB,EAAMgB,YAAYv5B,KAAKq4B,GACvBA,EAAMmD,MAAQ,GACdnD,EAAMmD,MAAM1mB,MAAQwjB,EAAYtK,WAChCqK,EAAMmD,MAAMzmB,OAASujB,EAAYrK,aACvBqK,EAAY1K,cACtByK,EAAMxoB,KAAO,YACb0oB,EAAMiB,eAAex5B,KAAKq4B,IAChBC,EAAYxK,UACtBuK,EAAMxoB,KAAO,WACb0oB,EAAMmB,WAAW15B,KAAKq4B,IACZC,EAAYzK,cACtBwK,EAAMxoB,KAAO,WACb0oB,EAAMkB,eAAez5B,KAAKq4B,KAE1BA,EAAMxoB,KAAO,WACb0oB,EAAMoB,YAAY35B,KAAKq4B,SAIzBE,EAAMG,SAAU,EAGjB,GADAH,EAAMkD,KAAO,GACTlD,EAAMG,SAAWH,EAAMc,OAAQ,CAQlC,IAPId,EAAMgB,aAA0C,EAA3BhB,EAAMgB,YAAYj9B,OAC1Ci8B,EAAMkD,MAAQ,sBACJlD,EAAMe,aAA0C,EAA3Bf,EAAMe,YAAYh9B,OACjDi8B,EAAMkD,MAAQ,sBAEdlD,EAAMkD,MAAQ,4BAEVt+B,EAAI,EAAGA,EAAIo7B,EAAMc,OAAO/8B,OAAQa,IAC1B,IAANA,IAASo7B,EAAMkD,MAAQ,KAC3BlD,EAAMkD,MAAOlD,EAAMc,OAAOl8B,GAAG49B,MAE9BxC,EAAMkD,MAAQ,gBACdlD,EAAMkD,MAAQngC,KAAK49B,KAAK/c,kBAAkB1f,OAC1C87B,EAAMkD,MAAQ,IAEf,OAAOlD,GAGR7D,QAAQ72B,UAAU+5B,eAAiB,SAASN,GAC3C,IAAIn6B,EAEJ,GAAK7B,KAAKo6B,wBAAV,CAKA,GAAIp6B,KAAKm6B,4BAAiD,OAAnBn6B,KAAK65B,UAC3C,IAAKh4B,EAAI,EAAGA,EAAI7B,KAAKi6B,iBAAiBj5B,OAAQa,IAG7C,IAFA,IAAIu+B,EAAWpgC,KAAKi6B,iBAAiBp4B,GACrCg5B,EAAOuF,EAASvF,KACTA,EAAKE,WAAaF,EAAK7D,QAAQh2B,QAAUhB,KAAKo6B,yBAAyB,CAG7E16B,IAAIO,MAAM,UAAW,qCAAqCmgC,EAASpgB,GAAI,eAAe6a,EAAKE,YAC3F,IAAIsF,EAASrgC,KAAKsgC,eAAeF,EAASpgB,GAAI6a,EAAKE,WAAYqF,EAASpF,eACxE,IAAIqF,EAKH,MAID,GARCD,EAASpF,cAAgBqF,EACzBxF,EAAKE,cAOFF,EAAKE,WAAaqF,EAASnF,YAAe,GAAMe,GAAQnB,EAAKE,YAAcF,EAAK7D,QAAQh2B,UAC3FtB,IAAIQ,KAAK,UAAW,qCAAqCkgC,EAASpgB,GAAG,iBAAiB1e,KAAKyB,IAAI,EAAE83B,EAAKE,WAAWqF,EAASnF,YAAY,KAAKJ,EAAKE,WAAW,GAAG,KAC9Jr7B,IAAIQ,KAAK,UAAW,+BAA+BF,KAAK88B,8BACpD98B,KAAK65B,WACR75B,KAAK65B,UAAUuG,EAASpgB,GAAIogB,EAAS1F,KAAM0F,EAASpF,cAAc74B,OAAQ04B,EAAKE,WAAaiB,GAAQnB,EAAKE,YAAcF,EAAK7D,QAAQh2B,QAGrIo/B,EAASpF,cAAgB,KACrBoF,IAAapgC,KAAKi6B,iBAAiBp4B,IAEtC,MAOL,GAAuB,OAAnB7B,KAAK85B,UAGR,IAAKj4B,EAAI,EAAGA,EAAI7B,KAAKk6B,gBAAgBl5B,OAAQa,IAAK,CACjD,IAAI0+B,EAAcvgC,KAAKk6B,gBAAgBr4B,GAEvC,IADAg5B,EAAO0F,EAAY1F,KACZA,EAAKE,WAAaF,EAAK7D,QAAQh2B,QAAUhB,KAAKo6B,yBAAyB,CAC7E16B,IAAIO,MAAM,UAAW,uBAAuBsgC,EAAYvgB,GAAI,YAAY6a,EAAKE,YAC7E,IAAIlC,EAAS74B,KAAKwgC,UAAU3F,EAAMA,EAAKE,YACvC,IAAIlC,EAIH,MAED,GALCgC,EAAKE,aACLwF,EAAYvJ,QAAQtyB,KAAKm0B,IAItBgC,EAAKE,WAAawF,EAAYtF,YAAe,GAAKJ,EAAKE,YAAcF,EAAK7D,QAAQh2B,UACrFtB,IAAIO,MAAM,UAAW,6BAA6BsgC,EAAYvgB,GAAG,eAAe6a,EAAKE,YACjF/6B,KAAK85B,WACR95B,KAAK85B,UAAUyG,EAAYvgB,GAAIugB,EAAY7F,KAAM6F,EAAYvJ,SAE9DuJ,EAAYvJ,QAAU,GAClBuJ,IAAgBvgC,KAAKk6B,gBAAgBr4B,IAExC,UASNu3B,QAAQ72B,UAAUk+B,OAAS,SAASlsB,GAC9B8rB,EAASrgC,KAAK0gC,SAASnsB,GAAM,GACjC,OAAQ8rB,EAAOr/B,OAASq/B,EAAO,GAAK,MAGtCjH,QAAQ72B,UAAUm+B,SAAW,SAASnsB,EAAMosB,GAC1C,IAAIN,EAAS,GAEb,OADAjH,QAAQwH,OAAO9uB,KAAK9R,KAAMuU,EAAM8rB,EAAQM,GACjCN,GAGTjH,QAAQwH,OAAS,SAASrsB,EAAM8rB,EAAQM,GAEtC,IAAK,IAAItpB,KADLrX,KAAKuU,MAAQvU,KAAKuU,MAAQA,GAAM8rB,EAAO37B,KAAK1E,MAChCA,KAAKgV,MAAO,CAC1B,GAAIqrB,EAAOr/B,QAAU2/B,EAAa,OAClCvH,QAAQwH,OAAO9uB,KAAK9R,KAAKgV,MAAMqC,GAAM9C,EAAM8rB,EAAQM,KAIvDvH,QAAQ72B,UAAUs+B,oBAAsB,SAASvR,GAC5CyN,EAAQ/8B,KAAK86B,aAAaxL,GAC9B,GAAIyN,EACH,OAAOA,EAAM/F,SAMfoC,QAAQ72B,UAAUu+B,eAAiB,SAASxR,EAAUvuB,GACjDg8B,EAAQ/8B,KAAK86B,aAAaxL,GAE9B,OADatvB,KAAKwgC,UAAUzD,EAAOh8B,IAKpCq4B,QAAQ72B,UAAUw+B,mBAAqB,SAAU/gB,EAAIghB,GACpD,IAAI39B,EAAO,EACPw3B,EAAO76B,KAAK86B,aAAa9a,GACxB6a,EAAKoG,kBAAiBpG,EAAKoG,gBAAkB,GAClD,IAAK,IAAIp/B,EAAIg5B,EAAKoG,gBAAiBp/B,EAAIm/B,EAAWn/B,IACjDwB,GAAMrD,KAAKkhC,cAAcrG,EAAMh5B,GAEhCnC,IAAIQ,KAAK,UAAW,UAAU8f,EAAG,2BAA2BghB,EAAU,oBAAoB39B,EAAK,gBAAgBrD,KAAKmhC,gBAAgB,KACpItG,EAAKoG,gBAAkBD,GAGxB5H,QAAQ72B,UAAU5C,MAAQ,WACzBK,KAAKo6B,yBAA0B,EAC/Bp6B,KAAKs8B,gBAAe,IAGrBlD,QAAQ72B,UAAU6+B,KAAO,WACxBphC,KAAKo6B,yBAA0B,GAIhChB,QAAQ72B,UAAU8+B,MAAQ,WACzB3hC,IAAIQ,KAAK,UAAW,8BACpBF,KAAKo8B,oBACLp8B,KAAKs8B,gBAAe,GACpBt8B,KAAKiR,OAAO3B,eACZtP,KAAKiR,OAAO1C,gBAAe,IAK5B6qB,QAAQ72B,UAAU++B,UAAY,SAASjiB,EAAMkiB,EAAQ1G,GACpD,IAAIjyB,EACAiwB,EACA2I,EAGA3hB,EAFA4hB,EAAsB,EACtBC,EAAkB,EAGtB,GAA4B,IAAxB7G,EAAK7D,QAAQh2B,OAEhB,OADAtB,IAAIQ,KAAK,UAAW,+CAA+CR,IAAIgB,kBAAkB,EAAG,GAAI,kBACzF,CAAE8J,OAAQ,EAAG6U,KAAM,GAG3B,IAAKzW,EAAI,EAAGA,EAAIiyB,EAAK7D,QAAQh2B,OAAQ4H,IAAK,CAEzC,GADAiwB,EAASgC,EAAK7D,QAAQpuB,GACZ,IAANA,EACH84B,EAAkB,EAClB7hB,EAAYgZ,EAAOhZ,eACb,GAAIgZ,EAAO8I,IAAMtiB,EAAOwZ,EAAOhZ,UAAW,CAChD6hB,EAAkB94B,EAAE,EACpB,MAEG24B,GAAU1I,EAAO+I,UACpBH,EAAsB74B,GAQxB,IALI24B,IACHG,EAAkBD,GAEnBpiB,EAAOwb,EAAK7D,QAAQ0K,GAAiBC,IACrC9G,EAAKE,WAAa2G,EACX7G,EAAK7D,QAAQ0K,GAAiBG,cAAgBhH,EAAK7D,QAAQ0K,GAAiBr+B,MAE7Ew3B,EAAK7D,QAAQ0K,EAAkB,IAGpCA,IAID,OAFAF,EAAc3G,EAAK7D,QAAQ0K,GAAiBl3B,OAAOqwB,EAAK7D,QAAQ0K,GAAiBG,YACjFniC,IAAIQ,KAAK,UAAW,eAAeqhC,EAAS,MAAO,IAAI,YAAY1G,EAAKE,WAAW,aAAaF,EAAK8D,KAAKrP,SAAS,UAAU5vB,IAAIgB,kBAAkB2e,EAAMQ,GAAY,gBAAgB2hB,GAC9K,CAAEh3B,OAAQg3B,EAAaniB,KAAMA,EAAKQ,IAI1CuZ,QAAQ72B,UAAUK,KAAO,SAASyc,EAAMkiB,GACvC,IAEIO,EACAjgC,EAHAq6B,EAAOl8B,KAAKk8B,KAIZ6F,EAAY,CAAEv3B,OAAQ4sB,EAAAA,EAAU/X,KAAM+X,EAAAA,GAC1C,GAAKp3B,KAAKk8B,KAEH,CACN,IAAKr6B,EAAI,EAAGA,EAAEq6B,EAAKoC,MAAMt9B,OAAQa,IAChCg5B,EAAOqB,EAAKoC,MAAMz8B,IAClBigC,EAAiB9hC,KAAKshC,UAAUjiB,EAAMkiB,EAAQ1G,IAC3BrwB,OAASu3B,EAAUv3B,SACrCu3B,EAAUv3B,OAASs3B,EAAet3B,QAE/Bs3B,EAAeziB,KAAO0iB,EAAU1iB,OACnC0iB,EAAU1iB,KAAOyiB,EAAeziB,MAclC,OAXA3f,IAAIQ,KAAK,UAAW,mBAAmBR,IAAIgB,kBAAkBqhC,EAAU1iB,KAAM,GAAG,gDAAgD0iB,EAAUv3B,QACtIu3B,EAAUv3B,SAAW4sB,EAAAA,EAExB2K,EAAY,CAAEv3B,OAAQxK,KAAKw8B,kBAAmBnd,KAAM,GAKpD0iB,EAAUv3B,OAASxK,KAAKiR,OAAOX,wBAAwByxB,EAAUv3B,QAElE9K,IAAIQ,KAAK,UAAW,mEAAmE6hC,EAAUv3B,QAC1Fu3B,EAvBP,KAAM,mCA2BR3I,QAAQ72B,UAAUy/B,MAAQ,SAASv9B,GAElC,IADA,IAAIw9B,EAAY,EACTA,EAAYjiC,KAAKgV,MAAMhU,QAAUihC,EAAYx9B,EAAEuQ,MAAMhU,QAAQ,CACnE,IAAIkhC,EAAQliC,KAAKgV,MAAMitB,GACnBE,EAAQ19B,EAAEuQ,MAAMitB,GACpB,IAAKhvB,UAAU2kB,SAASsK,EAAOC,GAC9B,OAAO,EAERF,IAED,OAAO,GAGe,oBAAZlgC,UACVA,QAAQq3B,QAAUA,SAInBA,QAAQ72B,UAAU6/B,qBAAuB,EAEzChJ,QAAQ72B,UAAU8/B,YAAc,KAMhCjJ,QAAQ72B,UAAUi6B,kBAAoB,EAEtCpD,QAAQ72B,UAAU+/B,iBAAkB,EAEpClJ,QAAQ72B,UAAUq5B,qBAAuB,SAASrjB,GACjD,IAAIlB,EAKJ,MAAiB,SAAbkB,EAAIhE,MAKP8C,EAAM,IAAIpE,UAAUsF,EAAIhE,KAAK,OAAOgE,EAAIlV,MACxCrD,KAAKqiC,YAAchrB,EACnBrX,KAAKgV,MAAMtQ,KAAK2S,GAChBrX,KAAKq5B,MAAM30B,KAAK2S,GAChBA,EAAI1X,MAAQ4Y,EAAI5Y,MAChB0X,EAAIpC,SAAWsD,EAAItD,SACnBjV,KAAKiR,OAAOV,aAAa8G,EAAIpC,UAG7BjV,KAAKoiC,qBAAuB/qB,EAAI1X,MAAQ0X,EAAIhU,KAEpCrD,KAAKiR,OAAOrO,KAAKyU,EAAI1X,MAAQ0X,EAAIhU,MAAM,EAAOrD,KAAKsiC,mBAG1DtiC,KAAKqiC,YAAc,OAMdriC,KAAKw5B,eAQTx5B,KAAKw8B,kBAAoBx8B,KAAKiR,OAAOf,uBAJrClQ,KAAKw8B,kBAAoBnlB,EAAI1X,MAAQ0X,EAAIhU,MAOnC,KAIS,SAAbkV,EAAIhE,OAEPvU,KAAKw5B,gBAAiB,EACI,IAAtBx5B,KAAKq5B,MAAMr4B,SACdhB,KAAKu5B,eAAgB,MAObv5B,KAAKiR,OAAO1B,iBAAkBvP,KAAKiR,OAAO1B,mBAKnDvP,KAAKw8B,kBAAoBx8B,KAAKiR,OAAOxO,kBAC9B,KAIF8V,EAAIhE,MAQJvU,KAAKw5B,eALTx5B,KAAKw8B,kBAAoBx8B,KAAKiR,OAAOxO,iBAQpCzC,KAAKw8B,kBAAoBx8B,KAAKiR,OAAOzO,cAAgB+V,EAAIlV,MAGpD,KAKV+1B,QAAQ72B,UAAUk5B,kBAAoB,WACrC,OAA6B,OAArBz7B,KAAKqiC,aAGdjJ,QAAQ72B,UAAUm5B,sBAAwB,WACzC,IAIArkB,EAAMrX,KAAKqiC,YAGX,OADQriC,KAAKiR,OAAOrO,KAAKyU,EAAI1X,MAAQ0X,EAAIhU,MAAM,EAAOrD,KAAKsiC,kBAE1D5iC,IAAIO,MAAM,UAAW,uCAErBD,KAAKqiC,YAAc,QAOnBriC,KAAKw8B,kBAAoBx8B,KAAKiR,OAAOf,wBAC9B,IAITkpB,QAAQ72B,UAAUi5B,qBAAuB,WAExC,OAAOx7B,KAAKiR,OAAOrO,KAAK5C,KAAKoiC,sBAAsB,EAAMpiC,KAAKsiC,kBAG/DlJ,QAAQ72B,UAAUo5B,kBAAoB,WAErC37B,KAAKoiC,qBAAuBpiC,KAAKiR,OAAOzO,eAGzC42B,QAAQ72B,UAAUs5B,gBAAkB,SAASxkB,EAAKkB,GAC7CvY,KAAKiR,OAAOV,eACE,SAAb8G,EAAI9C,MAEPvU,KAAKiR,OAAOV,aAAa8G,EAAIpC,UACzBjV,KAAKsiC,iBACRtiC,KAAKiR,OAAOV,aAAa8G,EAAIhU,KAAKgU,EAAIpC,WAIvCjV,KAAKiR,OAAOV,aAAa8G,EAAIhU,QAKhC+1B,QAAQ72B,UAAU2U,IAAMjE,UAAUiB,IAAI3R,UAAU2U,IAChDkiB,QAAQ72B,UAAU6U,OAASnE,UAAUiB,IAAI3R,UAAU6U,OAEnDgiB,QAAQ72B,UAAUggC,KAAO,SAAUC,GAClC,IAAI7H,EAAU6H,GAAY,GAItBtG,GAHOl8B,KAAKkX,IAAI,QAAQ1Q,IAAI,cAAgBm0B,EAAQgD,QAAUhD,EAAQgD,OAAO,IAAO,QAC9En3B,IAAI,gBAAiB,GACrBA,IAAI,oBAAqBm0B,EAAQgD,QAAU,CAAC,SAC3C39B,KAAKkX,IAAI,SAUpB,OATAglB,EAAKhlB,IAAI,QAAQ1Q,IAAI,YAAam0B,EAAQ9a,WAAa,KAClDrZ,IAAI,OAAQm0B,EAAQxU,MAAQ,GAC5B3f,IAAI,gBAAiB,GACrBA,IAAI,oBAAqB,GACzBA,IAAI,WAAYm0B,EAAQh6B,UAAY,GACpC6F,IAAI,SAAU,GACdA,IAAI,SAAU,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IACxCA,IAAI,gBAAiB,GAC1B01B,EAAKhlB,IAAI,QACFlX,MAGRo5B,QAAQ72B,UAAUkgC,SAAW,SAAUD,GACjCxiC,KAAKk8B,MACTl8B,KAAKuiC,KAAKC,GAGX,IAAI7H,EAAU6H,GAAY,GAC1B7H,EAAQnhB,MAAQmhB,EAAQnhB,OAAS,IACjCmhB,EAAQlhB,OAASkhB,EAAQlhB,QAAU,IACnCkhB,EAAQ3a,GAAK2a,EAAQ3a,IAAMhgB,KAAKk8B,KAAKmB,KAAK/W,cAC1CqU,EAAQpmB,KAAOomB,EAAQpmB,MAAQ,OAE/B,IAAIsmB,EAAO76B,KAAKk8B,KAAKhlB,IAAI,QACzBlX,KAAKk8B,KAAKmB,KAAK/W,cAAgBqU,EAAQ3a,GAAG,EAC1C6a,EAAK3jB,IAAI,QAAQ1Q,IAAI,QAAQyM,UAAUiD,kBAC/BjD,UAAUkD,mBACVlD,UAAUmD,sBACb5P,IAAI,gBAAgB,GACpBA,IAAI,oBAAqB,GACzBA,IAAI,WAAYm0B,EAAQ3a,IACxBxZ,IAAI,WAAYm0B,EAAQh6B,UAAY,GACpC6F,IAAI,QAASm0B,EAAQvK,OAAS,GAC9B5pB,IAAI,kBAAmB,GACvBA,IAAI,SAAU,GACdA,IAAI,SAAU,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IACxCA,IAAI,QAASm0B,EAAQnhB,OACrBhT,IAAI,SAAUm0B,EAAQlhB,QAEvB8kB,EAAO1D,EAAK3jB,IAAI,QACpBqnB,EAAKrnB,IAAI,QAAQ1Q,IAAI,gBAAiB,GACjCA,IAAI,oBAAqB,GACzBA,IAAI,YAAam0B,EAAQ9a,WAAa,GACtCrZ,IAAI,WAAYm0B,EAAQ+H,gBAAkB,GAC1Cl8B,IAAI,WAAYm0B,EAAQjiB,UAAY,GAEzC6lB,EAAKrnB,IAAI,QAAQ1Q,IAAI,UAAWm0B,EAAQiE,MAAQ,QAC3Cp4B,IAAI,OAAQm0B,EAAQxjB,MAAQ,gCAEjConB,EAAKrnB,IAAI,QAAQ1Q,IAAI,oBAAqBm0B,EAAQjiB,UAAY,SAE9D,IAAI8lB,EAAOD,EAAKrnB,IAAI,QACpB,QAA8C3W,IAA1C0S,UAAU0nB,EAAQpmB,KAAK,eAA3B,CACA,IAAIouB,EAA2B,IAAI1vB,UAAU0nB,EAAQpmB,KAAK,eAC1DouB,EAAyBtpB,qBAAuB,EAChD,IACS3D,EADLktB,EAAa,GACjB,IAASltB,KAAazC,UAAUU,iBAE/B,IADA,IAAIkvB,EAAQ5vB,UAAUU,iBAAiB+B,GAC9B7T,EAAI,EAAGA,EAAIghC,EAAM7hC,OAAQa,IACjC,IAAmC,EAA/BghC,EAAMrqB,QAAQmiB,EAAQpmB,MAAY,CACrCquB,EAAaltB,EACb,MAIH,OAAOktB,GACN,IAAK,SACJpE,EAAKtnB,IAAI,QAAQ1Q,IAAI,eAAe,GAAGA,IAAI,UAAW,CAAE,EAAG,EAAG,IAC9Dm8B,EAAyBn8B,IAAI,QAASm0B,EAAQnhB,OAC1ChT,IAAI,SAAUm0B,EAAQlhB,QACtBjT,IAAI,kBAAmB,IAAM,IAC7BA,IAAI,iBAAkB,IAAM,IAC5BA,IAAI,cAAe,GACnBA,IAAI,iBAAkBm0B,EAAQpmB,KAAK,eACnC/N,IAAI,QAAS,IAQjB,MACD,IAAK,QACJg4B,EAAKtnB,IAAI,QAAQ1Q,IAAI,UAAWm0B,EAAQhO,SAAW,GACnDgW,EAAyBn8B,IAAI,gBAAiBm0B,EAAQ5gB,eAAiB,GACnEvT,IAAI,aAAcm0B,EAAQ3gB,YAAc,IACxCxT,IAAI,aAAcm0B,EAAQ1gB,YAAc,OAC5C,MACD,IAAK,OACJukB,EAAKtnB,IAAI,QACT,MACD,IAAK,WACJsnB,EAAKtnB,IAAI,QAEH,SADEyjB,EAAQpmB,MAEdouB,EAAyBn8B,IAAI,YAAam0B,EAAQ5S,WAAa,eAC3DvhB,IAAI,kBAAmBm0B,EAAQ3S,iBAAmB,IAClDxhB,IAAI,uBAAwBm0B,EAAQ1S,sBAAwB,IAGlE,MACD,IAAK,WAGL,IAAK,SAGL,QACCuW,EAAKtnB,IAAI,QAGPyjB,EAAQmI,aACXH,EAAyBvrB,OAAOujB,EAAQmI,aAErCnI,EAAQoI,mBACXpI,EAAQoI,kBAAkBzuB,QAAQ,SAAU7P,GAC3Ck+B,EAAyBvrB,OAAO3S,KAGlC+5B,EAAKtnB,IAAI,QAAQA,IAAI,QAAQK,UAAS,IAAKtE,UAAU,YAAczM,IAAI,QAAS,IAC5Ei4B,EAAOD,EAAKtnB,IAAI,QAgBpB,OAfAunB,EAAKvnB,IAAI,QAAQK,SAASorB,GAC1BlE,EAAKvnB,IAAI,QAAQ1Q,IAAI,gBAAiB,IACjCA,IAAI,gBAAiB,IAC1Bi4B,EAAKvnB,IAAI,QAAQ1Q,IAAI,cAAe,IAC/BA,IAAI,oBAAqB,IACzBA,IAAI,2BAA4B,IACrCi4B,EAAKvnB,IAAI,QAAQ1Q,IAAI,gBAAiB,IACtCi4B,EAAKvnB,IAAI,QAAQ1Q,IAAI,eAAgB,IAErCxG,KAAKk8B,KAAKqB,KAAKrmB,IAAI,QAAQ1Q,IAAI,WAAYm0B,EAAQ3a,IAC1CxZ,IAAI,mCAAoCm0B,EAAQnL,kCAAoC,GACpFhpB,IAAI,0BAA2Bm0B,EAAQlL,yBAA2B,GAClEjpB,IAAI,sBAAuBm0B,EAAQjL,qBAAuB,GAC1DlpB,IAAI,uBAAwBm0B,EAAQhL,sBAAwB,GACrE3vB,KAAKgjC,qBAAqBnI,GACnBF,EAAQ3a,KAGhB/M,UAAUiB,IAAI3R,UAAU0gC,YAAc,SAASC,GAC1CjyB,EAASiyB,GAAW,IAAIz9B,WAC5BwL,EAAOtL,WAAaF,WAAWkB,WAC/B3G,KAAKoY,MAAMnH,IAGZmoB,QAAQ72B,UAAU4gC,UAAY,SAAU7T,EAAU5d,EAAM8wB,GACvD,IAAI7H,EAAU6H,GAAY,GACtB3J,EAAS,GACTgC,EAAO76B,KAAK86B,aAAaxL,GAC7B,GAAa,OAATuL,EAAJ,CACGhC,EAAO93B,OAAS85B,EAAK7D,QAAQh2B,OAChC63B,EAAOvJ,SAAWuL,EAAK8D,KAAKrP,SAC5BuJ,EAAOhZ,UAAYgb,EAAK0D,KAAKc,KAAKxf,UAClCgZ,EAAOxB,kBAAqBsD,EAAQpN,yBAA2BoN,EAAQpN,yBAA2B,EAAG,EACrGsL,EAAOiK,YAAcjI,EAAK0D,KAAKC,KAAKC,KAAKC,KAAKpf,QAAQuZ,EAAOxB,mBAC7DwB,EAAOnnB,KAAOA,EACdmnB,EAAOx1B,KAAOqO,EAAK1Q,OACnB63B,EAAOgJ,YAAchJ,EAAOx1B,KAC5Bw1B,EAAOl4B,SAAWg6B,EAAQh6B,UAAY,EACtCk4B,EAAO8I,IAAMhH,EAAQgH,KAAO,EAC5B9I,EAAO3B,IAAMyD,EAAQzD,KAAO,EAC5B2B,EAAO+I,QAAUjH,EAAQiH,UAAW,EACpC/I,EAAO9N,WAAa4P,EAAQ5P,YAAc,EAC1C8N,EAAOuK,WAAazI,EAAQyI,YAAc,EAC1CvK,EAAOwK,eAAiB1I,EAAQ0I,gBAAkB,EAClDxK,EAAOyK,eAAiB3I,EAAQ2I,gBAAkB,EAClDzK,EAAO0K,qBAAuB5I,EAAQ4I,sBAAwB,EAC9D1K,EAAOruB,OAAS,EAChBquB,EAAOpK,WAAakM,EAAQlM,WAC5BoM,EAAK7D,QAAQtyB,KAAKm0B,GAClBgC,EAAKiF,cAAgBjH,EAAOx1B,KAC5Bw3B,EAAK2E,kBAAoB3G,EAAOl4B,SAEhCX,KAAKs8B,iBAEDkH,EAAOxjC,KAAKyjC,uBAAuB5K,GAMvC,OALA74B,KAAKoX,OAAOosB,GACZA,EAAKP,cAELO,EAAKE,MAAM,GAAGC,MAAM,GAAGlT,YAAc+S,EAAKngC,KAAK,EAC/CrD,KAAKkX,IAAI,QAAQxF,KAAOA,EACjBmnB,IAGRO,QAAQ72B,UAAUkhC,uBAAyB,SAAS5K,GACnD,IAAIjI,EAAe,EAElBA,EADGiI,EAAO+I,QACM,GAAK,GAEN,MAEZ4B,EAAO,IAAIvwB,UAAU2wB,QACzBJ,EAAKtsB,IAAI,QAAQ1Q,IAAI,kBAAmBxG,KAAKq6B,gBAC7Cr6B,KAAKq6B,iBACL,IAAIwJ,EAAOL,EAAKtsB,IAAI,QAcpB,OAbA2sB,EAAK3sB,IAAI,QAAQ1Q,IAAI,WAAYqyB,EAAOvJ,UACnC9oB,IAAI,QAASyM,UAAU0D,gCAC5BktB,EAAK3sB,IAAI,QAAQ1Q,IAAI,sBAAuBqyB,EAAO3B,KACnD2M,EAAK3sB,IAAI,QAAQ1Q,IAAI,QAASyM,UAAU2D,uBAAyB3D,UAAU6D,oBACjE7D,UAAU8D,gBAAkB9D,UAAU+D,iBACtC/D,UAAUgE,uBACfzQ,IAAI,cAAc,GAClBA,IAAI,qBAAqB,GACzBA,IAAI,eAAe,GACnBA,IAAI,kBAAkB,CAACqyB,EAAOl4B,WAC9B6F,IAAI,cAAc,CAACqyB,EAAOx1B,OAC1BmD,IAAI,eAAe,CAACoqB,IACpBpqB,IAAI,iCAAkC,CAACqyB,EAAO8I,IAAM9I,EAAO3B,MACzDsM,GAKRpK,QAAQ72B,UAAUuhC,cAAgB,EAGlC1K,QAAQ72B,UAAU4+B,gBAAkB,EAGpC/H,QAAQ72B,UAAUwhC,YAAc,WAC/B,IAAIliC,EACAg5B,EAGJ,IAFA76B,KAAKgkC,iBAAmBhkC,KAAKk8B,KAAKmB,KAAK18B,SAElCkB,EADL7B,KAAKk8B,KAAKmB,KAAK18B,SAAW,EACdkB,EAAI7B,KAAKk8B,KAAKoC,MAAMt9B,OAAQa,IAAK,EAC5Cg5B,EAAO76B,KAAKk8B,KAAKoC,MAAMz8B,IAClB88B,KAAKh+B,SAAW,EACrBk6B,EAAK0D,KAAKc,KAAK1+B,SAAW,GACnBk6B,EAAK0D,KAAKC,KAAKC,KAAKwF,MAAQpJ,EAAK0D,KAAKC,KAAKC,KAAKyF,MAClDnnB,cAAgB,IACrBonB,EAAOtJ,EAAK0D,KAAKC,KAAKC,KAAK0F,MACtB9W,YAAc,GACnB8W,EAAK7W,kBAAoB,GACzB6W,EAAK5W,yBAA2B,IACzBsN,EAAK0D,KAAKC,KAAKC,KAAK2F,MAAQvJ,EAAK0D,KAAKC,KAAKC,KAAK4F,MAClDzW,aAAe,IACpB0W,EAAOzJ,EAAK0D,KAAKC,KAAKC,KAAK6F,MACtBxmB,cAAgB,GACrBwmB,EAAKvW,cAAgB,IACrBwW,EAAO1J,EAAK0D,KAAKC,KAAKC,KAAK8F,QAE1BA,EAAKzmB,cAAgB,GACrBymB,EAAKxmB,eAAiB,IAEvBymB,EAAO3J,EAAK0D,KAAKC,KAAKC,KAAK+F,KAC3B,IAAI37B,EAAIgyB,EAAK0D,KAAKC,KAAKC,KAAKzpB,MAAMwD,QAAQgsB,IAChC,GAAN37B,IAASgyB,EAAK0D,KAAKC,KAAKC,KAAKzpB,MAAMnM,GAAK,QAI9CuwB,QAAQqL,iBAAmB,SAAS5J,EAAMgJ,EAAMa,EAAOC,EAAYC,GAClE,IAAI7yB,EACAlJ,EAEAg8B,EACAC,EACJ,SAASC,EAAgBnwB,EAAOowB,EAAYC,GAC3CjlC,KAAKmV,cAAgBP,EACrB5U,KAAKolB,wBAA0B4f,EAC/BhlC,KAAKklC,KAAOD,EACZjlC,KAAKmlC,oBAAsB,EAC3BnlC,KAAKolC,aAAe,EAQrB,IANIvB,IACHA,EAAKwB,mBAAqB,IAEtBxK,EAAKwK,qBACTxK,EAAKwK,mBAAqB,IAEtBx8B,EAAI,EAAGA,EAAI67B,EAAM1jC,OAAQ6H,IAAK,CASlC,IARAi8B,EAAmBJ,EAAM77B,GAAGsM,cAAe,IAAKuvB,EAAM77B,GAAGuc,wBACzDyf,EAAoB,IAAIE,EAAgBL,EAAM77B,GAAGsM,cAAeuvB,EAAM77B,GAAGuc,wBAAyBsf,EAAM77B,IACpGg7B,IACHA,EAAKwB,mBAAmBP,GAAoBD,GAExChK,EAAKwK,mBAAmBP,KAC5BjK,EAAKwK,mBAAmBP,GAAoBD,GAExC9yB,EAAE,EAAGA,EAAG4yB,EAAW3jC,OAAQ+Q,IAC3B4yB,EAAW5yB,GAAGoD,gBAAkBuvB,EAAM77B,GAAGsM,gBAC5C0vB,EAAkB/B,YAAc6B,EAAW5yB,GAC3C8yB,EAAkB/B,YAAY1zB,MAAO,GAGvC,GAAIw1B,EACH,IAAK7yB,EAAE,EAAGA,EAAG6yB,EAAW5jC,OAAQ+Q,IAC3B6yB,EAAW7yB,GAAGoD,gBAAkBuvB,EAAM77B,GAAGsM,gBAC5C0vB,EAAkBS,qBAAuBV,EAAW7yB,GACpD8yB,EAAkBS,qBAAqBl2B,MAAO,EAC9Cy1B,EAAkBU,aAAc,GAKpC,GAAK1B,GAWJ,GAAIe,EACH,IAAK/7B,EAAI,EAAGA,EAAI+7B,EAAW5jC,OAAQ6H,KAC7B+7B,EAAW/7B,GAAGuG,MAAiC,GAAzBw1B,EAAW/7B,GAAGkM,UACxC+vB,EAAmBF,EAAW/7B,GAAGsM,cAAe,MAChD0vB,EAAoB,IAAIE,EAAgBH,EAAW/7B,GAAGsM,cAAe,IACnDowB,aAAc,EAC3B1B,EAAKwB,mBAAmBP,KAC5BjB,EAAKwB,mBAAmBP,GAAoBD,SAjBhD,IAAKh8B,EAAI,EAAGA,EAAI87B,EAAW3jC,OAAQ6H,KAC7B87B,EAAW97B,GAAGuG,MAAiC,GAAzBu1B,EAAW97B,GAAGkM,UACxC+vB,EAAmBH,EAAW97B,GAAGsM,cAAe,KAChD0vB,EAAoB,IAAIE,EAAgBJ,EAAW97B,GAAGsM,cAAe,GAChE0lB,EAAKwK,mBAAmBP,KAC5BjK,EAAKwK,mBAAmBP,GAAoBD,KAoBjDzL,QAAQoM,yBAA2B,SAAS3K,EAAMhC,EAAQ1I,EAAekV,GACxE,IAAIx8B,EACAoH,EAuBD6yB,EArBH,IAAKj6B,KADLgwB,EAAO4M,cAAgB,GACbJ,EACTxM,EAAO4M,cAAc58B,GAAK,GAC1BgwB,EAAO4M,cAAc58B,GAAGsM,cAAgBkwB,EAAmBx8B,GAAGsM,cAC9D0jB,EAAO4M,cAAc58B,GAAGuc,wBAA0BigB,EAAmBx8B,GAAGuc,wBACpE+K,GAAiBkV,EAAmBx8B,GAAGs8B,qBACtCE,EAAmBx8B,GAAGs8B,mBAAqB,IAC9CE,EAAmBx8B,GAAGs8B,mBAAqB,GAE5CE,EAAmBx8B,GAAGu8B,cAClBC,EAAmBx8B,GAAGu8B,aAAeC,EAAmBx8B,GAAGq8B,KAAK5lB,QAAQte,OAAS,IACpFqkC,EAAmBx8B,GAAGs8B,oBAAsBE,EAAmBx8B,GAAGq8B,KAAK5lB,QAAQ+lB,EAAmBx8B,GAAGu8B,aAAa5e,eAGhH6e,EAAmBx8B,GAAGu8B,aAAeC,EAAmBx8B,GAAGq8B,KAAK5lB,QAAQte,OAAS,EACpF63B,EAAO4M,cAAc58B,GAAG8hB,wBAA0B0a,EAAmBx8B,GAAGq8B,KAAK5lB,QAAQ+lB,EAAmBx8B,GAAGu8B,aAAaza,wBAExHkO,EAAO4M,cAAc58B,GAAG8hB,yBAA2B,EAEI,IAApDkO,EAAO4M,cAAc58B,GAAG8hB,0BAG1BmY,EADGuC,EAAmBx8B,GAAGy8B,sBAGXD,EAAmBx8B,GAAGi6B,YAEiB,EAAlDjK,EAAO4M,cAAc58B,GAAG8hB,yBAE1B1a,EADqD,MAAlD4oB,EAAO4M,cAAc58B,GAAG8hB,yBAClBkO,EAAO4M,cAAc58B,GAAG8hB,yBAA2B,IAAI,EAExDkO,EAAO4M,cAAc58B,GAAG8hB,wBAAwB,EAErDmY,GAAwB,GAAT7yB,IAClB4oB,EAAO4M,cAAc58B,GAAGi6B,YAAcA,EAAYxjB,QAAQrP,KAGvD6yB,GAAsC,GAAvBA,EAAY/tB,SACoB,EAA9C+tB,EAAY1X,kCACfyN,EAAO4M,cAAc58B,GAAGi6B,YAAcA,EAAYxjB,QAAQwjB,EAAY1X,gCAAgC,MAQ5GgO,QAAQsM,aAAe,SAAUC,EAAM9M,EAAQ93B,GACzC83B,IAGD8M,GACH9M,EAAO9N,WAAa4a,EAAK5a,WAAWhqB,GACpC83B,EAAOuK,WAAauC,EAAK3a,kBAAkBjqB,GAC3C83B,EAAOwK,eAAiBsC,EAAK1a,sBAAsBlqB,GACnD83B,EAAOyK,eAAiBqC,EAAKza,sBAAsBnqB,KAEnD83B,EAAO9N,WAAa,EACpB8N,EAAOuK,WAAa,EACpBvK,EAAOwK,eAAiB,EACxBxK,EAAOyK,eAAiB,KAK1BlK,QAAQ72B,UAAU45B,iBAAmB,WAGpC,IAFA,IACItB,EACCh5B,EAAI,EAAGA,EAAI7B,KAAKk8B,KAAKoC,MAAMt9B,OAAQa,IACvCg5B,EAAO76B,KAAKk8B,KAAKoC,MAAMz8B,GACvB7B,KAAKgjC,qBAAqBnI,IAI5BzB,QAAQ72B,UAAUygC,qBAAuB,SAASnI,GACjD,IAAIjyB,EACAq7B,EAAME,EAAMC,EAAME,EAAMC,EAAMC,EAAM9F,EAAMkH,EAAMlB,EAAOmB,EAAOC,EAC9DC,EAAiBzO,EAAa0O,EAAmBC,EAAiBC,EAClEC,EAAyBC,EAAgBC,EAAyBC,EAAgBC,EAAkCC,EAAkBC,EA2B1I,GAzBA5L,EAAK7D,QAAU,GACf6D,EAAK2E,iBAAmB,EACxB3E,EAAKiF,aAAe,EACpBmE,EAAOpJ,EAAK0D,KAAKC,KAAKC,KAAKwF,MAAQpJ,EAAK0D,KAAKC,KAAKC,KAAKyF,KACvDC,EAAOtJ,EAAK0D,KAAKC,KAAKC,KAAK0F,KAC3BC,EAAOvJ,EAAK0D,KAAKC,KAAKC,KAAK2F,MAAQvJ,EAAK0D,KAAKC,KAAKC,KAAK4F,KACvDC,EAAOzJ,EAAK0D,KAAKC,KAAKC,KAAK6F,KAC3BC,EAAO1J,EAAK0D,KAAKC,KAAKC,KAAK8F,KAC3BC,EAAO3J,EAAK0D,KAAKC,KAAKC,KAAK+F,KAC3B9F,EAAO7D,EAAK0D,KAAKC,KAAKC,KAAKC,KAC3BkH,EAAO/K,EAAK0D,KAAKC,KAAKC,KAAKmH,KAC3BE,EAAOjL,EAAK0D,KAAKC,KAAKC,KAAKqH,KAC3BpB,EAAQ7J,EAAK0D,KAAKC,KAAKC,KAAKiG,MAC5BmB,EAAQhL,EAAK0D,KAAKC,KAAKC,KAAKoH,MAK5BS,EADAD,EADAD,EADAD,GAA2B,EAM3BM,EADAD,EADAD,EAAkB,EAIlBnN,QAAQqL,iBAAiB5J,EAAM,KAAM6J,EAAOmB,QAExB,IAATzB,EAAX,CAKA,IAAKx7B,EAAI,EAAGA,EAAIw7B,EAAKxW,aAAa5sB,OAAQ4H,IAAK,CAC9C,IAAIiwB,EAAS,GACbA,EAAO93B,OAAS6H,EAChBiwB,EAAOvJ,SAAWuL,EAAK8D,KAAKrP,SAC5BuJ,EAAOhZ,UAAYgb,EAAK0D,KAAKc,KAAKxf,UAClCgZ,EAAOgJ,YAAc,GACrBhH,EAAK7D,QAAQpuB,GAAKiwB,GAEXx1B,KAAO+gC,EAAKxW,aAAahlB,GAChCiyB,EAAKiF,cAAgBjH,EAAOx1B,KAElB,IAANuF,GACH0uB,EAAc,EACdyO,EAAkB,EAClBlN,EAAOvB,YAAcA,EACrBuB,EAAOkN,gBAAkBA,EACzBG,EAAuB/B,EAAK7W,kBAAkByY,GAC9CE,EAAkB,EAKjBD,EAFGD,EAAkB,EAAI5B,EAAK9W,YAAYrsB,OAEtBmjC,EAAK9W,YAAY0Y,EAAgB,GAAG,EAGpC3O,EAAAA,GAGjBxuB,EAAIs9B,GAEPrN,EAAOvB,YAAcA,EACrBuB,EAAOkN,gBAAkBA,IAGzBzO,IAGA2O,EAAkB,GAFlBpN,EAAOvB,YAAcA,IAGF0O,IAQjBA,IAJDD,EAEsB,EAAI5B,EAAK9W,YAAYrsB,OAEtBmjC,EAAK9W,YAAY0Y,EAAgB,GAAG,EAGpC3O,EAAAA,GAItByB,EAAOkN,gBAAkBA,EACzBG,GAAwB/B,EAAK7W,kBAAkByY,IAIjDlN,EAAOxB,kBAAoB8M,EAAK5W,yBAAyBsL,EAAOkN,iBAAiB,EACjFlN,EAAOiK,YAAcpE,EAAKpf,QAAQuZ,EAAOxB,mBACzCwB,EAAOruB,OAASy5B,EAAKlnB,cAAc8b,EAAOvB,YAAY,GAAK2O,EAC3DA,GAAmBpN,EAAOx1B,KAGlB8iC,EAAJv9B,IACHw9B,IACID,EAA0B,IAC7BA,EAA0B,GAE3BA,GAA2B7B,EAAKxmB,cAAcsoB,IAEvC,EAAJx9B,GACHiyB,EAAK7D,QAAQpuB,EAAE,GAAGjI,SAAW2jC,EAAKvW,cAAcqY,GAChDvL,EAAK2E,kBAAoB3E,EAAK7D,QAAQpuB,EAAE,GAAGjI,SAC3Ck4B,EAAO3B,IAAM2D,EAAK7D,QAAQpuB,EAAE,GAAGsuB,IAAM2D,EAAK7D,QAAQpuB,EAAE,GAAGjI,UAEvDk4B,EAAO3B,IAAM,EAEVqN,GACM8B,GAALz9B,IACH09B,IACID,EAA0B,IAC7BA,EAA0B,GAE3BA,GAA2B9B,EAAKzmB,cAAcwoB,IAE/CzN,EAAO8I,IAAM9G,EAAK7D,QAAQpuB,GAAGsuB,IAAMqN,EAAKxmB,eAAeuoB,IAEvDzN,EAAO8I,IAAM9I,EAAO3B,IAEjBsN,GACC57B,GAAK47B,EAAK7W,eAAe4Y,GAAmB,GAC/C1N,EAAO+I,SAAU,EACjB2E,MAEA1N,EAAO+I,SAAU,EACjB/I,EAAO0K,qBAAuB,GAE3BqC,GACCA,EAAKtmB,QAAQknB,GAAkBhY,aAAeiY,GAA0B79B,EAAE,IAC7EiwB,EAAOpK,WAAamX,EAAKtmB,QAAQknB,GAAkB/X,WACnDgY,GAA0Bb,EAAKtmB,QAAQknB,GAAkBhY,aACzDgY,MAIF3N,EAAO+I,SAAU,EAElBxI,QAAQsM,aAAa7K,EAAK0D,KAAKC,KAAKC,KAAKkH,KAAM9M,EAAQA,EAAO93B,QAE7D83B,EAAO0K,qBADJuC,EAC2BA,EAAK7Y,SAASrkB,GAEd,EAE3Bg9B,GACCA,EAAKtmB,QAAQknB,GAAkBhY,aAAeiY,GAA0B79B,IAC3EiwB,EAAOpK,WAAamX,EAAKtmB,QAAQknB,GAAkB/X,WACnDgY,GAA0Bb,EAAKtmB,QAAQknB,GAAkBhY,eAGxC,EAAfkW,EAAM1jC,QAA6B,EAAf6kC,EAAM7kC,SAC7Bo4B,QAAQoM,yBAAyB3K,EAAMhC,EAAQjwB,EAAGiyB,EAAKwK,oBAGnD,EAAFz8B,IACHiyB,EAAK7D,QAAQpuB,EAAE,GAAGjI,SAAWW,KAAKyB,IAAI83B,EAAK0D,KAAKc,KAAK1+B,SAAWk6B,EAAK7D,QAAQpuB,EAAE,GAAGsuB,IAAK,GACvF2D,EAAK2E,kBAAoB3E,EAAK7D,QAAQpuB,EAAE,GAAGjI,YAK7Cy4B,QAAQ72B,UAAU65B,kBAAoB,WACrC,IAAIv6B,EACA2tB,EAAkCC,EAAyBC,EAAqBC,EAChF+W,EACArvB,EAAKmsB,EAAMK,EAAMhJ,EAAM8L,EACvB9N,EAGJ,QAAkBt4B,IAAdP,KAAKk8B,KAIT,KAAOl8B,KAAK8jC,cAAgB9jC,KAAKs5B,MAAMt4B,QAGtC,GAFAqW,EAAMrX,KAAKs5B,MAAMt5B,KAAK8jC,eACtB9jC,KAAK8jC,gBACW,QAAZzsB,EAAI9C,KAEP,IADAivB,EAAOnsB,EACFxV,EAAI,EAAGA,EAAI2hC,EAAKE,MAAM1iC,OAAQa,IAAK,CA6BvC,IA5BAgiC,EAAOL,EAAKE,MAAM7hC,GAClBg5B,EAAO76B,KAAK86B,aAAa+I,EAAK+C,KAAKtX,UACnCqX,EAAO3mC,KAAK6mC,YAAYhD,EAAK+C,KAAKtX,UAEjCE,EADGqU,EAAK+C,KAAK30B,MAAQgB,UAAUqD,sBACIutB,EAAK+C,KAAKpX,iCAETmX,EAAOA,EAAKnX,iCAAkC,EAGlFC,EADGoU,EAAK+C,KAAK30B,MAAQgB,UAAUsD,qBACLstB,EAAK+C,KAAKnX,wBAETkX,EAAOA,EAAKlX,wBAA0B,EAGjEC,EADGmU,EAAK+C,KAAK30B,MAAQgB,UAAUuD,sBACTqtB,EAAK+C,KAAKlX,oBAETiX,EAAOA,EAAKjX,oBAAsB,EAGzDC,EADGkU,EAAK+C,KAAK30B,MAAQgB,UAAUwD,uBACRotB,EAAK+C,KAAKjX,qBAETgX,EAAOA,EAAKhX,qBAAuB,GAE5DkU,EAAK1T,cAAgB,GAEjB0T,EAAKa,MAAM1jC,QACdo4B,QAAQqL,iBAAiB5J,EAAMgJ,EAAMA,EAAKa,MAAO7J,EAAK0D,KAAKC,KAAKC,KAAKoH,MAAOhC,EAAKgC,OAE7Ej9B,EAAI,EAAGA,EAAIi7B,EAAKF,MAAM3iC,OAAQ4H,IAElC,IADA,IAAIk+B,EAAOjD,EAAKF,MAAM/6B,GACjBC,EAAI,EAAGA,EAAIi+B,EAAKtgB,aAAc3d,IAAK,EACvCgwB,EAAS,IACFkO,YAAc/mC,KAAK8jC,cAC1BjL,EAAOmO,eAAiBnD,EAAK1T,cAC7B0T,EAAK1T,gBACI0I,EAAO93B,OAAS85B,EAAK7D,QAAQh2B,OACtC6iC,EAAKoD,mBAAqBpM,EAAK7D,QAAQh2B,OACvC65B,EAAK7D,QAAQtyB,KAAKm0B,GAClBA,EAAOvJ,SAAWuL,EAAK8D,KAAKrP,SAC5BuJ,EAAOhZ,UAAYgb,EAAK0D,KAAKc,KAAKxf,UAClCgZ,EAAOxB,kBAAoB7H,EAAiC,EAC5DqJ,EAAOiK,YAAcjI,EAAK0D,KAAKC,KAAKC,KAAKC,KAAKpf,QAAQuZ,EAAOxB,mBAC7DwB,EAAOx1B,KAAOqsB,EACVoX,EAAK70B,MAAQgB,UAAU8D,kBAC1B8hB,EAAOx1B,KAAOyjC,EAAKjZ,YAAYhlB,IAEhCgyB,EAAKiF,cAAgBjH,EAAOx1B,KAC5Bw1B,EAAOl4B,SAAW8uB,EACdqX,EAAK70B,MAAQgB,UAAU6D,sBAC1B+hB,EAAOl4B,SAAWmmC,EAAKnW,gBAAgB9nB,IAExCgyB,EAAK2E,kBAAoB3G,EAAOl4B,SAC5Bk6B,EAAKqM,mBAAyB,EAAJr+B,EAC7BgwB,EAAO3B,IAAM2D,EAAK7D,QAAQ6D,EAAK7D,QAAQh2B,OAAO,GAAGk2B,IAAI2D,EAAK7D,QAAQ6D,EAAK7D,QAAQh2B,OAAO,GAAGL,UAErFkjC,EAAKsD,KACRtO,EAAO3B,IAAM2M,EAAKsD,KAAK/X,oBAEvByJ,EAAO3B,IAAM,EAEd2D,EAAKqM,mBAAoB,GAE1BrO,EAAO8I,IAAM9I,EAAO3B,IAChB4P,EAAK70B,MAAQgB,UAAUgE,wBAC1B4hB,EAAO8I,IAAM9I,EAAO3B,IAAM4P,EAAKjW,+BAA+BhoB,IAE/D+nB,EAAejB,EACXmX,EAAK70B,MAAQgB,UAAU+D,iBAC1B4Z,EAAekW,EAAKlW,aAAa/nB,GACjB,IAANA,GAAYi+B,EAAK70B,MAAQgB,UAAU4D,wBAC7C+Z,EAAekW,EAAKpW,oBAErBmI,EAAO+I,UAAYhR,GAAgB,GAAK,GACxCiI,EAAO9N,WAAc6F,GAAgB,GAAK,EAC1CiI,EAAOuK,WAAcxS,GAAgB,GAAK,EAC1CiI,EAAOwK,eAAkBzS,GAAgB,GAAK,EAC9CiI,EAAOyK,eAAkB1S,GAAgB,GAAK,EAC9CiI,EAAO0K,qBAAuC,MAAf3S,EAE/B,IAAIwW,KAAQvD,EAAK+C,KAAK30B,MAAQgB,UAAUoD,4BACpCgxB,KAAQxD,EAAK+C,KAAK30B,MAAQgB,UAAU0D,gCACpC2wB,KAAOR,EAAK70B,MAAQgB,UAAU2D,wBAC9B2wB,EAAM,EAYTA,EAXIH,EAWEvD,EAAK+C,KAAKrX,iBAVX8X,GACM,IAANz+B,EAME46B,EAAK7jC,MAHJ+mC,EAUP7N,EAAOruB,OAFC,IAAN5B,GAAiB,IAANC,EACVy+B,EACaC,EAAMT,EAAKrW,YAEX8W,EAGDb,EAEjBA,EAAoB7N,EAAOruB,OAASquB,EAAOx1B,MACnB,EAApBwgC,EAAKa,MAAM1jC,QAAkC,EAApB6iC,EAAKgC,MAAM7kC,QACJ,EAAnC65B,EAAK0D,KAAKC,KAAKC,KAAKiG,MAAM1jC,QAAiD,EAAnC65B,EAAK0D,KAAKC,KAAKC,KAAKoH,MAAM7kC,SAClEo4B,QAAQoM,yBAAyB3K,EAAMhC,EAAQA,EAAOmO,eAAgBnD,EAAKwB,oBAI9E,GAAIxB,EAAK+B,KAAM,CACd/K,EAAK2M,yBAA0B,EAE/B,IADA,IAAIC,EAAe5D,EAAKoD,mBACnBr+B,EAAI,EAAGA,EAAIi7B,EAAK+B,KAAKtmB,QAAQte,OAAQ4H,IACzC6+B,GAAgB5D,EAAK+B,KAAKtmB,QAAQ1W,GAAG4lB,cACrCqK,EAASgC,EAAK7D,QAAQyQ,EAAa,IAC5BhZ,WAAaoV,EAAK+B,KAAKtmB,QAAQ1W,GAAG6lB,cAY/C2K,QAAQ72B,UAAUi+B,UAAY,SAAS3F,EAAMmG,GAC5C,IAAI7+B,EACA02B,EAASgC,EAAK7D,QAAQgK,GAE1B,IAAKhhC,KAAKk8B,KACT,OAAO,KAGR,GAAKrD,EAAOnnB,MAML,GAAImnB,EAAOgJ,aAAehJ,EAAOx1B,KAEvC,OAAOw1B,OANPA,EAAOnnB,KAAO,IAAIzM,WAAW4zB,EAAOx1B,MACpCw1B,EAAOgJ,YAAc,EACrB7hC,KAAKmhC,iBAAmBtI,EAAOx1B,KAC/B3D,IAAIO,MAAM,UAAW,sBAAsB+gC,EAAU,cAAcnG,EAAK8D,KAAKrP,SAAS,YAAYuJ,EAAOx1B,KAAK,YAAYrD,KAAKmhC,gBAAgB,KAOhJ,OAAY,CACX,IAAIlxB,EAAQjQ,KAAKiR,OAAOrB,cAAa,EAAMipB,EAAOruB,OAASquB,EAAOgJ,aAAa,GAC/E,MAAa,EAAT5xB,GAsCH,OAAO,KApCHy3B,GADJvlC,EAASnC,KAAKiR,OAAOhD,QAAQgC,IACCvN,YAAcm2B,EAAOruB,OAASquB,EAAOgJ,YAAc1/B,EAAOmM,WACxF,GAAIuqB,EAAOx1B,KAAOw1B,EAAOgJ,aAAe6F,EAevC,OAZAhoC,IAAIO,MAAM,UAAU,mBAAmB+gC,EAAU,uBAAuBnI,EAAOgJ,YAAY,aACzFhJ,EAAOruB,OAAOquB,EAAOgJ,YAAc1/B,EAAOmM,WAAW,gBAAgBuqB,EAAOx1B,KAAOw1B,EAAOgJ,aAAa,eAAehJ,EAAOx1B,KAAK,KAEpIoC,WAAW2B,OAAOyxB,EAAOnnB,KAAKvP,OAAQ02B,EAAOgJ,YAC3B1/B,EAAQ02B,EAAOruB,OAAOquB,EAAOgJ,YAAc1/B,EAAOmM,UAAWuqB,EAAOx1B,KAAOw1B,EAAOgJ,aAGpG1/B,EAAO2M,WAAa+pB,EAAOx1B,KAAOw1B,EAAOgJ,YACzC7hC,KAAKiR,OAAO1C,iBAEZsqB,EAAOgJ,YAAchJ,EAAOx1B,KAErBw1B,EAIP,GAAyB,GAArB6O,EAAwB,OAAO,KAEnChoC,IAAIO,MAAM,UAAU,mBAAmB+gC,EAAU,+BAA+BnI,EAAOgJ,YAAY,aACjGhJ,EAAOruB,OAAOquB,EAAOgJ,YAAc1/B,EAAOmM,WAAW,eAAeo5B,EAAiB,eAAe7O,EAAOx1B,KAAK,KAElHoC,WAAW2B,OAAOyxB,EAAOnnB,KAAKvP,OAAQ02B,EAAOgJ,YAC3B1/B,EAAQ02B,EAAOruB,OAAOquB,EAAOgJ,YAAc1/B,EAAOmM,UAAWo5B,GAC/E7O,EAAOgJ,aAAe6F,EAGtBvlC,EAAO2M,WAAa44B,EACpB1nC,KAAKiR,OAAO1C,mBAWhB6qB,QAAQ72B,UAAU2+B,cAAgB,SAASrG,EAAMmG,GAC5CnI,EAASgC,EAAK7D,QAAQgK,GAC1B,OAAInI,EAAOnnB,MACV1R,KAAKmhC,iBAAmBtI,EAAOx1B,KAC/Bw1B,EAAOnnB,KAAO,KACdmnB,EAAOgJ,YAAc,EACdhJ,EAAOx1B,MAEP,GAIT+1B,QAAQ72B,UAAUu6B,2BAA6B,WAC9C,OAAO98B,KAAKmhC,iBAIb/H,QAAQ72B,UAAUolC,UAAY,WAG7B,IAFA,IACIC,EAAS,GACR/lC,EAAI,EAAGA,EAAI7B,KAAKk8B,KAAKoC,MAAMt9B,OAAQa,IAEjC,EAAFA,IACH+lC,GAAQ,KAETA,GAJW5nC,KAAKk8B,KAAKoC,MAAMz8B,GAIZ08B,KAAKC,KAAKC,KAAKC,KAAKpf,QAAQ,GAAGmT,WAE/C,OAAOmV,GAIRxO,QAAQ72B,UAAUskC,YAAc,SAAS7mB,GACxC,IAAIne,EACJ,IAAK7B,KAAKk8B,OAASl8B,KAAKk8B,KAAKqB,KAAM,OAAO,KAC1C,IAAK17B,EAAI,EAAGA,EAAI7B,KAAKk8B,KAAKqB,KAAKsK,MAAM7mC,OAAQa,IAAK,CACjD,IAAI8kC,EAAO3mC,KAAKk8B,KAAKqB,KAAKsK,MAAMhmC,GAChC,GAAI8kC,EAAKrX,UAAYtP,EAAI,OAAO2mB,EAEjC,OAAO,MAIRvN,QAAQ72B,UAAUu4B,aAAe,SAAS9a,GACzC,QAAkBzf,IAAdP,KAAKk8B,KACR,OAAO,KAER,IAAK,IAAItzB,EAAI,EAAGA,EAAI5I,KAAKk8B,KAAKoC,MAAMt9B,OAAQ4H,IAAK,CAChD,IAAIiyB,EAAO76B,KAAKk8B,KAAKoC,MAAM11B,GAC3B,GAAIiyB,EAAK8D,KAAKrP,UAAYtP,EAAI,OAAO6a,EAEtC,OAAO,MAGRzB,QAAQ72B,UAAUqgB,MAAQ,GAE1BwW,QAAQ72B,UAAUulC,cAAgB,EAElC1O,QAAQ72B,UAAUo6B,gBAAkB,WACnC,IAAI/Z,EAAQ5iB,KAAK4iB,MAGb8Z,EAAO18B,KAAK08B,KAChB,GAAIA,MAAAA,QACcn8B,IAAdm8B,EAAKkC,WACSr+B,IAAdm8B,EAAKqL,KAAT,CACA,IAAKlmC,EAAI,EAAGA,EAAI66B,EAAKqL,KAAKzlB,WAAWthB,OAAQa,KAC5CihB,EAAO,IACF9C,GAAK0c,EAAKqL,KAAKzlB,WAAWzgB,GAAGkhB,SAClCH,EAAME,EAAK9C,IAAM8C,GACZklB,OAAS,GACdllB,EAAK3L,KAAOulB,EAAKqL,KAAKzlB,WAAWzgB,GAAG8hB,UACW,EAA3C+Y,EAAKqL,KAAKzlB,WAAWzgB,GAAGomC,mBAC3BnlB,EAAKolB,WAAaxL,EAAKyL,KAAKC,YAAY1L,EAAKqL,KAAKzlB,WAAWzgB,GAAGomC,iBAAiB,IAE9EvL,EAAKqL,KAAKzlB,WAAWzgB,GAAGkiB,UAC3BjB,EAAKvO,KAAOmoB,EAAKqL,KAAKzlB,WAAWzgB,GAAGkiB,UAEpCjB,EAAKvO,KAAO,OAEbuO,EAAKc,aAAe8Y,EAAKqL,KAAKzlB,WAAWzgB,GAAG+hB,aAC5Cd,EAAKe,iBAAmB6Y,EAAKqL,KAAKzlB,WAAWzgB,GAAGgiB,iBAEjD,GAAI6Y,EAAK2L,KACR,IAAIxmC,EAAI,EAAGA,EAAI66B,EAAK2L,KAAKzlB,MAAM5hB,OAAQa,IAAK,CAC3C,IACIymC,EAAU5L,EAAK2L,KAAKzlB,MAAM/gB,GAC9BihB,EAAOF,EAAM0lB,EAAQvlB,SAKrB,OAJqC,IAAjCulB,EAAQjvB,uBACX3Z,IAAIS,KAAK,6DACT2iB,EAAKylB,OAAS7L,EAAK8L,KAAKxzB,MAAMszB,EAAQjvB,qBAAqB,IAErDivB,EAAQtlB,qBACd,KAAK,EACL,MACA,KAAK,EAGL,KAAK,EACLtjB,IAAIS,KAAK,yDAKV,IAFA2iB,EAAKK,QAAU,GAEVva,EADLka,EAAKzf,KAAO,EACAuF,EAAI0/B,EAAQnlB,QAAQniB,OAAQ4H,IACvCka,EAAKK,QAAQva,GAAK,GAClBka,EAAKK,QAAQva,GAAG4B,OAAS89B,EAAQnlB,QAAQva,GAAG0a,cAAgBglB,EAAQrlB,YACpEH,EAAKK,QAAQva,GAAG5H,OAASsnC,EAAQnlB,QAAQva,GAAG2a,cAC5CT,EAAKK,QAAQva,GAAGi5B,YAAc,EAC9B/e,EAAKzf,MAAQyf,EAAKK,QAAQva,GAAG5H,OAOhC,GAHI07B,EAAK+L,OACR7lB,EAAM8Z,EAAK+L,KAAKzhB,SAAS0hB,SAAU,GAEhChM,EAAKiM,KACR,IAAK9mC,EAAE,EAAGA,EAAG66B,EAAKiM,KAAKnkB,WAAWxjB,OAAQa,IAEzC,IADA,IAAI2pB,EAAMkR,EAAKiM,KAAKnkB,WAAW3iB,GAC1B+G,EAAE,EAAGA,EAAE4iB,EAAIhH,WAAWxjB,OAAQ4H,IAClCga,EAAM4I,EAAIQ,cAAcgc,OAAOtjC,KAAK,CAAC6P,KAAMiX,EAAIjX,KAAMyL,GAAIwL,EAAIhH,WAAW5b,KAI3E,GAAI8zB,EAAKkM,KACR,IAAK,IAAI//B,EAAI,EAAGA,EAAI6zB,EAAKkM,KAAKC,MAAM7nC,OAAQ6H,IAE3C,IADA,IAAIigC,EAAOpM,EAAKkM,KAAKC,MAAMhgC,GACtBhH,EAAI,EAAGA,EAAIinC,EAAK7kB,aAAajjB,OAAQa,IAAK,CAC9C,IAAIknC,EAAcD,EAAK7kB,aAAapiB,GAMpC,SAJwBtB,KADxBuiB,EAAOF,EAAMmmB,EAAY/oB,KAChBgpB,aACRlmB,EAAKkmB,WAAa,GAClBlmB,EAAKkmB,WAAWh0B,MAAQ,IAEpBpM,EAAI,EAAGA,EAAImgC,EAAY3kB,MAAMpjB,OAAQ4H,IAAK,CAC9C,IAAIqgC,EAAYF,EAAY3kB,MAAMxb,GACH,EAA3BqgC,EAAU1kB,iBACT2kB,EAAUxM,EAAKkM,KAAKO,KAAKn0B,MAAMi0B,EAAU1kB,eAAe,GAC5DzB,EAAKkmB,WAAWE,EAAQ30B,MAAQ20B,EAChCpmB,EAAKkmB,WAAWh0B,MAAMtQ,KAAKwkC,QAQjC9P,QAAQ72B,UAAU6mC,QAAU,SAASpiB,GACpC,IAAI7kB,EACA2gB,EAEJ,IAAK9iB,KAAK08B,KACT,OAAO,KAIR,KADC5Z,EAAO9iB,KAAK4iB,MAAMoE,IACTtV,MAAQoR,EAAKzf,KAEtByf,EAAKpR,KAAO,IAAIzM,WAAW6d,EAAKzf,MAChCyf,EAAK+e,YAAc,EACnB7hC,KAAK8nC,eAAiBhlB,EAAKzf,KAC3B3D,IAAIO,MAAM,UAAW,oBAAoB+mB,EAAQ,YAAYlE,EAAKzf,KAAK,YAAYrD,KAAK8nC,cAAc,UAChG,GAAIhlB,EAAK+e,cAAgB/e,EAAKzf,KAEpC,OAAOyf,EAKR,IAAK,IAAIjhB,EAAI,EAAGA,EAAIihB,EAAKK,QAAQniB,OAAQa,IAAK,CAC7C,IAAIuhB,EAASN,EAAKK,QAAQthB,GAC1B,GAAIuhB,EAAOye,cAAgBze,EAAOpiB,OAAlC,CAGC,IAAIiP,EAAQjQ,KAAKiR,OAAOrB,cAAa,EAAMwT,EAAO5Y,OAAS4Y,EAAOye,aAAa,GAC/E,MAAa,EAAT5xB,GAqCH,OAAO,KAnCHy3B,GADJvlC,EAASnC,KAAKiR,OAAOhD,QAAQgC,IACCvN,YAAc0gB,EAAO5Y,OAAS4Y,EAAOye,YAAc1/B,EAAOmM,WACxF,KAAI8U,EAAOpiB,OAASoiB,EAAOye,aAAe6F,GA+BzC,OAZAhoC,IAAIO,MAAM,UAAU,iBAAiB+mB,EAAQ,YAAYnlB,EAAE,+BAA+BuhB,EAAOye,YAAY,aAC3Gze,EAAO5Y,OAAO4Y,EAAOye,YAAc1/B,EAAOmM,WAAW,eAAeo5B,EACrE,sBAAsBtkB,EAAOpiB,OAAO,oBAAoB8hB,EAAKzf,KAAK,KAEnEoC,WAAW2B,OAAO0b,EAAKpR,KAAKvP,OAAQ2gB,EAAK+e,YACvB1/B,EAAQihB,EAAO5Y,OAAO4Y,EAAOye,YAAc1/B,EAAOmM,UAAWo5B,GAC/EtkB,EAAOye,aAAe6F,EACtB5kB,EAAK+e,aAAe6F,EAGpBvlC,EAAO2M,WAAa44B,EACpB1nC,KAAKiR,OAAO1C,iBACL,KA5BP7O,IAAIO,MAAM,UAAU,iBAAiB+mB,EAAQ,YAAYnlB,EAAE,uBAAuBuhB,EAAOye,YACxF,aAAaze,EAAO5Y,OAAO4Y,EAAOye,YAAc1/B,EAAOmM,WAAW,gBAAgB8U,EAAOpiB,OAASoiB,EAAOye,aACzG,sBAAsBze,EAAOpiB,OAAO,oBAAoB8hB,EAAKzf,KAAK,KAEnEoC,WAAW2B,OAAO0b,EAAKpR,KAAKvP,OAAQ2gB,EAAK+e,YACvB1/B,EAAQihB,EAAO5Y,OAAO4Y,EAAOye,YAAc1/B,EAAOmM,UAAW8U,EAAOpiB,OAASoiB,EAAOye,aAGtG1/B,EAAO2M,WAAasU,EAAOpiB,OAASoiB,EAAOye,YAC3C7hC,KAAKiR,OAAO1C,iBAEZuU,EAAK+e,aAAgBze,EAAOpiB,OAASoiB,EAAOye,YAC5Cze,EAAOye,YAAcze,EAAOpiB,QAuBhC,OAAI8hB,EAAK+e,cAAgB/e,EAAKzf,KAEtByf,EAEA,MAKTsW,QAAQ72B,UAAU8mC,YAAc,SAASriB,GACxC,IAAIlE,EAAO9iB,KAAK4iB,MAAMoE,GACtB,GAAIlE,EAAKpR,KAAM,CACd1R,KAAK8nC,eAAiBhlB,EAAKzf,KAC3Byf,EAAKpR,KAAO,KAEZ,IAAK,IAAI7P,EADTihB,EAAK+e,YAAc,EACHhgC,EAAIihB,EAAKK,QAAQniB,OAAQa,IAC3BihB,EAAKK,QAAQthB,GACnBggC,YAAc,EAEtB,OAAO/e,EAAKzf,KAEZ,OAAO,GAKT+1B,QAAQ72B,UAAUq6B,aAAe,SAAS0M,GACzC,IAAI,IAAIznC,KAAK7B,KAAK4iB,MAAO,CACxB,IAAIE,EAAO9iB,KAAK4iB,MAAM/gB,GACtB7B,KAAKopC,QAAQtmB,EAAK9C,IACdspB,IAAaxmB,EAAKymB,OACrBD,EAASxmB,GACTA,EAAKymB,MAAO,EACZzmB,EAAKpR,KAAO,QAKf0nB,QAAQ72B,UAAUinC,QAAU,SAASryB,GACpC,IAAI,IAAItV,KAAK7B,KAAK4iB,MAAO,CACxB,IAAIE,EAAO9iB,KAAK4iB,MAAM/gB,GACtB,GAAIihB,EAAK3L,OAASA,EACjB,OAAO2L,EAAK9C,GAGd,OAAQ,GAGToZ,QAAQ72B,UAAUknC,eAAiB,WAClC,OAAKzpC,KAAK08B,KAGF18B,KAAK08B,KAAKkC,KAAK9d,QAFf,MAMTsY,QAAQ72B,UAAUmnC,eAAiB,WAClC,OAAK1pC,KAAK08B,MAAS18B,KAAK08B,KAAK+L,KAGrBzoC,KAAKopC,QAAQppC,KAAK08B,KAAK+L,KAAKzhB,SAF5B,MAMToS,QAAQ72B,UAAUonC,0BAA4B,SAASnH,GACtD,IAAI7H,EAAU6H,GAAY,GACtB1f,EAAO,KAMX,GAAY,OAJXA,EADG6X,EAAQiP,OACJ5pC,KAAKopC,QAAQzO,EAAQiP,QAErB5pC,KAAK0pC,kBAEK,OAAO,KAErBG,EAAO,IAAIzQ,QACfyQ,EAAKvH,iBAAkB,EAEnBwH,EAAe,CAAEv1B,KAAMuO,EAAKvO,KAAMwuB,kBAAmBjgB,EAAKkmB,WAAWh0B,OACrE8N,EAAKkmB,WAAWe,OACnBD,EAAatwB,MAAQsJ,EAAKkmB,WAAWe,KAAKnlB,YAC1CklB,EAAarwB,OAASqJ,EAAKkmB,WAAWe,KAAKllB,cAExCmlB,EAAUH,EAAKpH,SAASqH,GAC5B,OAAIE,GACHH,EAAK1G,UAAU6G,EAASlnB,EAAKpR,MACtBm4B,GAEA,MAMTzQ,QAAQ72B,UAAU6V,MAAQ,SAAS6xB,GAClC,IAAK,IAAIpoC,EAAE,EAAGA,EAAE7B,KAAKgV,MAAMhU,OAAQa,IAClC7B,KAAKgV,MAAMnT,GAAGuW,MAAM6xB,IAItB7Q,QAAQ72B,UAAU+9B,eAAiB,SAAShR,EAAU4a,EAAchH,GACnE,IAAIrI,EAAO76B,KAAK86B,aAAaxL,GACzBuJ,EAAS74B,KAAKwgC,UAAU3F,EAAMqP,GAClC,GAAc,MAAVrR,EAOH,OANAA,EAASgC,EAAK7D,QAAQkT,GAClBlqC,KAAKu8B,iBACRv8B,KAAKu8B,iBAAmBj7B,KAAK0B,IAAI61B,EAAOruB,OAAOquB,EAAOgJ,YAAY7hC,KAAKu8B,kBAEvEv8B,KAAKu8B,iBAAmB1B,EAAK7D,QAAQkT,GAAc1/B,OAAOquB,EAAOgJ,YAE3D,KAGJ5wB,EAASiyB,GAAW,IAAIz9B,WAC5BwL,EAAOtL,WAAaF,WAAWkB,WAE3B68B,EAAOxjC,KAAKyjC,uBAAuB5K,GACvC2K,EAAKprB,MAAMnH,GAGXuyB,EAAKE,MAAM,GAAGC,MAAM,GAAGlT,YAAc+S,EAAKngC,KAAK,EAC/C3D,IAAIO,MAAM,SAAU,wCAAwCujC,EAAKE,MAAM,GAAGC,MAAM,GAAGlT,aACnFxf,EAAOnD,aAAa01B,EAAKE,MAAM,GAAGC,MAAM,GAAG9M,qBAAsB2M,EAAKE,MAAM,GAAGC,MAAM,GAAGlT,aAEpF0Z,EAAO,IAAIl3B,UAAUm3B,QAGzB,OAFAD,EAAKz4B,KAAOmnB,EAAOnnB,KACnBy4B,EAAK/xB,MAAMnH,GACJA,GAIRmoB,QAAQiR,2BAA6B,SAASzM,EAAM1B,EAAMoO,EAAgB3Z,GACzE,IAAI9uB,EAKJnC,IAAIO,MAAM,UAAW,qCAErB,IAAIgR,EAAS,IAAIxL,WACjBwL,EAAOtL,WAAaF,WAAWkB,WAC/Bi3B,EAAKxlB,MAAMnH,GAGX,IAAIssB,EAAOrB,EAAKhlB,IAAI,QAIpB,IAHIozB,GACH/M,EAAKrmB,IAAI,QAAQ1Q,IAAI,oBAAqB8jC,GAEtCzoC,EAAI,EAAGA,EAAIq6B,EAAKoC,MAAMt9B,OAAQa,IAClC07B,EAAKrmB,IAAI,QAAQ1Q,IAAI,WAAY01B,EAAKoC,MAAMz8B,GAAG88B,KAAKrP,UAC/C9oB,IAAI,mCAAoC,GACxCA,IAAI,0BAA2BmqB,GAC/BnqB,IAAI,sBAAuB,GAC3BA,IAAI,uBAAwB,OAIlC,OAFA01B,EAAK9jB,MAAMnH,GAEJA,EAAO9O,QAIfi3B,QAAQ72B,UAAUiH,KAAO,SAAS2N,GACjC,IAAIlG,EAAS,IAAIxL,WACjBwL,EAAOtL,WAAaF,WAAWkB,WAC/B3G,KAAKoY,MAAMnH,GACXA,EAAOzH,KAAK2N,IAGbiiB,QAAQ72B,UAAUgoC,UAAY,WAC7B,IAAIt5B,EAAS,IAAIxL,WAGjB,OAFAwL,EAAOtL,WAAaF,WAAWkB,WAC/B3G,KAAKoY,MAAMnH,GACJA,EAAO9O,QAGfi3B,QAAQ72B,UAAUioC,uBAAyB,WAC1C,IAAI3oC,EAGA4oC,EACA5P,EACA6P,EAUJ,IATuB,OAAnB1qC,KAAK65B,WACRn6B,IAAIS,KAAK,SAAU,iCAEfH,KAAKm6B,6BACTn6B,KAAKm6B,4BAA6B,EAClCn6B,KAAKq6B,eAAiB,EACtBr6B,KAAK+jC,eAEN0G,EAAW,GACN5oC,EAAI,EAAGA,EAAI7B,KAAKi6B,iBAAiBj5B,OAAQa,IAAK,CAClD,IAAIq6B,EAAO,IAAIjpB,UAAU03B,QACzBzO,EAAKmB,KAAOr9B,KAAKk8B,KAAKmB,KACnBnB,EAAKlnB,MAAMtQ,KAAKw3B,EAAKmB,MACxBxC,EAAO76B,KAAK86B,aAAa96B,KAAKi6B,iBAAiBp4B,GAAGme,IAClDkc,EAAKlnB,MAAMtQ,KAAKm2B,GAChBqB,EAAKoC,MAAM55B,KAAKm2B,IAChB6P,EAAM,IACF1qB,GAAK6a,EAAK8D,KAAKrP,SACnBob,EAAIhQ,KAAO16B,KAAKi6B,iBAAiBp4B,GAAG64B,KACpCgQ,EAAIvoC,OAASi3B,QAAQiR,2BAA2BrqC,KAAK49B,KAAM1B,EAAOl8B,KAAKk8B,KAAKqB,MAAQv9B,KAAKk8B,KAAKqB,KAAKC,KAAOx9B,KAAKk8B,KAAKqB,KAAKC,KAAKvX,uBAAmB1lB,EAA+C,EAAlCP,KAAKk8B,KAAKoC,MAAMz8B,GAAGm1B,QAAQh2B,OAAWhB,KAAKk8B,KAAKoC,MAAMz8B,GAAGm1B,QAAQ,GAAGr2B,SAAU,GAC5O8pC,EAAS/lC,KAAKgmC,GAEf,OAAOD,GAQRx3B,UAAUiB,IAAI3R,UAAUqoC,YAAc,SAASC,GAC9C7qC,KAAKqD,MAAQ,EACTrD,KAAKqD,KAAOiG,WACftJ,KAAKqD,MAAQ,GAEI,SAAdrD,KAAKuU,OACRvU,KAAKqD,MAAQ,IAEdwnC,EAAOpqC,IAAIoqC,EAAOC,OAAO,QAAQ9qC,KAAKqD,MACtCwnC,EAAOpqC,IAAIoqC,EAAOC,OAAO,QAAQ9qC,KAAKuU,OAGvCtB,UAAUgB,QAAQ1R,UAAUqoC,YAAc,SAASC,GAClD7qC,KAAKqD,MAAQ,EACb4P,UAAUiB,IAAI3R,UAAUqoC,YAAY94B,KAAK9R,KAAM6qC,GAC/CA,EAAOpqC,IAAIoqC,EAAOC,OAAO,WAAW9qC,KAAK+U,SACzC81B,EAAOpqC,IAAIoqC,EAAOC,OAAO,SAAS9qC,KAAKiS,QAGxCgB,UAAUiB,IAAI3R,UAAUwoC,MAAQ,SAASF,GACxC7qC,KAAK4qC,YAAYC,IAGlB53B,UAAUkB,aAAa5R,UAAUwoC,MAAQ,SAASF,GACjD7qC,KAAK4qC,YAAYC,GACjB,IAAK,IAECG,EAFGnpC,EAAE,EAAGA,EAAE7B,KAAKgV,MAAMhU,OAAQa,IAC9B7B,KAAKgV,MAAMnT,KACVmpC,EAAcH,EAAOC,OACzBD,EAAOC,QAAU,IACjB9qC,KAAKgV,MAAMnT,GAAGkpC,MAAMF,GACpBA,EAAOC,OAASE,IAKnB5R,QAAQ72B,UAAUwoC,MAAQ,SAASF,GAClCA,EAAOC,OAAS,GAChB,IAAK,IAAIjpC,EAAE,EAAGA,EAAE7B,KAAKgV,MAAMhU,OAAQa,IAC9B7B,KAAKgV,MAAMnT,IACd7B,KAAKgV,MAAMnT,GAAGkpC,MAAMF,IAKvB53B,UAAUwiB,QAAQlzB,UAAUwoC,MAAQ,SAASF,GAC5C53B,UAAUgB,QAAQ1R,UAAUqoC,YAAY94B,KAAK9R,KAAM6qC,GACnDA,EAAOpqC,IAAIoqC,EAAOC,OAAO,kBAAkB9qC,KAAK+lB,eAChD8kB,EAAOpqC,IAAIoqC,EAAOC,OAAO,sBAAsB9qC,KAAKgmB,mBACpD6kB,EAAOpqC,IAAIoqC,EAAOC,OAAO,cAAc9qC,KAAK6f,WAC5CgrB,EAAOpqC,IAAIoqC,EAAOC,OAAO,aAAa9qC,KAAKW,UAC3CkqC,EAAOpqC,IAAIoqC,EAAOC,OAAO,SAAS9qC,KAAKmmB,MACvC0kB,EAAOpqC,IAAIoqC,EAAOC,OAAO,YAAY9qC,KAAKomB,QAAQ,IAClDykB,EAAOpqC,IAAIoqC,EAAOC,OAAO,WAAW9qC,KAAKqmB,OAAOllB,KAAK,OACrD0pC,EAAOpqC,IAAIoqC,EAAOC,OAAO,kBAAkB9qC,KAAKsmB,gBAGjDrT,UAAUyjB,QAAQn0B,UAAUwoC,MAAQ,SAASF,GAC5C53B,UAAUgB,QAAQ1R,UAAUqoC,YAAY94B,KAAK9R,KAAM6qC,GACnDA,EAAOpqC,IAAIoqC,EAAOC,OAAO,kBAAkB9qC,KAAK+lB,eAChD8kB,EAAOpqC,IAAIoqC,EAAOC,OAAO,sBAAsB9qC,KAAKgmB,mBACpD6kB,EAAOpqC,IAAIoqC,EAAOC,OAAO,aAAa9qC,KAAKsvB,UAC3Cub,EAAOpqC,IAAIoqC,EAAOC,OAAO,aAAa9qC,KAAKW,UAC3CkqC,EAAOpqC,IAAIoqC,EAAOC,OAAO,YAAY9qC,KAAKomB,QAAQ,IAClDykB,EAAOpqC,IAAIoqC,EAAOC,OAAO,WAAW9qC,KAAKqmB,OAAOllB,KAAK,OACrD0pC,EAAOpqC,IAAIoqC,EAAOC,OAAO,UAAU9qC,KAAKowB,OACxCya,EAAOpqC,IAAIoqC,EAAOC,OAAO,oBAAoB9qC,KAAKmtB,iBAClD0d,EAAOpqC,IAAIoqC,EAAOC,OAAO,UAAU9qC,KAAKwZ,OACxCqxB,EAAOpqC,IAAIoqC,EAAOC,OAAO,WAAW9qC,KAAKyZ,SAM1C,IAAIwxB,OAAS,CAEbC,WAAoB,SAAUC,EAAeC,GAExCC,OAAkC9qC,IAAlB4qC,GAA8BA,EAC9CtB,EAAO,IAAIzQ,QAAQgS,GAEvB,OADAvB,EAAKvH,iBAAmB+I,EACjBxB,IAGe,oBAAZ9nC,UACVA,QAAQmpC,WAAaD,OAAOC"} \ No newline at end of file diff --git a/samples/samples.css b/samples/samples.css index 1e2d74cc..6a410835 100644 --- a/samples/samples.css +++ b/samples/samples.css @@ -31,11 +31,11 @@ body { text-decoration: underline; } -article a { +a article { color: #FEFEF2; text-decoration: none; } -article a:hover { +a:hover article { color: white; text-decoration: underline; } diff --git a/samples/server.js b/samples/server.js new file mode 100644 index 00000000..c3f09577 --- /dev/null +++ b/samples/server.js @@ -0,0 +1,64 @@ +const http = require('http'), + url = require("url"), + path = require("path"), + fs = require("fs"), + port = process.argv[2] || 8888, + mimeTypes = { + "html": "text/html", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "png": "image/png", + "js": "text/javascript", + "wasm": "application/wasm", + "css": "text/css" + }; + +const serverPort = parseInt(port, 10); + +http.createServer({}, function(request, response) { + var uri = url.parse(request.url).pathname, + filename = path.join(process.cwd(), uri); + + fs.exists(filename, function(exists) { + if(!exists) { + response.writeHead(404, { "Content-Type": "text/plain" }); + response.write("404 Not Found\n"); + response.end(); + return; + } + + if (fs.statSync(filename).isDirectory()) { + if (filename[filename.length-1] != '/') { + filename += '/'; + } + filename += 'index.html'; + } + + fs.readFile(filename, "binary", function(err, file) { + if(err) { + response.writeHead(500, {"Content-Type": "text/plain", "Cross-Origin-Opener-Policy": "same-origin unsafe-allow-outgoing"}); + response.write(err + "\n"); + response.end(); + return; + } + + var mimeType = mimeTypes[filename.split('.').pop()]; + + if (!mimeType) { + mimeType = 'text/plain'; + } + + console.log("serving " + filename); + + response.writeHead(200, { "Content-Type": mimeType , + "Cross-Origin-Opener-Policy": "same-origin", + "Cross-Origin-Embedder-Policy": "require-corp" }); + response.write(file, "binary"); + response.end(); + }); + }); + +// This server is insecure. Only listen for conncections on localhost. +}).listen(serverPort, 'localhost'); + +console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown"); diff --git a/samples/third_party/mp4boxjs/LICENSE b/samples/third_party/mp4boxjs/LICENSE new file mode 100644 index 00000000..6513daca --- /dev/null +++ b/samples/third_party/mp4boxjs/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2012. Telecom ParisTech/TSI/MM/GPAC Cyril Concolato +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/samples/third_party/mp4boxjs/mp4box.all.min.js b/samples/third_party/mp4boxjs/mp4box.all.min.js new file mode 100644 index 00000000..5aea04cc --- /dev/null +++ b/samples/third_party/mp4boxjs/mp4box.all.min.js @@ -0,0 +1,3 @@ +/*! mp4box 19-03-2022 */ + +var Log=function(){var i=new Date,r=4;return{setLogLevel:function(t){r=t==this.debug?1:t==this.info?2:t==this.warn?3:(this.error,4)},debug:function(t,e){void 0===console.debug&&(console.debug=console.log),r<=1&&console.debug("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)},log:function(t,e){this.debug(t.msg)},info:function(t,e){r<=2&&console.info("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)},warn:function(t,e){r<=3&&console.warn("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)},error:function(t,e){r<=4&&console.error("["+Log.getDurationString(new Date-i,1e3)+"]","["+t+"]",e)}}}();Log.getDurationString=function(t,e){var i;function r(t,e){for(var i=(""+t).split(".");i[0].length=this.getEndPosition()},MP4BoxStream.prototype.readAnyInt=function(t,e){var i=0;if(this.position+t<=this.buffer.byteLength){switch(t){case 1:i=e?this.dataview.getInt8(this.position):this.dataview.getUint8(this.position);break;case 2:i=e?this.dataview.getInt16(this.position):this.dataview.getUint16(this.position);break;case 3:if(e)throw"No method for reading signed 24 bits values";i=this.dataview.getUint8(this.position)<<16,i|=this.dataview.getUint8(this.position+1)<<8,i|=this.dataview.getUint8(this.position+2);break;case 4:i=e?this.dataview.getInt32(this.position):this.dataview.getUint32(this.position);break;case 8:if(e)throw"No method for reading signed 64 bits values";i=this.dataview.getUint32(this.position)<<32,i|=this.dataview.getUint32(this.position+4);break;default:throw"readInt method not implemented for size: "+t}return this.position+=t,i}throw"Not enough bytes in buffer"},MP4BoxStream.prototype.readUint8=function(){return this.readAnyInt(1,!1)},MP4BoxStream.prototype.readUint16=function(){return this.readAnyInt(2,!1)},MP4BoxStream.prototype.readUint24=function(){return this.readAnyInt(3,!1)},MP4BoxStream.prototype.readUint32=function(){return this.readAnyInt(4,!1)},MP4BoxStream.prototype.readUint64=function(){return this.readAnyInt(8,!1)},MP4BoxStream.prototype.readString=function(t){if(this.position+t<=this.buffer.byteLength){for(var e="",i=0;ithis._byteLength&&(this._byteLength=e);else{for(i<1&&(i=1);i=this._byteLength},DataStream.prototype.mapUint8Array=function(t){this._realloc(+t);var e=new Uint8Array(this._buffer,this.byteOffset+this.position,t);return this.position+=+t,e},DataStream.prototype.readInt32Array=function(t,e){t=null==t?this.byteLength-this.position/4:t;var i=new Int32Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readInt16Array=function(t,e){t=null==t?this.byteLength-this.position/2:t;var i=new Int16Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readInt8Array=function(t){t=null==t?this.byteLength-this.position:t;var e=new Int8Array(t);return DataStream.memcpy(e.buffer,0,this.buffer,this.byteOffset+this.position,t*e.BYTES_PER_ELEMENT),this.position+=e.byteLength,e},DataStream.prototype.readUint32Array=function(t,e){t=null==t?this.byteLength-this.position/4:t;var i=new Uint32Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readUint16Array=function(t,e){t=null==t?this.byteLength-this.position/2:t;var i=new Uint16Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readUint8Array=function(t){t=null==t?this.byteLength-this.position:t;var e=new Uint8Array(t);return DataStream.memcpy(e.buffer,0,this.buffer,this.byteOffset+this.position,t*e.BYTES_PER_ELEMENT),this.position+=e.byteLength,e},DataStream.prototype.readFloat64Array=function(t,e){t=null==t?this.byteLength-this.position/8:t;var i=new Float64Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readFloat32Array=function(t,e){t=null==t?this.byteLength-this.position/4:t;var i=new Float32Array(t);return DataStream.memcpy(i.buffer,0,this.buffer,this.byteOffset+this.position,t*i.BYTES_PER_ELEMENT),DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=i.byteLength,i},DataStream.prototype.readInt32=function(t){t=this._dataView.getInt32(this.position,null==t?this.endianness:t);return this.position+=4,t},DataStream.prototype.readInt16=function(t){t=this._dataView.getInt16(this.position,null==t?this.endianness:t);return this.position+=2,t},DataStream.prototype.readInt8=function(){var t=this._dataView.getInt8(this.position);return this.position+=1,t},DataStream.prototype.readUint32=function(t){t=this._dataView.getUint32(this.position,null==t?this.endianness:t);return this.position+=4,t},DataStream.prototype.readUint16=function(t){t=this._dataView.getUint16(this.position,null==t?this.endianness:t);return this.position+=2,t},DataStream.prototype.readUint8=function(){var t=this._dataView.getUint8(this.position);return this.position+=1,t},DataStream.prototype.readFloat32=function(t){t=this._dataView.getFloat32(this.position,null==t?this.endianness:t);return this.position+=4,t},DataStream.prototype.readFloat64=function(t){t=this._dataView.getFloat64(this.position,null==t?this.endianness:t);return this.position+=8,t},DataStream.endianness=0>16),this.writeUint8((65280&t)>>8),this.writeUint8(255&t)},DataStream.prototype.adjustUint32=function(t,e){var i=this.position;this.seek(t),this.writeUint32(e),this.seek(i)},DataStream.prototype.mapInt32Array=function(t,e){this._realloc(4*t);var i=new Int32Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=4*t,i},DataStream.prototype.mapInt16Array=function(t,e){this._realloc(2*t);var i=new Int16Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=2*t,i},DataStream.prototype.mapInt8Array=function(t){this._realloc(+t);var e=new Int8Array(this._buffer,this.byteOffset+this.position,t);return this.position+=+t,e},DataStream.prototype.mapUint32Array=function(t,e){this._realloc(4*t);var i=new Uint32Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=4*t,i},DataStream.prototype.mapUint16Array=function(t,e){this._realloc(2*t);var i=new Uint16Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=2*t,i},DataStream.prototype.mapFloat64Array=function(t,e){this._realloc(8*t);var i=new Float64Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=8*t,i},DataStream.prototype.mapFloat32Array=function(t,e){this._realloc(4*t);var i=new Float32Array(this._buffer,this.byteOffset+this.position,t);return DataStream.arrayToNative(i,null==e?this.endianness:e),this.position+=4*t,i};var MultiBufferStream=function(t){this.buffers=[],this.bufferIndex=-1,t&&(this.insertBuffer(t),this.bufferIndex=0)};MultiBufferStream.prototype=new DataStream(new ArrayBuffer,0,DataStream.BIG_ENDIAN),MultiBufferStream.prototype.initialized=function(){var t;return-1r.byteLength){this.buffers.splice(i,1),i--;continue}Log.warn("MultiBufferStream","Buffer (fileStart: "+t.fileStart+" - Length: "+t.byteLength+") already appended, ignoring")}else t.fileStart+t.byteLength<=r.fileStart||(t=this.reduceBuffer(t,0,r.fileStart-t.fileStart)),Log.debug("MultiBufferStream","Appending new buffer (fileStart: "+t.fileStart+" - Length: "+t.byteLength+")"),this.buffers.splice(i,0,t),0===i&&(this.buffer=t);e=!1;break}if(t.fileStart"+this.buffer.byteLength+")"),!0}return!1},MultiBufferStream.prototype.findPosition=function(t,e,i){for(var r=null,s=-1,a=!0===t?0:this.bufferIndex;a=e?(Log.debug("MultiBufferStream","Found position in existing buffer #"+s),s):-1},MultiBufferStream.prototype.findEndContiguousBuf=function(t){var e,i,t=void 0!==t?t:this.bufferIndex,r=this.buffers[t];if(this.buffers.length>t+1)for(e=t+1;e>3;return 31===e&&2<=i.data.length&&(e=32+((7&i.data[0])<<3)+((224&i.data[1])>>5)),e}return null},a.DecoderConfigDescriptor=function(t){a.Descriptor.call(this,4,t)},a.DecoderConfigDescriptor.prototype=new a.Descriptor,a.DecoderConfigDescriptor.prototype.parse=function(t){this.oti=t.readUint8(),this.streamType=t.readUint8(),this.bufferSize=t.readUint24(),this.maxBitrate=t.readUint32(),this.avgBitrate=t.readUint32(),this.size-=13,this.parseRemainingDescriptors(t)},a.DecoderSpecificInfo=function(t){a.Descriptor.call(this,5,t)},a.DecoderSpecificInfo.prototype=new a.Descriptor,a.SLConfigDescriptor=function(t){a.Descriptor.call(this,6,t)},a.SLConfigDescriptor.prototype=new a.Descriptor,this};"undefined"!=typeof exports&&(exports.MPEG4DescriptorParser=MPEG4DescriptorParser);var BoxParser={ERR_INVALID_DATA:-1,ERR_NOT_ENOUGH_DATA:0,OK:1,BASIC_BOXES:["mdat","idat","free","skip","meco","strk"],FULL_BOXES:["hmhd","nmhd","iods","xml ","bxml","ipro","mere"],CONTAINER_BOXES:[["moov",["trak","pssh"]],["trak"],["edts"],["mdia"],["minf"],["dinf"],["stbl",["sgpd","sbgp"]],["mvex",["trex"]],["moof",["traf"]],["traf",["trun","sgpd","sbgp"]],["vttc"],["tref"],["iref"],["mfra",["tfra"]],["meco"],["hnti"],["hinf"],["strk"],["strd"],["sinf"],["rinf"],["schi"],["trgr"],["udta",["kind"]],["iprp",["ipma"]],["ipco"]],boxCodes:[],fullBoxCodes:[],containerBoxCodes:[],sampleEntryCodes:{},sampleGroupEntryCodes:[],trackGroupTypes:[],UUIDBoxes:{},UUIDs:[],initialize:function(){BoxParser.FullBox.prototype=new BoxParser.Box,BoxParser.ContainerBox.prototype=new BoxParser.Box,BoxParser.SampleEntry.prototype=new BoxParser.Box,BoxParser.TrackGroupTypeBox.prototype=new BoxParser.FullBox,BoxParser.BASIC_BOXES.forEach(function(t){BoxParser.createBoxCtor(t)}),BoxParser.FULL_BOXES.forEach(function(t){BoxParser.createFullBoxCtor(t)}),BoxParser.CONTAINER_BOXES.forEach(function(t){BoxParser.createContainerBoxCtor(t[0],null,t[1])})},Box:function(t,e,i){this.type=t,this.size=e,this.uuid=i},FullBox:function(t,e,i){BoxParser.Box.call(this,t,e,i),this.flags=0,this.version=0},ContainerBox:function(t,e,i){BoxParser.Box.call(this,t,e,i),this.boxes=[]},SampleEntry:function(t,e,i,r){BoxParser.ContainerBox.call(this,t,e),this.hdr_size=i,this.start=r},SampleGroupEntry:function(t){this.grouping_type=t},TrackGroupTypeBox:function(t,e){BoxParser.FullBox.call(this,t,e)},createBoxCtor:function(e,t){BoxParser.boxCodes.push(e),BoxParser[e+"Box"]=function(t){BoxParser.Box.call(this,e,t)},BoxParser[e+"Box"].prototype=new BoxParser.Box,t&&(BoxParser[e+"Box"].prototype.parse=t)},createFullBoxCtor:function(e,i){BoxParser[e+"Box"]=function(t){BoxParser.FullBox.call(this,e,t)},BoxParser[e+"Box"].prototype=new BoxParser.FullBox,BoxParser[e+"Box"].prototype.parse=function(t){this.parseFullHeader(t),i&&i.call(this,t)}},addSubBoxArrays:function(t){if(t)for(var e=(this.subBoxNames=t).length,i=0;it.getEndPosition()?(t.seek(a),Log.info("BoxParser","Not enough data in stream to parse the entire '"+h+"' box"),{code:BoxParser.ERR_NOT_ENOUGH_DATA,type:h,size:o,hdr_size:n,start:a}):e?{code:BoxParser.OK,type:h,size:o,hdr_size:n,start:a}:(BoxParser[h+"Box"]?r=new BoxParser[h+"Box"](o):"uuid"!==h?(Log.warn("BoxParser","Unknown box type: '"+h+"'"),(r=new BoxParser.Box(h,o)).has_unparsed_data=!0):BoxParser.UUIDBoxes[s]?r=new BoxParser.UUIDBoxes[s](o):(Log.warn("BoxParser","Unknown uuid type: '"+s+"'"),(r=new BoxParser.Box(h,o)).uuid=s,r.has_unparsed_data=!0),r.hdr_size=n,r.start=a,r.write===BoxParser.Box.prototype.write&&"mdat"!==r.type&&(Log.info("BoxParser","'"+d+"' box writing not yet implemented, keeping unparsed data in memory for later write"),r.parseDataAndRewind(t)),r.parse(t),(a=t.getPosition()-(r.start+r.size))<0?(Log.warn("BoxParser","Parsing of box '"+d+"' did not read the entire indicated box data size (missing "+-a+" bytes), seeking forward"),t.seek(r.start+r.size)):0>10&31,t[1]=this.language>>5&31,t[2]=31&this.language,this.languageString=String.fromCharCode(t[0]+96,t[1]+96,t[2]+96)},BoxParser.SAMPLE_ENTRY_TYPE_VISUAL="Visual",BoxParser.SAMPLE_ENTRY_TYPE_AUDIO="Audio",BoxParser.SAMPLE_ENTRY_TYPE_HINT="Hint",BoxParser.SAMPLE_ENTRY_TYPE_METADATA="Metadata",BoxParser.SAMPLE_ENTRY_TYPE_SUBTITLE="Subtitle",BoxParser.SAMPLE_ENTRY_TYPE_SYSTEM="System",BoxParser.SAMPLE_ENTRY_TYPE_TEXT="Text",BoxParser.SampleEntry.prototype.parseHeader=function(t){t.readUint8Array(6),this.data_reference_index=t.readUint16(),this.hdr_size+=8},BoxParser.SampleEntry.prototype.parse=function(t){this.parseHeader(t),this.data=t.readUint8Array(this.size-this.hdr_size)},BoxParser.SampleEntry.prototype.parseDataAndRewind=function(t){this.parseHeader(t),this.data=t.readUint8Array(this.size-this.hdr_size),this.hdr_size-=8,t.position-=this.size-this.hdr_size},BoxParser.SampleEntry.prototype.parseFooter=function(t){BoxParser.ContainerBox.prototype.parse.call(this,t)},BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_HINT),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_METADATA),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SUBTITLE),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SYSTEM),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_TEXT),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,function(t){var e;this.parseHeader(t),t.readUint16(),t.readUint16(),t.readUint32Array(3),this.width=t.readUint16(),this.height=t.readUint16(),this.horizresolution=t.readUint32(),this.vertresolution=t.readUint32(),t.readUint32(),this.frame_count=t.readUint16(),e=Math.min(31,t.readUint8()),this.compressorname=t.readString(e),e<31&&t.readString(31-e),this.depth=t.readUint16(),t.readUint16(),this.parseFooter(t)}),BoxParser.createMediaSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,function(t){this.parseHeader(t),t.readUint32Array(2),this.channel_count=t.readUint16(),this.samplesize=t.readUint16(),t.readUint16(),t.readUint16(),this.samplerate=t.readUint32()/65536,this.parseFooter(t)}),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc2"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc3"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"avc4"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"av01"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"hvc1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"hev1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"vvc1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"vvi1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"vvs1"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"vvcN"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"vp08"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"vp09"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"mp4a"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"ac-3"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"ec-3"),BoxParser.createSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"Opus"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_VISUAL,"encv"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_AUDIO,"enca"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SUBTITLE,"encu"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_SYSTEM,"encs"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_TEXT,"enct"),BoxParser.createEncryptedSampleEntryCtor(BoxParser.SAMPLE_ENTRY_TYPE_METADATA,"encm"),BoxParser.createBoxCtor("a1lx",function(t){var e=16*(1+(1&(1&t.readUint8())));this.layer_size=[];for(var i=0;i<3;i++)this.layer_size[i]=16==e?t.readUint16():t.readUint32()}),BoxParser.createBoxCtor("a1op",function(t){this.op_index=t.readUint8()}),BoxParser.createFullBoxCtor("auxC",function(t){this.aux_type=t.readCString();var e=this.size-this.hdr_size-(this.aux_type.length+1);this.aux_subtype=t.readUint8Array(e)}),BoxParser.createBoxCtor("av1C",function(t){var e=t.readUint8();if(e>>7&!1)Log.error("av1C marker problem");else if(this.version=127&e,1===this.version)if(e=t.readUint8(),this.seq_profile=e>>5&7,this.seq_level_idx_0=31&e,e=t.readUint8(),this.seq_tier_0=e>>7&1,this.high_bitdepth=e>>6&1,this.twelve_bit=e>>5&1,this.monochrome=e>>4&1,this.chroma_subsampling_x=e>>3&1,this.chroma_subsampling_y=e>>2&1,this.chroma_sample_position=3&e,e=t.readUint8(),this.reserved_1=e>>5&7,0===this.reserved_1){if(this.initial_presentation_delay_present=e>>4&1,1===this.initial_presentation_delay_present)this.initial_presentation_delay_minus_one=15&e;else if(this.reserved_2=15&e,0!==this.reserved_2)return void Log.error("av1C reserved_2 parsing problem");e=this.size-this.hdr_size-4;this.configOBUs=t.readUint8Array(e)}else Log.error("av1C reserved_1 parsing problem");else Log.error("av1C version "+this.version+" not supported")}),BoxParser.createBoxCtor("avcC",function(t){var e,i;for(this.configurationVersion=t.readUint8(),this.AVCProfileIndication=t.readUint8(),this.profile_compatibility=t.readUint8(),this.AVCLevelIndication=t.readUint8(),this.lengthSizeMinusOne=3&t.readUint8(),this.nb_SPS_nalus=31&t.readUint8(),i=this.size-this.hdr_size-6,this.SPS=[],e=0;e>7):"rICC"!==this.colour_type&&"prof"!==this.colour_type||(this.ICC_profile=t.readUint8Array(this.size-4))}),BoxParser.createFullBoxCtor("cprt",function(t){this.parseLanguage(t),this.notice=t.readCString()}),BoxParser.createFullBoxCtor("cslg",function(t){0===this.version&&(this.compositionToDTSShift=t.readInt32(),this.leastDecodeToDisplayDelta=t.readInt32(),this.greatestDecodeToDisplayDelta=t.readInt32(),this.compositionStartTime=t.readInt32(),this.compositionEndTime=t.readInt32())}),BoxParser.createFullBoxCtor("ctts",function(t){var e,i=t.readUint32();if(this.sample_counts=[],this.sample_offsets=[],0===this.version)for(e=0;e>6,this.bsid=e>>1&31,this.bsmod=(1&e)<<2|i>>6&3,this.acmod=i>>3&7,this.lfeon=i>>2&1,this.bit_rate_code=3&i|t>>5&7}),BoxParser.createBoxCtor("dec3",function(t){var e=t.readUint16();this.data_rate=e>>3,this.num_ind_sub=7&e,this.ind_subs=[];for(var i=0;i>6,r.bsid=s>>1&31,r.bsmod=(1&s)<<4|a>>4&15,r.acmod=a>>1&7,r.lfeon=1&a,r.num_dep_sub=n>>1&15,0>12,t.readUint8Array(20)),e.push(i[s]),128&r)break}this.numMetadataBlocks=e.length+" ("+e.join(", ")+")"}),BoxParser.createBoxCtor("dimm",function(t){this.bytessent=t.readUint64()}),BoxParser.createBoxCtor("dmax",function(t){this.time=t.readUint32()}),BoxParser.createBoxCtor("dmed",function(t){this.bytessent=t.readUint64()}),BoxParser.createBoxCtor("dOps",function(t){if(this.Version=t.readUint8(),this.OutputChannelCount=t.readUint8(),this.PreSkip=t.readUint16(),this.InputSampleRate=t.readUint32(),this.OutputGain=t.readInt16(),this.ChannelMappingFamily=t.readUint8(),0!==this.ChannelMappingFamily){this.StreamCount=t.readUint8(),this.CoupledCount=t.readUint8(),this.ChannelMapping=[];for(var e=0;e>6,this.general_tier_flag=(32&i)>>5,this.general_profile_idc=31&i,this.general_profile_compatibility=t.readUint32(),this.general_constraint_indicator=t.readUint8Array(6),this.general_level_idc=t.readUint8(),this.min_spatial_segmentation_idc=4095&t.readUint16(),this.parallelismType=3&t.readUint8(),this.chroma_format_idc=3&t.readUint8(),this.bit_depth_luma_minus8=7&t.readUint8(),this.bit_depth_chroma_minus8=7&t.readUint8(),this.avgFrameRate=t.readUint16(),i=t.readUint8(),this.constantFrameRate=i>>6,this.numTemporalLayers=(13&i)>>3,this.temporalIdNested=(4&i)>>2,this.lengthSizeMinusOne=3&i,this.nalu_arrays=[];for(var r=t.readUint8(),s=0;s>7,a.nalu_type=63&i;for(var n=t.readUint16(),o=0;o>4&15,this.length_size=15&e,e=t.readUint8(),this.base_offset_size=e>>4&15,1===this.version||2===this.version?this.index_size=15&e:this.index_size=0,this.items=[];var i=0;if(this.version<2)i=t.readUint16();else{if(2!==this.version)throw"version of iloc box not supported";i=t.readUint32()}for(var r=0;r>7,this.axis=1&t}),BoxParser.createFullBoxCtor("infe",function(t){return 0!==this.version&&1!==this.version||(this.item_ID=t.readUint16(),this.item_protection_index=t.readUint16(),this.item_name=t.readCString(),this.content_type=t.readCString(),this.content_encoding=t.readCString()),1===this.version?(this.extension_type=t.readString(4),Log.warn("BoxParser","Cannot parse extension type"),void t.seek(this.start+this.size)):void(2<=this.version&&(2===this.version?this.item_ID=t.readUint16():3===this.version&&(this.item_ID=t.readUint32()),this.item_protection_index=t.readUint16(),this.item_type=t.readString(4),this.item_name=t.readCString(),"mime"===this.item_type?(this.content_type=t.readCString(),this.content_encoding=t.readCString()):"uri "===this.item_type&&(this.item_uri_type=t.readCString())))}),BoxParser.createFullBoxCtor("ipma",function(t){var e,i;for(entry_count=t.readUint32(),this.associations=[],e=0;e>7==1,1&this.flags?n.property_index=(127&a)<<8|t.readUint8():n.property_index=127&a}}}),BoxParser.createFullBoxCtor("iref",function(t){var e;for(this.references=[];t.getPosition()>7,r.assignment_type=127&s,r.assignment_type){case 0:r.grouping_type=t.readString(4);break;case 1:r.grouping_type=t.readString(4),r.grouping_type_parameter=t.readUint32();break;case 2:case 3:break;case 4:r.sub_track_id=t.readUint32();break;default:Log.warn("BoxParser","Unknown leva assignement type")}}}),BoxParser.createBoxCtor("lsel",function(t){this.layer_id=t.readUint16()}),BoxParser.createBoxCtor("maxr",function(t){this.period=t.readUint32(),this.bytes=t.readUint32()}),BoxParser.createBoxCtor("mdcv",function(t){this.display_primaries=[],this.display_primaries[0]={},this.display_primaries[0].x=t.readUint16(),this.display_primaries[0].y=t.readUint16(),this.display_primaries[1]={},this.display_primaries[1].x=t.readUint16(),this.display_primaries[1].y=t.readUint16(),this.display_primaries[2]={},this.display_primaries[2].x=t.readUint16(),this.display_primaries[2].y=t.readUint16(),this.white_point={},this.white_point.x=t.readUint16(),this.white_point.y=t.readUint16(),this.max_display_mastering_luminance=t.readUint32(),this.min_display_mastering_luminance=t.readUint32()}),BoxParser.createFullBoxCtor("mdhd",function(t){1==this.version?(this.creation_time=t.readUint64(),this.modification_time=t.readUint64(),this.timescale=t.readUint32(),this.duration=t.readUint64()):(this.creation_time=t.readUint32(),this.modification_time=t.readUint32(),this.timescale=t.readUint32(),this.duration=t.readUint32()),this.parseLanguage(t),t.readUint16()}),BoxParser.createFullBoxCtor("mehd",function(t){1&this.flags&&(Log.warn("BoxParser","mehd box incorrectly uses flags set to 1, converting version to 1"),this.version=1),1==this.version?this.fragment_duration=t.readUint64():this.fragment_duration=t.readUint32()}),BoxParser.createFullBoxCtor("meta",function(t){this.boxes=[],BoxParser.ContainerBox.prototype.parse.call(this,t)}),BoxParser.createFullBoxCtor("mfhd",function(t){this.sequence_number=t.readUint32()}),BoxParser.createFullBoxCtor("mfro",function(t){this._size=t.readUint32()}),BoxParser.createFullBoxCtor("mvhd",function(t){1==this.version?(this.creation_time=t.readUint64(),this.modification_time=t.readUint64(),this.timescale=t.readUint32(),this.duration=t.readUint64()):(this.creation_time=t.readUint32(),this.modification_time=t.readUint32(),this.timescale=t.readUint32(),this.duration=t.readUint32()),this.rate=t.readUint32(),this.volume=t.readUint16()>>8,t.readUint16(),t.readUint32Array(2),this.matrix=t.readUint32Array(9),t.readUint32Array(6),this.next_track_id=t.readUint32()}),BoxParser.createBoxCtor("npck",function(t){this.packetssent=t.readUint32()}),BoxParser.createBoxCtor("nump",function(t){this.packetssent=t.readUint64()}),BoxParser.createFullBoxCtor("padb",function(t){var e=t.readUint32();this.padbits=[];for(var i=0;i>7,this.avgRateFlag=e>>6&1,this.durationFlag&&(this.duration=t.readUint32()),this.avgRateFlag&&(this.accurateStatisticsFlag=t.readUint8(),this.avgBitRate=t.readUint16(),this.avgFrameRate=t.readUint16()),this.dependency=[];for(var i=t.readUint8(),r=0;r>7,this.num_leading_samples=127&t}),BoxParser.createSampleGroupCtor("rash",function(t){if(this.operation_point_count=t.readUint16(),this.description_length!==2+(1===this.operation_point_count?2:6*this.operation_point_count)+9)Log.warn("BoxParser","Mismatch in "+this.grouping_type+" sample group length"),this.data=t.readUint8Array(this.description_length-2);else{if(1===this.operation_point_count)this.target_rate_share=t.readUint16();else{this.target_rate_share=[],this.available_bitrate=[];for(var e=0;e>4,this.skip_byte_block=15&e,this.isProtected=t.readUint8(),this.Per_Sample_IV_Size=t.readUint8(),this.KID=BoxParser.parseHex16(t),this.constant_IV_size=0,this.constant_IV=0,1===this.isProtected&&0===this.Per_Sample_IV_Size&&(this.constant_IV_size=t.readUint8(),this.constant_IV=t.readUint8Array(this.constant_IV_size))}),BoxParser.createSampleGroupCtor("stsa",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createSampleGroupCtor("sync",function(t){t=t.readUint8();this.NAL_unit_type=63&t}),BoxParser.createSampleGroupCtor("tele",function(t){t=t.readUint8();this.level_independently_decodable=t>>7}),BoxParser.createSampleGroupCtor("tsas",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createSampleGroupCtor("tscl",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createSampleGroupCtor("vipr",function(t){Log.warn("BoxParser","Sample Group type: "+this.grouping_type+" not fully parsed")}),BoxParser.createFullBoxCtor("sbgp",function(t){this.grouping_type=t.readString(4),1===this.version?this.grouping_type_parameter=t.readUint32():this.grouping_type_parameter=0,this.entries=[];for(var e=t.readUint32(),i=0;i>6,this.sample_depends_on[r]=e>>4&3,this.sample_is_depended_on[r]=e>>2&3,this.sample_has_redundancy[r]=3&e}),BoxParser.createFullBoxCtor("senc"),BoxParser.createFullBoxCtor("sgpd",function(t){this.grouping_type=t.readString(4),Log.debug("BoxParser","Found Sample Groups of type "+this.grouping_type),1===this.version?this.default_length=t.readUint32():this.default_length=0,2<=this.version&&(this.default_group_description_index=t.readUint32()),this.entries=[];for(var e=t.readUint32(),i=0;i>31&1,r.referenced_size=2147483647&s,r.subsegment_duration=t.readUint32(),s=t.readUint32(),r.starts_with_SAP=s>>31&1,r.SAP_type=s>>28&7,r.SAP_delta_time=268435455&s}}),BoxParser.SingleItemTypeReferenceBox=function(t,e,i,r){BoxParser.Box.call(this,t,e),this.hdr_size=i,this.start=r},BoxParser.SingleItemTypeReferenceBox.prototype=new BoxParser.Box,BoxParser.SingleItemTypeReferenceBox.prototype.parse=function(t){this.from_item_ID=t.readUint16();var e=t.readUint16();this.references=[];for(var i=0;i>4&15,this.sample_sizes[e+1]=15&r}else if(8===this.field_size)for(e=0;e>4&15,this.default_skip_byte_block=15&e),this.default_isProtected=t.readUint8(),this.default_Per_Sample_IV_Size=t.readUint8(),this.default_KID=BoxParser.parseHex16(t),1===this.default_isProtected&&0===this.default_Per_Sample_IV_Size&&(this.default_constant_IV_size=t.readUint8(),this.default_constant_IV=t.readUint8Array(this.default_constant_IV_size))}),BoxParser.createFullBoxCtor("tfdt",function(t){1==this.version?this.baseMediaDecodeTime=t.readUint64():this.baseMediaDecodeTime=t.readUint32()}),BoxParser.createFullBoxCtor("tfhd",function(t){var e=0;this.track_id=t.readUint32(),this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET?(this.base_data_offset=t.readUint64(),e+=8):this.base_data_offset=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_DESC?(this.default_sample_description_index=t.readUint32(),e+=4):this.default_sample_description_index=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_DUR?(this.default_sample_duration=t.readUint32(),e+=4):this.default_sample_duration=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_SIZE?(this.default_sample_size=t.readUint32(),e+=4):this.default_sample_size=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TFHD_FLAG_SAMPLE_FLAGS?(this.default_sample_flags=t.readUint32(),e+=4):this.default_sample_flags=0}),BoxParser.createFullBoxCtor("tfra",function(t){this.track_ID=t.readUint32(),t.readUint24();var e=t.readUint8();this.length_size_of_traf_num=e>>4&3,this.length_size_of_trun_num=e>>2&3,this.length_size_of_sample_num=3&e,this.entries=[];for(var i=t.readUint32(),r=0;r>8,t.readUint16(),this.matrix=t.readInt32Array(9),this.width=t.readUint32(),this.height=t.readUint32()}),BoxParser.createBoxCtor("tmax",function(t){this.time=t.readUint32()}),BoxParser.createBoxCtor("tmin",function(t){this.time=t.readUint32()}),BoxParser.createBoxCtor("totl",function(t){this.bytessent=t.readUint32()}),BoxParser.createBoxCtor("tpay",function(t){this.bytessent=t.readUint32()}),BoxParser.createBoxCtor("tpyl",function(t){this.bytessent=t.readUint64()}),BoxParser.TrackGroupTypeBox.prototype.parse=function(t){this.parseFullHeader(t),this.track_group_id=t.readUint32()},BoxParser.createTrackGroupCtor("msrc"),BoxParser.TrackReferenceTypeBox=function(t,e,i,r){BoxParser.Box.call(this,t,e),this.hdr_size=i,this.start=r},BoxParser.TrackReferenceTypeBox.prototype=new BoxParser.Box,BoxParser.TrackReferenceTypeBox.prototype.parse=function(t){this.track_ids=t.readUint32Array((this.size-this.hdr_size)/4)},BoxParser.trefBox.prototype.parse=function(t){for(var e;t.getPosition()e&&this.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET?(this.data_offset=t.readInt32(),e+=4):this.data_offset=0,this.size-this.hdr_size>e&&this.flags&BoxParser.TRUN_FLAGS_FIRST_FLAG?(this.first_sample_flags=t.readUint32(),e+=4):this.first_sample_flags=0,this.sample_duration=[],this.sample_size=[],this.sample_flags=[],this.sample_composition_time_offset=[],this.size-this.hdr_size>e)for(var i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}),BoxParser.createUUIDBox("d08a4f1810f34a82b6c832d8aba183d3",!0,!1,function(t){this.system_id=BoxParser.parseHex16(t);var e=t.readUint32();0>4,this.chromaSubsampling=e>>1&7,this.videoFullRangeFlag=1&e,this.colourPrimaries=t.readUint8(),this.transferCharacteristics=t.readUint8(),this.matrixCoefficients=t.readUint8()):(this.profile=t.readUint8(),this.level=t.readUint8(),e=t.readUint8(),this.bitDepth=e>>4&15,this.colorSpace=15&e,e=t.readUint8(),this.chromaSubsampling=e>>4&15,this.transferFunction=e>>1&7,this.videoFullRangeFlag=1&e),this.codecIntializationDataSize=t.readUint16(),this.codecIntializationData=t.readUint8Array(this.codecIntializationDataSize)}),BoxParser.createBoxCtor("vttC",function(t){this.text=t.readString(this.size-this.hdr_size)}),BoxParser.createFullBoxCtor("vvcC",function(t){var e,i={held_bits:void 0,num_held_bits:0,stream_read_1_bytes:function(t){this.held_bits=t.readUint8(),this.num_held_bits=8},stream_read_2_bytes:function(t){this.held_bits=t.readUint16(),this.num_held_bits=16},extract_bits:function(t){var e=this.held_bits>>this.num_held_bits-t&(1<>=1;t+=BoxParser.decimalToHex(i,0),t+=".",0===this.hvcC.general_tier_flag?t+="L":t+="H",t+=this.hvcC.general_level_idc;var s=!1,a="";for(r=5;0<=r;r--)(this.hvcC.general_constraint_indicator[r]||s)&&(a="."+BoxParser.decimalToHex(this.hvcC.general_constraint_indicator[r],0)+a,s=!0);t+=a}return t},BoxParser.vvc1SampleEntry.prototype.getCodec=BoxParser.vvi1SampleEntry.prototype.getCodec=function(){var t=BoxParser.SampleEntry.prototype.getCodec.call(this);if(this.vvcC){t+="."+this.vvcC.general_profile_idc,this.vvcC.general_tier_flag?t+=".H":t+=".L",t+=this.vvcC.general_level_idc;var e="";if(this.vvcC.general_constraint_info){var i,r=[],s=0;for(s|=this.vvcC.ptl_frame_only_constraint<<7,s|=this.vvcC.ptl_multilayer_enabled<<6,h=0;h>2&63,r.push(s),s&&(i=h),s=this.vvcC.general_constraint_info[h]>>2&3;if(void 0===i)e=".CA";else{e=".C";for(var a="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",n=0,o=0,h=0;h<=i;++h)for(n=n<<8|r[h],o+=8;5<=o;)e+=a[n>>o-5&31],n&=(1<<(o-=5))-1;o&&(e+=a[31&(n<<=5-o)])}}t+=e}return t},BoxParser.mp4aSampleEntry.prototype.getCodec=function(){var t=BoxParser.SampleEntry.prototype.getCodec.call(this);if(this.esds&&this.esds.esd){var e=this.esds.esd.getOTI(),i=this.esds.esd.getAudioConfig();return t+"."+BoxParser.decimalToHex(e)+(i?"."+i:"")}return t},BoxParser.stxtSampleEntry.prototype.getCodec=function(){var t=BoxParser.SampleEntry.prototype.getCodec.call(this);return this.mime_format?t+"."+this.mime_format:t},BoxParser.vp08SampleEntry.prototype.getCodec=BoxParser.vp09SampleEntry.prototype.getCodec=function(){var t=BoxParser.SampleEntry.prototype.getCodec.call(this),e=this.vpcC.level;0==e&&(e="00");var i=this.vpcC.bitDepth;return 8==i&&(i="08"),t+".0"+this.vpcC.profile+"."+e+"."+i},BoxParser.av01SampleEntry.prototype.getCodec=function(){var t,e=BoxParser.SampleEntry.prototype.getCodec.call(this),i=this.av1C.seq_level_idx_0;return i<10&&(i="0"+i),2===this.av1C.seq_profile&&1===this.av1C.high_bitdepth?t=1===this.av1C.twelve_bit?"12":"10":this.av1C.seq_profile<=2&&(t=1===this.av1C.high_bitdepth?"10":"08"),e+"."+this.av1C.seq_profile+"."+i+(this.av1C.seq_tier_0?"H":"M")+"."+t},BoxParser.Box.prototype.writeHeader=function(t,e){this.size+=8,this.size>MAX_SIZE&&(this.size+=8),"uuid"===this.type&&(this.size+=16),Log.debug("BoxWriter","Writing box "+this.type+" of size: "+this.size+" at position "+t.getPosition()+(e||"")),this.size>MAX_SIZE?t.writeUint32(1):(this.sizePosition=t.getPosition(),t.writeUint32(this.size)),t.writeString(this.type,null,4),"uuid"===this.type&&t.writeUint8Array(this.uuid),this.size>MAX_SIZE&&t.writeUint64(this.size)},BoxParser.FullBox.prototype.writeHeader=function(t){this.size+=4,BoxParser.Box.prototype.writeHeader.call(this,t," v="+this.version+" f="+this.flags),t.writeUint8(this.version),t.writeUint24(this.flags)},BoxParser.Box.prototype.write=function(t){"mdat"===this.type?this.data&&(this.size=this.data.length,this.writeHeader(t),t.writeUint8Array(this.data)):(this.size=this.data?this.data.length:0,this.writeHeader(t),this.data&&t.writeUint8Array(this.data))},BoxParser.ContainerBox.prototype.write=function(t){this.size=0,this.writeHeader(t);for(var e=0;ee?1:0,this.flags=0,this.size=4,1===this.version&&(this.size+=4),this.writeHeader(t),1===this.version?t.writeUint64(this.baseMediaDecodeTime):t.writeUint32(this.baseMediaDecodeTime)},BoxParser.tfhdBox.prototype.write=function(t){this.version=0,this.size=4,this.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET&&(this.size+=8),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DESC&&(this.size+=4),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DUR&&(this.size+=4),this.flags&BoxParser.TFHD_FLAG_SAMPLE_SIZE&&(this.size+=4),this.flags&BoxParser.TFHD_FLAG_SAMPLE_FLAGS&&(this.size+=4),this.writeHeader(t),t.writeUint32(this.track_id),this.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET&&t.writeUint64(this.base_data_offset),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DESC&&t.writeUint32(this.default_sample_description_index),this.flags&BoxParser.TFHD_FLAG_SAMPLE_DUR&&t.writeUint32(this.default_sample_duration),this.flags&BoxParser.TFHD_FLAG_SAMPLE_SIZE&&t.writeUint32(this.default_sample_size),this.flags&BoxParser.TFHD_FLAG_SAMPLE_FLAGS&&t.writeUint32(this.default_sample_flags)},BoxParser.tkhdBox.prototype.write=function(t){this.version=0,this.size=80,this.writeHeader(t),t.writeUint32(this.creation_time),t.writeUint32(this.modification_time),t.writeUint32(this.track_id),t.writeUint32(0),t.writeUint32(this.duration),t.writeUint32(0),t.writeUint32(0),t.writeInt16(this.layer),t.writeInt16(this.alternate_group),t.writeInt16(this.volume<<8),t.writeUint16(0),t.writeInt32Array(this.matrix),t.writeUint32(this.width),t.writeUint32(this.height)},BoxParser.trexBox.prototype.write=function(t){this.version=0,this.flags=0,this.size=20,this.writeHeader(t),t.writeUint32(this.track_id),t.writeUint32(this.default_sample_description_index),t.writeUint32(this.default_sample_duration),t.writeUint32(this.default_sample_size),t.writeUint32(this.default_sample_flags)},BoxParser.trunBox.prototype.write=function(t){this.version=0,this.size=4,this.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET&&(this.size+=4),this.flags&BoxParser.TRUN_FLAGS_FIRST_FLAG&&(this.size+=4),this.flags&BoxParser.TRUN_FLAGS_DURATION&&(this.size+=4*this.sample_duration.length),this.flags&BoxParser.TRUN_FLAGS_SIZE&&(this.size+=4*this.sample_size.length),this.flags&BoxParser.TRUN_FLAGS_FLAGS&&(this.size+=4*this.sample_flags.length),this.flags&BoxParser.TRUN_FLAGS_CTS_OFFSET&&(this.size+=4*this.sample_composition_time_offset.length),this.writeHeader(t),t.writeUint32(this.sample_count),this.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET&&(this.data_offset_position=t.getPosition(),t.writeInt32(this.data_offset)),this.flags&BoxParser.TRUN_FLAGS_FIRST_FLAG&&t.writeUint32(this.first_sample_flags);for(var e=0;e=e?t:new Array(e-t.length+1).join(i)+t}function r(t){var e=Math.floor(t/3600),i=Math.floor((t-3600*e)/60),r=Math.floor(t-3600*e-60*i),t=Math.floor(1e3*(t-3600*e-60*i-r));return s(e,2)+":"+s(i,2)+":"+s(r,2)+"."+s(t,3)}for(var a=this.parseSample(i),n="",o=0;o=r.samples.length)&&(Log.info("ISOFile","Sending fragmented data on track #"+i.id+" for samples ["+Math.max(0,r.nextSample-i.nb_samples)+","+(r.nextSample-1)+"]"),Log.info("ISOFile","Sample data size in memory: "+this.getAllocatedSampleDataSize()),this.onSegment&&this.onSegment(i.id,i.user,i.segmentStream.buffer,r.nextSample,t||r.nextSample>=r.samples.length),i.segmentStream=null,i!==this.fragmentedTracks[e]))break}if(null!==this.onSamples)for(e=0;e=r.samples.length)&&(Log.debug("ISOFile","Sending samples on track #"+a.id+" for sample "+r.nextSample),this.onSamples&&this.onSamples(a.id,a.user,a.samples),a.samples=[],a!==this.extractedTracks[e]))break}}}},ISOFile.prototype.getBox=function(t){t=this.getBoxes(t,!0);return t.length?t[0]:null},ISOFile.prototype.getBoxes=function(t,e){var i=[];return ISOFile._sweep.call(this,t,i,e),i},ISOFile._sweep=function(t,e,i){for(var r in this.type&&this.type==t&&e.push(this),this.boxes){if(e.length&&i)return;ISOFile._sweep.call(this.boxes[r],t,e,i)}},ISOFile.prototype.getTrackSamplesInfo=function(t){t=this.getTrackById(t);if(t)return t.samples},ISOFile.prototype.getTrackSample=function(t,e){t=this.getTrackById(t);return this.getSample(t,e)},ISOFile.prototype.releaseUsedSamples=function(t,e){var i=0,r=this.getTrackById(t);r.lastValidSample||(r.lastValidSample=0);for(var s=r.lastValidSample;st*s.timescale){h=r-1;break}e&&s.is_sync&&(o=r)}for(e&&(h=o),t=i.samples[h].cts,i.nextSample=h;i.samples[h].alreadyRead===i.samples[h].size&&i.samples[h+1];)h++;return a=i.samples[h].offset+i.samples[h].alreadyRead,Log.info("ISOFile","Seeking to "+(e?"RAP":"")+" sample #"+i.nextSample+" on track "+i.tkhd.track_id+", time "+Log.getDurationString(t,n)+" and offset: "+a),{offset:a,time:t/n}},ISOFile.prototype.seek=function(t,e){var i,r,s=this.moov,a={offset:1/0,time:1/0};if(this.moov){for(r=0;r=r[s].last_sample_in_run&&(r[s].last_sample_in_run<0&&(r[s].last_sample_in_run=0),r[s].entry_index++,r[s].entry_index<=r[s].sbgp.entries.length-1&&(r[s].last_sample_in_run+=r[s].sbgp.entries[r[s].entry_index].sample_count)),r[s].entry_index<=r[s].sbgp.entries.length-1?e.sample_groups[s].group_description_index=r[s].sbgp.entries[r[s].entry_index].group_description_index:e.sample_groups[s].group_description_index=-1,0!==e.sample_groups[s].group_description_index&&(n=r[s].fragment_description||r[s].description,0>16)-1:e.sample_groups[s].group_description_index-1,n&&0<=a&&(e.sample_groups[s].description=n.entries[a])):n&&2<=n.version&&0>16&1),p.is_leading=g>>26&3,p.depends_on=g>>24&3,p.is_depended_on=g>>22&3,p.has_redundancy=g>>20&3,p.degradation_priority=65535&g;var _=!!(h.tfhd.flags&BoxParser.TFHD_FLAG_BASE_DATA_OFFSET),c=!!(h.tfhd.flags&BoxParser.TFHD_FLAG_DEFAULT_BASE_IS_MOOF),m=!!(f.flags&BoxParser.TRUN_FLAGS_DATA_OFFSET),g=0,g=_?h.tfhd.base_data_offset:c||0===y?o.start:a;p.offset=0===y&&0===u?m?g+f.data_offset:g:a,a=p.offset+p.size,(0MAX_SIZE&&(this.size+=8),"uuid"===this.type&&(this.size+=16),t.log(t.indent+"size:"+this.size),t.log(t.indent+"type:"+this.type)},BoxParser.FullBox.prototype.printHeader=function(t){this.size+=4,BoxParser.Box.prototype.printHeader.call(this,t),t.log(t.indent+"version:"+this.version),t.log(t.indent+"flags:"+this.flags)},BoxParser.Box.prototype.print=function(t){this.printHeader(t)},BoxParser.ContainerBox.prototype.print=function(t){this.printHeader(t);for(var e,i=0;i>8)),t.log(t.indent+"matrix: "+this.matrix.join(", ")),t.log(t.indent+"next_track_id: "+this.next_track_id)},BoxParser.tkhdBox.prototype.print=function(t){BoxParser.FullBox.prototype.printHeader.call(this,t),t.log(t.indent+"creation_time: "+this.creation_time),t.log(t.indent+"modification_time: "+this.modification_time),t.log(t.indent+"track_id: "+this.track_id),t.log(t.indent+"duration: "+this.duration),t.log(t.indent+"volume: "+(this.volume>>8)),t.log(t.indent+"matrix: "+this.matrix.join(", ")),t.log(t.indent+"layer: "+this.layer),t.log(t.indent+"alternate_group: "+this.alternate_group),t.log(t.indent+"width: "+this.width),t.log(t.indent+"height: "+this.height)};var MP4Box={createFile:function(t,e){t=void 0===t||t,e=new ISOFile(e);return e.discardMdatData=!t,e}};"undefined"!=typeof exports&&(exports.createFile=MP4Box.createFile); diff --git a/samples/third_party/ringbufjs/LICENSE b/samples/third_party/ringbufjs/LICENSE new file mode 100644 index 00000000..a612ad98 --- /dev/null +++ b/samples/third_party/ringbufjs/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/samples/third_party/ringbufjs/ringbuf.js b/samples/third_party/ringbufjs/ringbuf.js new file mode 100644 index 00000000..c782b0a4 --- /dev/null +++ b/samples/third_party/ringbufjs/ringbuf.js @@ -0,0 +1,195 @@ +// A Single Producer - Single Consumer thread-safe wait-free ring buffer. +// +// The producer and the consumer can be on separate threads, but cannot change roles, +// except with external synchronization. + +export class RingBuffer { + static getStorageForCapacity(capacity, type) { + if (!type.BYTES_PER_ELEMENT) { + throw "Pass in a ArrayBuffer subclass"; + } + var bytes = 8 + (capacity + 1) * type.BYTES_PER_ELEMENT; + return new SharedArrayBuffer(bytes); + } + // `sab` is a SharedArrayBuffer with a capacity calculated by calling + // `getStorageForCapacity` with the desired capacity. + constructor(sab, type) { + if (!ArrayBuffer.__proto__.isPrototypeOf(type) && + type.BYTES_PER_ELEMENT !== undefined) { + throw "Pass a concrete typed array class as second argument"; + } + + // Maximum usable size is 1<<32 - type.BYTES_PER_ELEMENT bytes in the ring + // buffer for this version, easily changeable. + // -4 for the write ptr (uint32_t offsets) + // -4 for the read ptr (uint32_t offsets) + // capacity counts the empty slot to distinguish between full and empty. + this._type = type; + this._capacity = (sab.byteLength - 8) / type.BYTES_PER_ELEMENT; + this.buf = sab; + this.write_ptr = new Uint32Array(this.buf, 0, 1); + this.read_ptr = new Uint32Array(this.buf, 4, 1); + this.storage = new type(this.buf, 8, this._capacity); + } + // Returns the type of the underlying ArrayBuffer for this RingBuffer. This + // allows implementing crude type checking. + type() { + return this._type.name; + } + // Push bytes to the ring buffer. `elements` is a typed array of the same type + // as passed in the ctor, to be written to the queue. + // Returns the number of elements written to the queue. + push(elements) { + var rd = Atomics.load(this.read_ptr, 0); + var wr = Atomics.load(this.write_ptr, 0); + + if ((wr + 1) % this._storage_capacity() == rd) { + // full + return 0; + } + + let to_write = Math.min(this._available_write(rd, wr), elements.length); + let first_part = Math.min(this._storage_capacity() - wr, to_write); + let second_part = to_write - first_part; + + this._copy(elements, 0, this.storage, wr, first_part); + this._copy(elements, first_part, this.storage, 0, second_part); + + // publish the enqueued data to the other side + Atomics.store( + this.write_ptr, + 0, + (wr + to_write) % this._storage_capacity() + ); + + return to_write; + } + + // Write bytes to the ring buffer using callbacks. This create wrapper + // objects and can GC, so it's best to no use this variant from a real-time + // thread such as an AudioWorklerProcessor `process` method. + // The callback is passed two typed arrays of the same type, to be filled. + // This allows skipping copies if the API that produces the data writes is + // passed arrays to write to, such as `AudioData.copyTo`. + writeCallback(amount, cb) { + var rd = Atomics.load(this.read_ptr, 0); + var wr = Atomics.load(this.write_ptr, 0); + + if ((wr + 1) % this._storage_capacity() == rd) { + // full + return 0; + } + + let to_write = Math.min(this._available_write(rd, wr), amount); + let first_part = Math.min(this._storage_capacity() - wr, to_write); + let second_part = to_write - first_part; + + // This part will cause GC: don't use in the real time thread. + var first_part_buf = new this._type(this.storage.buffer, 8 + wr * 4, first_part); + var second_part_buf = new this._type(this.storage.buffer, 8 + 0, second_part); + + cb(first_part_buf, second_part_buf); + + // publish the enqueued data to the other side + Atomics.store( + this.write_ptr, + 0, + (wr + to_write) % this._storage_capacity() + ); + + return to_write; + } + + // Read `elements.length` elements from the ring buffer. `elements` is a typed + // array of the same type as passed in the ctor. + // Returns the number of elements read from the queue, they are placed at the + // beginning of the array passed as parameter. + pop(elements) { + var rd = Atomics.load(this.read_ptr, 0); + var wr = Atomics.load(this.write_ptr, 0); + + if (wr == rd) { + return 0; + } + + let to_read = Math.min(this._available_read(rd, wr), elements.length); + + let first_part = Math.min(this._storage_capacity() - rd, to_read); + let second_part = to_read - first_part; + + this._copy(this.storage, rd, elements, 0, first_part); + this._copy(this.storage, 0, elements, first_part, second_part); + + Atomics.store(this.read_ptr, 0, (rd + to_read) % this._storage_capacity()); + + return to_read; + } + + // True if the ring buffer is empty false otherwise. This can be late on the + // reader side: it can return true even if something has just been pushed. + empty() { + var rd = Atomics.load(this.read_ptr, 0); + var wr = Atomics.load(this.write_ptr, 0); + + return wr == rd; + } + + // True if the ring buffer is full, false otherwise. This can be late on the + // write side: it can return true when something has just been popped. + full() { + var rd = Atomics.load(this.read_ptr, 0); + var wr = Atomics.load(this.write_ptr, 0); + + return (wr + 1) % this._storage_capacity() == rd; + } + + // The usable capacity for the ring buffer: the number of elements that can be + // stored. + capacity() { + return this._capacity - 1; + } + + // Number of elements available for reading. This can be late, and report less + // elements that is actually in the queue, when something has just been + // enqueued. + available_read() { + var rd = Atomics.load(this.read_ptr, 0); + var wr = Atomics.load(this.write_ptr, 0); + return this._available_read(rd, wr); + } + + // Number of elements available for writing. This can be late, and report less + // elements that is actually available for writing, when something has just + // been dequeued. + available_write() { + var rd = Atomics.load(this.read_ptr, 0); + var wr = Atomics.load(this.write_ptr, 0); + return this._available_write(rd, wr); + } + + // private methods // + + // Number of elements available for reading, given a read and write pointer.. + _available_read(rd, wr) { + return (wr + this._storage_capacity() - rd) % this._storage_capacity(); + } + + // Number of elements available from writing, given a read and write pointer. + _available_write(rd, wr) { + return this.capacity() - this._available_read(rd, wr); + } + + // The size of the storage for elements not accounting the space for the + // index, counting the empty slot. + _storage_capacity() { + return this._capacity; + } + + // Copy `size` elements from `input`, starting at offset `offset_input`, to + // `output`, starting at offset `offset_output`. + _copy(input, offset_input, output, offset_output, size) { + for (var i = 0; i < size; i++) { + output[offset_output + i] = input[offset_input + i]; + } + } +} diff --git a/samples/video-decode-display/demuxer_mp4.js b/samples/video-decode-display/demuxer_mp4.js new file mode 100644 index 00000000..d2cd49a6 --- /dev/null +++ b/samples/video-decode-display/demuxer_mp4.js @@ -0,0 +1,107 @@ +importScripts("../third_party/mp4boxjs/mp4box.all.min.js"); + +// Wraps an MP4Box File as a WritableStream underlying sink. +class MP4FileSink { + #setStatus = null; + #file = null; + #offset = 0; + + constructor(file, setStatus) { + this.#file = file; + this.#setStatus = setStatus; + } + + write(chunk) { + // MP4Box.js requires buffers to be ArrayBuffers, but we have a Uint8Array. + const buffer = new ArrayBuffer(chunk.byteLength); + new Uint8Array(buffer).set(chunk); + + // Inform MP4Box where in the file this chunk is from. + buffer.fileStart = this.#offset; + this.#offset += buffer.byteLength; + + // Append chunk. + this.#setStatus("fetch", (this.#offset / (1024 ** 2)).toFixed(1) + " MiB"); + this.#file.appendBuffer(buffer); + } + + close() { + this.#setStatus("fetch", "Done"); + this.#file.flush(); + } +} + +// Demuxes the first video track of an MP4 file using MP4Box, calling +// `onConfig()` and `onChunk()` with appropriate WebCodecs objects. +class MP4Demuxer { + #onConfig = null; + #onChunk = null; + #setStatus = null; + #file = null; + + constructor(uri, {onConfig, onChunk, setStatus}) { + this.#onConfig = onConfig; + this.#onChunk = onChunk; + this.#setStatus = setStatus; + + // Configure an MP4Box File for demuxing. + this.#file = MP4Box.createFile(); + this.#file.onError = error => setStatus("demux", error); + this.#file.onReady = this.#onReady.bind(this); + this.#file.onSamples = this.#onSamples.bind(this); + + // Fetch the file and pipe the data through. + const fileSink = new MP4FileSink(this.#file, setStatus); + fetch(uri).then(response => { + // highWaterMark should be large enough for smooth streaming, but lower is + // better for memory usage. + response.body.pipeTo(new WritableStream(fileSink, {highWaterMark: 2})); + }); + } + + // Get the appropriate `description` for a specific track. Assumes that the + // track is H.264, H.265, VP8, VP9, or AV1. + #description(track) { + const trak = this.#file.getTrackById(track.id); + for (const entry of trak.mdia.minf.stbl.stsd.entries) { + const box = entry.avcC || entry.hvcC || entry.vpcC || entry.av1C; + if (box) { + const stream = new DataStream(undefined, 0, DataStream.BIG_ENDIAN); + box.write(stream); + return new Uint8Array(stream.buffer, 8); // Remove the box header. + } + } + throw new Error("avcC, hvcC, vpcC, or av1C box not found"); + } + + #onReady(info) { + this.#setStatus("demux", "Ready"); + const track = info.videoTracks[0]; + + // Generate and emit an appropriate VideoDecoderConfig. + this.#onConfig({ + // Browser doesn't support parsing full vp8 codec (eg: `vp08.00.41.08`), + // they only support `vp8`. + codec: track.codec.startsWith('vp08') ? 'vp8' : track.codec, + codedHeight: track.video.height, + codedWidth: track.video.width, + description: this.#description(track), + }); + + // Start demuxing. + this.#file.setExtractionOptions(track.id); + this.#file.start(); + } + + #onSamples(track_id, ref, samples) { + // Generate and emit an EncodedVideoChunk for each demuxed sample. + for (const sample of samples) { + this.#onChunk(new EncodedVideoChunk({ + type: sample.is_sync ? "key" : "delta", + timestamp: 1e6 * sample.cts / sample.timescale, + duration: 1e6 * sample.duration / sample.timescale, + data: sample.data + })); + } + } +} diff --git a/samples/video-decode-display/index.html b/samples/video-decode-display/index.html new file mode 100644 index 00000000..d981c015 --- /dev/null +++ b/samples/video-decode-display/index.html @@ -0,0 +1,101 @@ + + + + WebCodec MP4 decode sample + + +

+ This demo decodes all frames from an MP4 file and renders them to a canvas as fast as possible. + It uses mp4box.js for demuxing. +

+ +

+ Note: The WebGPU rendering mode is not yet available in all browsers. + As of M108, Chrome requires the --enable-unsafe-webgpu flag. +

+ +

+ Renderer: + + + + +

+ +

+ Video Codec: + + + + + +

+ +

+ +

+ + + + + + +
FetchNot started
DemuxNot started
DecodeNot started
RenderNot started
+ + + + + + + diff --git a/samples/video-decode-display/renderer_2d.js b/samples/video-decode-display/renderer_2d.js new file mode 100644 index 00000000..3e101113 --- /dev/null +++ b/samples/video-decode-display/renderer_2d.js @@ -0,0 +1,16 @@ +class Canvas2DRenderer { + #canvas = null; + #ctx = null; + + constructor(canvas) { + this.#canvas = canvas; + this.#ctx = canvas.getContext("2d"); + } + + draw(frame) { + this.#canvas.width = frame.displayWidth; + this.#canvas.height = frame.displayHeight; + this.#ctx.drawImage(frame, 0, 0, frame.displayWidth, frame.displayHeight); + frame.close(); + } +}; diff --git a/samples/video-decode-display/renderer_webgl.js b/samples/video-decode-display/renderer_webgl.js new file mode 100644 index 00000000..f4af5c2c --- /dev/null +++ b/samples/video-decode-display/renderer_webgl.js @@ -0,0 +1,96 @@ +class WebGLRenderer { + #canvas = null; + #ctx = null; + + static vertexShaderSource = ` + attribute vec2 xy; + + varying highp vec2 uv; + + void main(void) { + gl_Position = vec4(xy, 0.0, 1.0); + // Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1). + // UV coordinates are Y-flipped relative to vertex coordinates. + uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0); + } + `; + + static fragmentShaderSource = ` + varying highp vec2 uv; + + uniform sampler2D texture; + + void main(void) { + gl_FragColor = texture2D(texture, uv); + } + `; + + constructor(type, canvas) { + this.#canvas = canvas; + const gl = this.#ctx = canvas.getContext(type); + + const vertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vertexShader, WebGLRenderer.vertexShaderSource); + gl.compileShader(vertexShader); + if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { + throw gl.getShaderInfoLog(vertexShader); + } + + const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fragmentShader, WebGLRenderer.fragmentShaderSource); + gl.compileShader(fragmentShader); + if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { + throw gl.getShaderInfoLog(fragmentShader); + } + + const shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram (shaderProgram ); + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + throw gl.getProgramInfoLog(shaderProgram); + } + gl.useProgram(shaderProgram); + + // Vertex coordinates, clockwise from bottom-left. + const vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + -1.0, -1.0, + -1.0, +1.0, + +1.0, +1.0, + +1.0, -1.0 + ]), gl.STATIC_DRAW); + + const xyLocation = gl.getAttribLocation(shaderProgram, "xy"); + gl.vertexAttribPointer(xyLocation, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(xyLocation); + + // Create one texture to upload frames to. + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + } + + draw(frame) { + this.#canvas.width = frame.displayWidth; + this.#canvas.height = frame.displayHeight; + + const gl = this.#ctx; + + // Upload the frame. + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame); + frame.close(); + + // Configure and clear the drawing area. + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + gl.clearColor(1.0, 0.0, 0.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Draw the frame. + gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); + } +}; diff --git a/samples/video-decode-display/renderer_webgpu.js b/samples/video-decode-display/renderer_webgpu.js new file mode 100644 index 00000000..f2dbadaa --- /dev/null +++ b/samples/video-decode-display/renderer_webgpu.js @@ -0,0 +1,133 @@ +class WebGPURenderer { + #canvas = null; + #ctx = null; + + // Promise for `#start()`, WebGPU setup is asynchronous. + #started = null; + + // WebGPU state shared between setup and drawing. + #format = null; + #device = null; + #pipeline = null; + #sampler = null; + + // Generates two triangles covering the whole canvas. + static vertexShaderSource = ` + struct VertexOutput { + @builtin(position) Position: vec4, + @location(0) uv: vec2, + } + + @vertex + fn vert_main(@builtin(vertex_index) VertexIndex: u32) -> VertexOutput { + var pos = array, 6>( + vec2( 1.0, 1.0), + vec2( 1.0, -1.0), + vec2(-1.0, -1.0), + vec2( 1.0, 1.0), + vec2(-1.0, -1.0), + vec2(-1.0, 1.0) + ); + + var uv = array, 6>( + vec2(1.0, 0.0), + vec2(1.0, 1.0), + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, 0.0) + ); + + var output : VertexOutput; + output.Position = vec4(pos[VertexIndex], 0.0, 1.0); + output.uv = uv[VertexIndex]; + return output; + } + `; + + // Samples the external texture using generated UVs. + static fragmentShaderSource = ` + @group(0) @binding(1) var mySampler: sampler; + @group(0) @binding(2) var myTexture: texture_external; + + @fragment + fn frag_main(@location(0) uv : vec2) -> @location(0) vec4 { + return textureSampleBaseClampToEdge(myTexture, mySampler, uv); + } + `; + + constructor(canvas) { + this.#canvas = canvas; + this.#started = this.#start(); + } + + async #start() { + const adapter = await navigator.gpu.requestAdapter(); + this.#device = await adapter.requestDevice(); + this.#format = navigator.gpu.getPreferredCanvasFormat(); + + this.#ctx = this.#canvas.getContext("webgpu"); + this.#ctx.configure({ + device: this.#device, + format: this.#format, + alphaMode: "opaque", + }); + + this.#pipeline = this.#device.createRenderPipeline({ + layout: "auto", + vertex: { + module: this.#device.createShaderModule({code: WebGPURenderer.vertexShaderSource}), + entryPoint: "vert_main" + }, + fragment: { + module: this.#device.createShaderModule({code: WebGPURenderer.fragmentShaderSource}), + entryPoint: "frag_main", + targets: [{format: this.#format}] + }, + primitive: { + topology: "triangle-list" + } + }); + + // Default sampler configuration is nearset + clamp. + this.#sampler = this.#device.createSampler({}); + } + + async draw(frame) { + // Don't try to draw any frames until the context is configured. + await this.#started; + + this.#canvas.width = frame.displayWidth; + this.#canvas.height = frame.displayHeight; + + const uniformBindGroup = this.#device.createBindGroup({ + layout: this.#pipeline.getBindGroupLayout(0), + entries: [ + {binding: 1, resource: this.#sampler}, + {binding: 2, resource: this.#device.importExternalTexture({source: frame})} + ], + }); + + const commandEncoder = this.#device.createCommandEncoder(); + const textureView = this.#ctx.getCurrentTexture().createView(); + const renderPassDescriptor = { + colorAttachments: [ + { + view: textureView, + clearValue: [1.0, 0.0, 0.0, 1.0], + loadOp: "clear", + storeOp: "store", + }, + ], + }; + + const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); + passEncoder.setPipeline(this.#pipeline); + passEncoder.setBindGroup(0, uniformBindGroup); + passEncoder.draw(6, 1, 0, 0); + passEncoder.end(); + this.#device.queue.submit([commandEncoder.finish()]); + + frame.close(); + } +}; diff --git a/samples/video-decode-display/worker.js b/samples/video-decode-display/worker.js new file mode 100644 index 00000000..c3600b9c --- /dev/null +++ b/samples/video-decode-display/worker.js @@ -0,0 +1,95 @@ +importScripts("demuxer_mp4.js", "renderer_2d.js", "renderer_webgl.js", "renderer_webgpu.js"); + +// Status UI. Messages are batched per animation frame. +let pendingStatus = null; + +function setStatus(type, message) { + if (pendingStatus) { + pendingStatus[type] = message; + } else { + pendingStatus = {[type]: message}; + self.requestAnimationFrame(statusAnimationFrame); + } +} + +function statusAnimationFrame() { + self.postMessage(pendingStatus); + pendingStatus = null; +} + +// Rendering. Drawing is limited to once per animation frame. +let renderer = null; +let pendingFrame = null; +let startTime = null; +let frameCount = 0; + +function renderFrame(frame) { + if (!pendingFrame) { + // Schedule rendering in the next animation frame. + requestAnimationFrame(renderAnimationFrame); + } else { + // Close the current pending frame before replacing it. + pendingFrame.close(); + } + // Set or replace the pending frame. + pendingFrame = frame; +} + +function renderAnimationFrame() { + renderer.draw(pendingFrame); + pendingFrame = null; +} + +// Startup. +function start({dataUri, rendererName, canvas}) { + // Pick a renderer to use. + switch (rendererName) { + case "2d": + renderer = new Canvas2DRenderer(canvas); + break; + case "webgl": + renderer = new WebGLRenderer(rendererName, canvas); + break; + case "webgl2": + renderer = new WebGLRenderer(rendererName, canvas); + break; + case "webgpu": + renderer = new WebGPURenderer(canvas); + break; + } + + // Set up a VideoDecoer. + const decoder = new VideoDecoder({ + output(frame) { + // Update statistics. + if (startTime == null) { + startTime = performance.now(); + } else { + const elapsed = (performance.now() - startTime) / 1000; + const fps = ++frameCount / elapsed; + setStatus("render", `${fps.toFixed(0)} fps`); + } + + // Schedule the frame to be rendered. + renderFrame(frame); + }, + error(e) { + setStatus("decode", e); + } + }); + + // Fetch and demux the media data. + const demuxer = new MP4Demuxer(dataUri, { + onConfig(config) { + setStatus("decode", `${config.codec} @ ${config.codedWidth}x${config.codedHeight}`); + decoder.configure(config); + }, + onChunk(chunk) { + decoder.decode(chunk); + }, + setStatus + }); +} + +// Listen for the start request. +self.addEventListener("message", message => start(message.data), {once: true}); diff --git a/ulaw_codec_registration.src.html b/ulaw_codec_registration.src.html index 64986a4a..339174ae 100644 --- a/ulaw_codec_registration.src.html +++ b/ulaw_codec_registration.src.html @@ -7,16 +7,16 @@ Group: mediawg ED: https://w3c.github.io/webcodecs/ulaw_codec_registration.html TR: https://www.w3.org/TR/webcodecs-ulaw-codec-registration/ -Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/ Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/ +Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/ Abstract: This registration is entered into the [[webcodecs-codec-registry]]. It describes, for u-law encoded PCM, the (1) fully qualified codec strings, (2) the codec-specific {{EncodedAudioChunk}} - [=EncodedAudioChunk/[[internal data]]=] bytes, (3) the - {{AudioDecoderConfig.description}} bytes, and (4) the values of - {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=]. + {{EncodedAudioChunk/[[internal data]]}} bytes, (3) the + {{AudioDecoderConfig/description|AudioDecoderConfig.description}} bytes, + and (4) the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}}. The registration is not intended to include any information on whether a codec format is encumbered by intellectual property claims. Implementers and @@ -32,21 +32,6 @@ !Version History: https://github.com/w3c/webcodecs/commits
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-    type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-        text: AudioEncoderConfig; url: dictdef-audioencoderconfig
-
-
 {
   "ITU-G.711": {
@@ -66,25 +51,30 @@
 EncodedAudioChunk data {#encodedaudiochunk-data}
 ================================================
 
-{{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] is expected to be
+{{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}} is expected to be
 a sequence of bytes of arbitrary length, where each byte is a u-law
 encoded PCM sample as defined by Table 2a and 2b in [[ITU-G.711]].
 
 AudioDecoderConfig description {#audiodecoderconfig-description}
 ================================================================
 
-An {{AudioDecoderConfig.description}} is expected to be omitted from the
+The {{AudioDecoderConfig/description}} is expected to be omitted from the
 {{AudioDecoderConfig}}.
 
 EncodedAudioChunk type {#encodedaudiochunk-type}
 ================================================
 
-The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing
-u-law PCM is always "[=EncodedAudioChunkType/key=]".
+The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing
+u-law PCM is always "{{EncodedAudioChunkType/key}}".
+
+Privacy Considerations {#privacy-considerations}
+==========================================================================
+
+Please refer to the section [[WEBCODECS#privacy-considerations|Privacy
+Considerations]] in [[WEBCODECS]].
 
-Privacy and Security Considerations {#privacy-and-security-considerations}
+Security Considerations {#security-considerations}
 ==========================================================================
 
-Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]]
-and [[WEBCODECS#security-considerations|Security Considerations]] sections in
-[[WEBCODECS]].
+Please refer to the section [[WEBCODECS#security-considerations|Security
+Considerations]] in [[WEBCODECS]].
diff --git a/video_frame_metadata_registry.src.html b/video_frame_metadata_registry.src.html
new file mode 100644
index 00000000..67992a91
--- /dev/null
+++ b/video_frame_metadata_registry.src.html
@@ -0,0 +1,66 @@
+
+
+
+Registration Entry Requirements {#registration-entry-requirements}
+==================================================================
+
+A registration entry is a document describing one or several metadata entries,
+and has the following requirements:
+1. Each metadata entry is defined as a separate {{VideoFrameMetadata}}
+    dictionary member.
+2. Each metadata entry must be serializable.
+3. Each metadata entry must be defined by a W3C specification that has
+    reached consensus in the originating Working Group.
+4. The specification defining each metadata entry must provide clearly defined
+    semantics. In particular, interactions with the media processing pipeline
+    (encoders, decoders, renderers, etc.) should be well defined.
+5. A candidate registration entry must be announced by filing an issue in the
+    WebCodecs GitHub issue tracker so they can be discussed and evaluated for
+    compliance before being added to the registry. If the Media Working Group
+    reaches consensus to accept the candidate, a pull request should be drafted
+    (either by editors or by the party requesting the candidate registration)
+    to register the candidate. The registry editors will review and merge the
+    pull request.
+6. Existing entries may be changed after being published, through the same
+    process as candidate entries. Possible changes include modification of
+    the link to the public specification.
+7. Existing entries may be deprecated. This requires Media Working Group
+    consensus, and if still active, consensus of the Working Group that
+    originated the registration entry specification.
+
+
+VideoFrameMetadata members {#videoframemetadata-members}
+========================================================
+
+
+Privacy Considerations {#privacy-considerations}
+================================================
+
+Please refer to the section [[WEBCODECS#privacy-considerations|Privacy
+Considerations]] in [[WEBCODECS]].
+
+Security Considerations {#security-considerations}
+==================================================
+
+Please refer to the section [[WEBCODECS#security-considerations|Security
+Considerations]] in [[WEBCODECS]].
diff --git a/vorbis_codec_registration.src.html b/vorbis_codec_registration.src.html
index 211420f9..88b9e222 100644
--- a/vorbis_codec_registration.src.html
+++ b/vorbis_codec_registration.src.html
@@ -7,16 +7,16 @@
 Group: mediawg
 ED: https://w3c.github.io/webcodecs/vorbis_codec_registration.html
 TR: https://www.w3.org/TR/webcodecs-vorbis-codec-registration/
-Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/
 Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/
+Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 
 Abstract: This registration is entered into the [[webcodecs-codec-registry]].
     It describes, for Vorbis, the (1) fully qualified codec strings,
     (2) the codec-specific {{EncodedAudioChunk}}
-    [=EncodedAudioChunk/[[internal data]]=] bytes, (3) the
-    {{AudioDecoderConfig.description}} bytes, and (4) the values of
-    {{EncodedAudioChunk}} [=EncodedAudioChunk/[[type]]=].
+    {{EncodedAudioChunk/[[internal data]]}} bytes, (3) the
+    {{AudioDecoderConfig/description|AudioDecoderConfig.description}} bytes,
+    and (4) the values of {{EncodedAudioChunk}} {{EncodedAudioChunk/[[type]]}}.
 
     The registration is not intended to include any information on whether a
     codec format is encumbered by intellectual property claims. Implementers and
@@ -32,22 +32,6 @@
 !Version History: https://github.com/w3c/webcodecs/commits
 
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: AudioDecoderConfig.description; url: dom-audiodecoderconfig-description
-        text: AudioDecoderConfig.sampleRate; url: dom-audiodecoderconfig-samplerate
-        text: AudioDecoderConfig.numberOfChannels; url: dom-audiodecoderconfig-numberofchannels
-    type: dfn
-        for: EncodedAudioChunkType; text: key; url: dom-encodedaudiochunktype-key
-        for: EncodedAudioChunk; text: [[internal data]]; url: dom-encodedaudiochunk-internal-data-slot
-        for: EncodedAudioChunk; text: [[type]]; url: dom-encodedaudiochunk-type-slot
-    type: interface
-        text: EncodedAudioChunk; url: encodedaudiochunk
-    type: dictionary
-        text: AudioDecoderConfig; url: dictdef-audiodecoderconfig
-
-
 {
   "VORBIS": {
@@ -72,20 +56,20 @@
 EncodedAudioChunk data {#encodedaudiochunk-data}
 ================================================
 
-{{EncodedAudioChunk}} [=EncodedAudioChunk/[[internal data]]=] is expected to be
+{{EncodedAudioChunk}} {{EncodedAudioChunk/[[internal data]]}} is expected to be
 an "audio packet", as described in the section 4.3 of the [[VORBIS]] specification.
 
 AudioDecoderConfig description {#audiodecoderconfig-description}
 ================================================================
 
-{{AudioDecoderConfig.description}} is required. It is assumed to be in Xiph
+The {{AudioDecoderConfig/description}} is required. It is assumed to be in Xiph
 extradata format, described in [[OGG-FRAMING]]. This format consists in the
 `page_segments` field, followed by the `segment_table` field, followed by the
 three Vorbis header packets, respectively the identification header, the comments
 header, and the setup header, in this order, as described in section 4.2 of
 [[VORBIS]].
 
-The {{AudioDecoderConfig.sampleRate}} and {{AudioDecoderConfig.numberOfChannels}}
+The {{AudioDecoderConfig/sampleRate}} and {{AudioDecoderConfig/numberOfChannels}}
 members are overridden by what the decoder finds in the identification header.
 
 NOTE: The comments header content is not used by [[WEBCODECS]].
@@ -93,15 +77,20 @@
 EncodedAudioChunk type {#encodedaudiochunk-type}
 ================================================
 
-The [=EncodedAudioChunk/[[type]]=] for an {{EncodedAudioChunk}} containing
-Vorbis is always "[=EncodedAudioChunkType/key=]".
+The {{EncodedAudioChunk/[[type]]}} for an {{EncodedAudioChunk}} containing
+Vorbis is always "{{EncodedAudioChunkType/key}}".
 
 NOTE: Once the initialization has succeeded, any Vorbis packet can be decoded at
 any time without error, but this might not result in the expected audio output.
 
-Privacy and Security Considerations {#privacy-and-security-considerations}
+Privacy Considerations {#privacy-considerations}
+==========================================================================
+
+Please refer to the section [[WEBCODECS#privacy-considerations|Privacy
+Considerations]] in [[WEBCODECS]].
+
+Security Considerations {#security-considerations}
 ==========================================================================
 
-Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]]
-and [[WEBCODECS#security-considerations|Security Considerations]] sections in
-[[WEBCODECS]].
+Please refer to the section [[WEBCODECS#security-considerations|Security
+Considerations]] in [[WEBCODECS]].
diff --git a/vp8_codec_registration.src.html b/vp8_codec_registration.src.html
index 87027931..87754e03 100644
--- a/vp8_codec_registration.src.html
+++ b/vp8_codec_registration.src.html
@@ -7,16 +7,16 @@
 Group: mediawg
 ED: https://w3c.github.io/webcodecs/vp8_codec_registration.html
 TR: https://www.w3.org/TR/webcodecs-vp8-codec-registration/
-Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/
 Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/
+Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 
 Abstract: This registration is entered into the [[webcodecs-codec-registry]].
     It describes, for VP8, the (1) fully qualified codec strings,
     (2) the codec-specific {{EncodedVideoChunk}}
-    [=EncodedVideoChunk/[[internal data]]=] bytes, (3) the
-    {{VideoDecoderConfig.description}} bytes, and (4) the values of
-    {{EncodedVideoChunk}} [=EncodedVideoChunk/[[type]]=].
+    {{EncodedVideoChunk/[[internal data]]}} bytes, (3) the
+    {{VideoDecoderConfig/description|VideoDecoderConfig.description}} bytes,
+    and (4) the values of {{EncodedVideoChunk}} {{EncodedVideoChunk/[[type]]}}.
 
     The registration is not intended to include any information on whether a
     codec format is encumbered by intellectual property claims. Implementers and
@@ -32,24 +32,6 @@
 !Version History: https://github.com/w3c/webcodecs/commits
 
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: EncodedVideoChunkMetadata.decoderConfig; url: dom-encodedvideochunkmetadata-decoderconfig
-        for: EncodedVideoChunkType; text: key; url: dom-encodedvideochunktype-key
-        text: VideoDecoderConfig.description; url: dom-videodecoderconfig-description
-    type: dfn
-        for: EncodedVideoChunk; text: [[internal data]]; url: dom-encodedvideochunk-internal-data-slot
-        for: EncodedVideoChunk; text: [[type]]; url: dom-encodedvideochunk-type-slot
-        for: VideoEncoder; text: [[output callback]]; url: dom-videoencoder-output-callback-slot
-    type: interface
-        text: EncodedVideoChunk; url: encodedvideochunk
-        text: VideoEncoder; url: videoencoder
-    type: dictionary
-        text: VideoEncoderConfig; url: dictdef-videoencoderconfig
-        text: VideoDecoderConfig; url: dictdef-videodecoderconfig
-
-
 {
   "VP8": {
@@ -68,24 +50,29 @@
 EncodedVideoChunk data {#encodedvideochunk-data}
 ================================================
 
-{{EncodedVideoChunk}} [=EncodedVideoChunk/[[internal data]]=] is expected to be
+{{EncodedVideoChunk}} {{EncodedVideoChunk/[[internal data]]}} is expected to be
 a frame as described in Section 4 and Annex A of [[VP8]].
 
 VideoDecoderConfig description {#videodecoderconfig-description}
 ================================================================
 
-{{VideoDecoderConfig.description}} is not used for this codec.
+The {{VideoDecoderConfig/description}} is not used for this codec.
 
 EncodedVideoChunk type {#encodedvideochunk-type}
 ================================================
 
-If an {{EncodedVideoChunk}}'s [=EncodedVideoChunk/[[type]]=] is
+If an {{EncodedVideoChunk}}'s {{EncodedVideoChunk/[[type]]}} is
 {{EncodedVideoChunkType/key}}, then the {{EncodedVideoChunk}} is expected to
 contain a frame where `key_frame` is true as defined in Section 19.1 of [[VP8]].
 
-Privacy and Security Considerations {#privacy-and-security-considerations}
+Privacy Considerations {#privacy-considerations}
+==========================================================================
+
+Please refer to the section [[WEBCODECS#privacy-considerations|Privacy
+Considerations]] in [[WEBCODECS]].
+
+Security Considerations {#security-considerations}
 ==========================================================================
 
-Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]]
-and [[WEBCODECS#security-considerations|Security Considerations]] sections in
-[[WEBCODECS]].
+Please refer to the section [[WEBCODECS#security-considerations|Security
+Considerations]] in [[WEBCODECS]].
diff --git a/vp9_codec_registration.src.html b/vp9_codec_registration.src.html
index 1c6474e7..0e9029a1 100644
--- a/vp9_codec_registration.src.html
+++ b/vp9_codec_registration.src.html
@@ -7,16 +7,17 @@
 Group: mediawg
 ED: https://w3c.github.io/webcodecs/vp9_codec_registration.html
 TR: https://www.w3.org/TR/webcodecs-vp9-codec-registration/
-Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 Editor: Paul Adenot, w3cid 62410, Mozilla https://www.mozilla.org/
 Editor: Bernard Aboba, w3cid 65611, Microsoft Corporation https://www.microsoft.com/
+Former Editor: Chris Cunningham, w3cid 114832, Google Inc. https://www.google.com/
 
 Abstract: This registration is entered into the [[webcodecs-codec-registry]].
     It describes, for VP9, the (1) fully qualified codec strings,
     (2) the codec-specific {{EncodedVideoChunk}}
-    [=EncodedVideoChunk/[[internal data]]=] bytes, (3) the
-    {{VideoDecoderConfig.description}} bytes, and (4) the values of
-    {{EncodedVideoChunk}} [=EncodedVideoChunk/[[type]]=].
+    {{EncodedVideoChunk/[[internal data]]}} bytes, (3) the
+    {{VideoDecoderConfig/description|VideoDecoderConfig.description}} bytes,
+    (4) the values of {{EncodedVideoChunk}} {{EncodedVideoChunk/[[type]]}}, and
+    (5) the codec-specific extensions to {{VideoEncoderEncodeOptions}}.
 
     The registration is not intended to include any information on whether a
     codec format is encumbered by intellectual property claims. Implementers and
@@ -32,24 +33,6 @@
 !Version History: https://github.com/w3c/webcodecs/commits
 
-
-spec: WEBCODECS; urlPrefix: https://w3c.github.io/webcodecs/#
-    type: attribute
-        text: EncodedVideoChunkMetadata.decoderConfig; url: dom-encodedvideochunkmetadata-decoderconfig
-        for: EncodedVideoChunkType; text: key; url: dom-encodedvideochunktype-key
-        text: VideoDecoderConfig.description; url: dom-videodecoderconfig-description
-    type: dfn
-        for: EncodedVideoChunk; text: [[internal data]]; url: dom-encodedvideochunk-internal-data-slot
-        for: EncodedVideoChunk; text: [[type]]; url: dom-encodedvideochunk-type-slot
-        for: VideoEncoder; text: [[output callback]]; url: dom-videoencoder-output-callback-slot
-    type: interface
-        text: EncodedVideoChunk; url: encodedvideochunk
-        text: VideoEncoder; url: videoencoder
-    type: dictionary
-        text: VideoEncoderConfig; url: dictdef-videoencoderconfig
-        text: VideoDecoderConfig; url: dictdef-videodecoderconfig
-
-
 {
   "VP9": {
@@ -74,25 +57,67 @@
 EncodedVideoChunk data {#encodedvideochunk-data}
 ================================================
 
-{{EncodedVideoChunk}} [=EncodedVideoChunk/[[internal data]]=] is expected to be
+{{EncodedVideoChunk}} {{EncodedVideoChunk/[[internal data]]}} is expected to be
 a frame as described in Section 6 of [[VP9]].
 
 VideoDecoderConfig description {#videodecoderconfig-description}
 ================================================================
 
-{{VideoDecoderConfig.description}} is not used for this codec.
+The {{VideoDecoderConfig/description}} is not used for this codec.
 
 EncodedVideoChunk type {#encodedvideochunk-type}
 ================================================
 
-If an {{EncodedVideoChunk}}'s [=EncodedVideoChunk/[[type]]=] is
+If an {{EncodedVideoChunk}}'s {{EncodedVideoChunk/[[type]]}} is
 {{EncodedVideoChunkType/key}}, then the {{EncodedVideoChunk}} is expected to
 contain a frame with a `frame_type` of `KEY_FRAME` as defined in Section
 7.2 of [[VP9]].
 
-Privacy and Security Considerations {#privacy-and-security-considerations}
+VideoEncoderEncodeOptions extensions {#videoencoderencodeoptions-extensions}
+==============================================================
+
+
+
+partial dictionary VideoEncoderEncodeOptions {
+  VideoEncoderEncodeOptionsForVp9 vp9;
+};
+
+
+ +
+
vp9
+
+ Contains codec specific encode options for the [[VP9]] codec. +
+
+ +VideoEncoderEncodeOptionsForVp9 {#vp9-encode-options} +-------------------------------------- +
+
+dictionary VideoEncoderEncodeOptionsForVp9 {
+  unsigned short? quantizer;
+};
+
+
+ +
+
quantizer
+
+ Sets per-frame quantizer value. + In [[VP9]] the quantizer threshold can be varied from 0 to 63 +
+
+ + +Privacy Considerations {#privacy-considerations} +========================================================================== + +Please refer to the section [[WEBCODECS#privacy-considerations|Privacy +Considerations]] in [[WEBCODECS]]. + +Security Considerations {#security-considerations} ========================================================================== -Please refer to the [[WEBCODECS#privacy-considerations|Privacy Considerations]] -and [[WEBCODECS#security-considerations|Security Considerations]] sections in -[[WEBCODECS]]. +Please refer to the section [[WEBCODECS#security-considerations|Security +Considerations]] in [[WEBCODECS]].