diff --git a/libraries/scrcpy-decoder-tinyh264/README.md b/libraries/scrcpy-decoder-tinyh264/README.md index 1262eb69..41fa0a73 100644 --- a/libraries/scrcpy-decoder-tinyh264/README.md +++ b/libraries/scrcpy-decoder-tinyh264/README.md @@ -25,21 +25,21 @@ new ScrcpyOptions1_24({ codecOptions: new CodecOptions({ profile: TinyH264Decoder.maxProfile, level: TinyH264Decoder.maxLevel, - }) -}) + }), +}); ``` However, it can fail on some very old devices that doesn't support even Baseline level 4 codec. You can retry without the `codecOptions` option if that happens. ### Render the video -It draws frames onto `decoder.element` (a `` element), you can insert it anywhere you want to display the video. +It draws frames onto `decoder.renderer` (a `` element), you can insert it anywhere you want to display the video. ```ts const decoder = new TinyH264Decoder(); -document.body.appendChild(decoder.element); +document.body.appendChild(decoder.renderer); videoPacketStream // from `@yume-chan/scrcpy` .pipeTo(decoder.writable) - .catch(() => { }); + .catch(() => {}); ``` diff --git a/libraries/scrcpy-decoder-tinyh264/package.json b/libraries/scrcpy-decoder-tinyh264/package.json index 38d71c32..d0c83a39 100644 --- a/libraries/scrcpy-decoder-tinyh264/package.json +++ b/libraries/scrcpy-decoder-tinyh264/package.json @@ -1,7 +1,7 @@ { "name": "@yume-chan/scrcpy-decoder-tinyh264", "version": "0.0.17", - "description": "TypeScript implementation of Scrcpy.", + "description": "Raw H.264 stream decoder and renderer wrapping TinyH264 and YUVCanvas packages (software decoding).", "keywords": [ "adb", "android-phone", diff --git a/libraries/scrcpy-decoder-webcodecs/README.md b/libraries/scrcpy-decoder-webcodecs/README.md index ea323cc9..b3e415bc 100644 --- a/libraries/scrcpy-decoder-webcodecs/README.md +++ b/libraries/scrcpy-decoder-webcodecs/README.md @@ -6,8 +6,8 @@ It has no dependencies and high performance, but is only available on recent ver **WARNING:** The public API is UNSTABLE. If you have any questions, please open an issue. -- [Compatibility](#compatibility) -- [Usage](#usage) +- [Compatibility](#compatibility) +- [Usage](#usage) ## Compatibility @@ -17,13 +17,13 @@ It has no dependencies and high performance, but is only available on recent ver ## Usage -It draws frames onto `decoder.element` (a `` element), you can insert it anywhere you want to display the video. +It draws frames onto `decoder.renderer` (a `` element), you can insert it anywhere you want to display the video. ```ts const decoder = new WebCodecsDecoder(); -document.body.appendChild(decoder.element); +document.body.appendChild(decoder.renderer); videoPacketStream // from `@yume-chan/scrcpy` .pipeTo(decoder.writable) - .catch(() => { }); + .catch(() => {}); ``` diff --git a/libraries/scrcpy-decoder-webcodecs/package.json b/libraries/scrcpy-decoder-webcodecs/package.json index f080f3d4..14c88a70 100644 --- a/libraries/scrcpy-decoder-webcodecs/package.json +++ b/libraries/scrcpy-decoder-webcodecs/package.json @@ -1,7 +1,7 @@ { "name": "@yume-chan/scrcpy-decoder-webcodecs", "version": "0.0.17", - "description": "TypeScript implementation of Scrcpy.", + "description": "Raw H.264 stream decoder and renderer using WebCodecs API (requires modern browser).", "keywords": [ "adb", "android-phone", diff --git a/libraries/stream-extra/README.md b/libraries/stream-extra/README.md index 0b1338ab..2602dc01 100644 --- a/libraries/stream-extra/README.md +++ b/libraries/stream-extra/README.md @@ -1,8 +1,40 @@ # @yume-chan/stream-extra -Some useful extensions for Web Streams API. +Some useful extensions for working with binary streams. Conforms to the [Web Streams API](https://streams.spec.whatwg.org/). -Currently it's using [web-streams-polyfill](https://github.com/MattiasBuelens/web-streams-polyfill) because it's hard to load native implementations from both browsers and Node.js. (An experimental implementation using Top Level Await is available in `native.ts`, but not exported). +## Find an implementation + +If all of `ReadableStream`, `WritableStream` and `TransformStream` fields are available on `globalThis`, they will be used. Otherwise, the [web-streams-polyfill](https://github.com/MattiasBuelens/web-streams-polyfill) package will be used. + +Google Chrome 89 and Mozilla Firefox 102 provide full support for Web Streams API natively. + +In Node.js, it's not possible to load the `stream/web` module while keeping the compatibility with both Web and bundlers: + +- Webpack has poor support with Top Level Await, for example, Hot Module Replacement doesn't work when any module is using TLA. +- Web doesn't have the `module` module, thus requires a shim in import map. + +Assigning `ReadableStream`, `WritableStream` and `TransformStream` from `stream/web` module to `globalThis`, before loading this library, will still work. Other custom polyfill can also be loaded this way. + +## Compatibility issue with `ReadableStream#pipeTo` and `ReadableStream#pipeThrough` + +The [Web Streams API spec](https://streams.spec.whatwg.org/#readable-stream-pipe-to) specifies that `ReadableStream#pipeTo` must check the argument to be an instance of `WritableStream`, so it can optimize the performance by calling internal methods directly. + +Native implementations will perform this check, so `new globalThis.ReadableStream().pipeTo(new Polyfill.WritableStream())` will throw an error. + +The `WrapReadableStream` class can be used to bypass this check: + +```ts +import { WrapReadableStream } from "@yume-chan/stream-extra"; +import { WritableStream as PolyfillWritableStream } from "web-streams-polyfill"; + +const nativeReadable = new globalThis.ReadableStream(); +const wrappedReadable = new WrapReadableStream(new globalThis.ReadableStream()); + +nativeReadable.pipeTo(new PolyfillWritableStream()); // Error +wrappedReadable.pipeTo(new PolyfillWritableStream()); // OK +``` + +web-streams-polyfill package's `ReadableStream#pipeTo` only uses public methods, so it can be used with any `WritableStream` implementation. ## `BufferedReadableStream` diff --git a/libraries/stream-extra/src/buffered-transform.ts b/libraries/stream-extra/src/buffered-transform.ts index e5fa9e39..a967cef5 100644 --- a/libraries/stream-extra/src/buffered-transform.ts +++ b/libraries/stream-extra/src/buffered-transform.ts @@ -46,9 +46,9 @@ export class BufferedTransformStream const value = await transform(buffered); controller.enqueue(value); } catch (e) { - // TODO: BufferedTransformStream: The semantic of stream ending is not clear - // If the `transform` started but did not finish, it should really be an error? - // But we can't detect that, unless there is a `peek` method on buffered stream. + // Treat `BufferedReadableStreamEndedError` as a normal end. + // If the `transform` method doesn't have enough data to return a value, + // it should throw another error to indicate that. if (e instanceof BufferedReadableStreamEndedError) { controller.close(); return; diff --git a/libraries/struct/src/types/number.ts b/libraries/struct/src/types/number.ts index 5963da71..2d2d414c 100644 --- a/libraries/struct/src/types/number.ts +++ b/libraries/struct/src/types/number.ts @@ -50,6 +50,11 @@ export namespace NumberFieldType { signed: false, size: 2, deserialize(array, littleEndian) { + // PERF: Chrome's `DataView#getUint16` uses inefficient operations, + // including branching, bit extending and 32-bit bit swapping. + // The best way should use 16-bit bit rotation and conditional move, + // like LLVM does for code similar to the below one. + // This code is much faster on V8, but the actual generated assembly is unknown. return ( (((array[1]! << 8) | array[0]!) * (littleEndian as any)) | (((array[0]! << 8) | array[1]!) * (!littleEndian as any))