legokichi / ts-ebml

EBML encoder and decoder
177 stars 52 forks source link

Can't use Buffer in browser #37

Open jlkiri opened 3 years ago

jlkiri commented 3 years ago

Buffer is a node thing and while I know it's possible to use it in browser via browserify I was wondering if there are other workarounds that do not make me use browserify just to use this library.

guest271314 commented 2 years ago

See https://github.com/legokichi/ts-ebml/issues/14#issuecomment-1025186091

or-else commented 1 year ago

@jlkiri Have you figured out how to use it in browser?

@guest271314 Where does ts-eblm-min.js come from? Is there a known process/script of building it from ts-ebml? Which version of ts-ebml is it built from?

Thanks!

guest271314 commented 1 year ago

Where does ts-eblm-min.js come from?

If I recollect correctly I built it using browserify.

Which version of ts-ebml is it built from?

Unminified, at the end of the script

version: '2.0.2'

or-else commented 1 year ago

If I recollect correctly I built it using browserify.

Great, thanks! Any chance to recover the build script/config used to build it? The file has a bunch of unused strings including the entire README. I would not mind repackaging it.

version: '2.0.2'

Yes, I see it now, thanks!

guest271314 commented 1 year ago

I created that some time ago. If I recollect correctly I used a Buffer and require() browser polyfill, and built using browserify, then included Ecmascript export at the end for the ability to import Decoder, Encoder, tools, et al.

Unfortunately the Buffer and require() parts are Node.js specific artifacts.

I think we can re-write the entire script without using require() or Buffer at all.

or-else commented 1 year ago

Unfortunately the Buffer and require() parts are Node.js specific artifacts.

Yes, that's exactly why I'm here :)

I think we can re-write the entire script without using require() or Buffer at all.

I don't think I understand it well enough to try.

Another option is to import buffer polyfill into my code and assign imported Buffer to the window object. It just does not look clean.

guest271314 commented 1 year ago

I don't think I understand it well enough to try.

You are already trying, right now. The first step is identifying the issue, then proposing solutions, then testing proposed solutions.

Another option is to import buffer polyfill into my code and assign imported Buffer to the window object. It just does not look clean.

Yes, that's exactly why I'm here :)

For me the idea is to get away from Node.js specific code, not continue those patterns. I use QuickJS and Deno without any package.json file just to import Ecmascript modules.

Is there an issue with just using the minified code I already published to gist?

guest271314 commented 1 year ago

See https://cdn.jsdelivr.net/npm/ts-ebml@2.0.2/src/buffer-type.d.ts for ts-ebml TypeScript version of extending Uint8Array to Node.js Buffer equivalent .

or-else commented 1 year ago

Is there an issue with just using the minified code I already published to gist?

Kind of. First, as I said before, it includes a lot of unused strings, including the entire README file. It would be nice to get rid of them. Second, I want to be able to rebuild it if ts-ebml changes. Then it's also a bit of a black box. I would have to explain it to my users which I really can't other than "I hope it's OK".

See https://cdn.jsdelivr.net/npm/ts-ebml@2.0.2/src/buffer-type.d.ts

Thanks! If I understand correctly, the Buffer is used in the upstream https://github.com/node-ebml/node-ebml though. I don't think my knowledge of JS packagers goes that far.

or-else commented 1 year ago

BTW, there is also this https://github.com/buynao/webm-duration-fix which solves the same problem. I have not tried it yet.

guest271314 commented 1 year ago

Kind of. First, as I said before, it includes a lot of unused strings, including the entire README file. It would be nice to get rid of them.

I think you can safely remove the commented lines 6265-6269 here https://plnkr.co/edit/QijGTcjFreeNvnKd?open=lib%2Fscript.js&preview.

Second, I want to be able to rebuild it if ts-ebml changes.

On the readme.mf of this repository it is stated https://github.com/legokichi/ts-ebml#fork-of-node-ebml

Fork of node-ebml

It is a fork of https://github.com/themasch/node-ebml

which is here https://cdn.jsdelivr.net/npm/ebml.

Then it's also a bit of a black box. I would have to explain it to my users which I really can't other than "I hope it's OK".

The readme part that is commented in the linked plnkr (above) explains what the ts-ebml does, and why it was necessary to create.

Thanks! If I understand correctly, the Buffer is used in the upstream https://github.com/node-ebml/node-ebml though. I don't think my knowledge of JS packagers goes that far.

Buffer just extends Uint8 TypedArray.

BTW, there is also this https://github.com/buynao/webm-duration-fix which solves the same problem. I have not tried it yet.

There is also https://github.com/davedoesdev/webm-muxer.js.

Really depends on what you are trying to do.

Technically it is possible to record Opus audio and VP8/VP9 without a WebM (Matroska) container, and play back the file https://github.com/guest271314/WebCodecsOpusRecorder.

guest271314 commented 1 year ago

Here is EBML.js https://github.com/davedoesdev/webm-muxer.js/blob/main/EBML.js, commented.

or-else commented 1 year ago

The readme part that is commented in the linked plnkr (above) explains what the ts-ebml does, and why it was necessary to create.

Yes, but it's basically a binary which no one can recreate. Sure, it's acceptable as a last resort. Just not great.

Really depends on what you are trying to do.

I'm recording in Chrome and want to playback in iOS and Android without recoding on the server. This is the project: https://github.com/tinode/webapp

There is also https://github.com/davedoesdev/webm-muxer.js.

Thanks!

or-else commented 1 year ago

https://github.com/guest271314/WebCodecsOpusRecorder.

VLC cannot play the records it produces.

guest271314 commented 1 year ago

Yes, but it's basically a binary which no one can recreate. Sure, it's acceptable as a last resort. Just not great.

We can re-write the code, without using require() or Buffer, which are not defined in the browser anyway.

You can parse the file and programmatically extract the "readme" property value, or just read and write it out by hand.

I would just use the minified ts-ebml gist. That is what I do here https://github.com/guest271314/captureSystemAudio/blob/0a13aff6bb45850bd8ae55f9c68dd3b35c1bc4b6/native_messaging/capture_system_audio/background.js#L80-L95

        } else if (this.mimeType.includes('opus')) {
          const {
            Decoder,
            Encoder,
            tools,
            Reader,
            injectMetadata,
          } = await import(`${this.src.origin}/ts-ebml.min.js`);
          Object.assign(this, {
            Decoder,
            Encoder,
            tools,
            Reader,
            injectMetadata,
          });
        }

If you want to understand the source code there is no substitute for reading every line of the code. The why is a non-short list of Chromium bug reports and specification issues.

I'm recording in Chrome and want to playback in iOS and Android without recoding on the server. This is the project: https://github.com/tinode/webapp

Cool.

I have no experience with iOS.

guest271314 commented 1 year ago

https://github.com/guest271314/WebCodecsOpusRecorder. VLC cannot play the records it produces.

Yes, I know.

I wrote the algorithm to write Opus audio produced by WebCodecs to a single file and the algorithm to play back the file using Media Source Extensions or converting the file to a WAV.

There was no roadmap for how to do that.

There is no media container, e.g., WebM (Matroska) involved.

Record your microphone, save the file, then upload the file back to the site for playback.

guest271314 commented 1 year ago

@or-else Is there any reason you just don't explain in your README.md that Chrome/Chromium does not setting duration of WebM files produced by W3C specified MediaRecorder, and thus you will be using ts-ebml to set said duration for WebM files?

or-else commented 1 year ago

We can re-write the code, without using require() or Buffer, which are not defined in the browser anyway.

I'm sure someone can. I cannot. Not without spending a week or two on figuring out how it all works.

Is there any reason you just don't explain in your README.md

It's not about explaining it in the README. As an open source project admin I want to use open source dependencies. Not just de-jure, but also de-facto, i.e. no cryptic binary blobs even if they are technically open source.

I have no experience with iOS.

There is no problem with iOS (kind of). iOS flat out does not support webm. I use VLC there. VLC has no issues with these webm files. I have a problem on Android: the legacy MediaPlayer kind of works but buggy, ExoPlayer has a problem with these files: https://github.com/google/ExoPlayer/issues/10824 Switching to VLC is an option, but it would add a lot to the size of the apk.

guest271314 commented 1 year ago

I'm sure someone can. I cannot. Not without spending a week or two on figuring out how it all works.

Then take the time to figure it out.

It's not about explaining it in the README. As an open source project admin I want to use open source dependencies. Not just de-jure, but also de-facto, i.e. no cryptic binary blobs even if they are technically open source.

There is nothing cryptic going on here.

Chrome refuses to support writing duration to WebM files produced by their implementation of MediaRecorder. Not because the requirement is not possible. Because Chrome authors just decided to not write the duration, in spite of multiple issues and bug reports stating it is in every developers interest to do so.

There is no problem with iOS (kind of). iOS flat out does not support webm. I use VLC there. VLC has no issues with these webm files. I have a problem on Android: the legacy MediaPlayer kind of works but buggy, ExoPlayer has a problem with these files: https://github.com/google/ExoPlayer/issues/10824 Switching to VLC is an option, but it would add a lot to the size of the apk.

There are multiple options available.

Perhaps begin your understanding and familiarity of the issue by reading the relevant specification and Chrome bugs listed in readme of this repository.

There is also mpv.js https://github.com/Kagami/mpv.js, and a variety of other ways to playback WebM files. I would just use the minified file or for a full fledged library that is well-maintained https://github.com/davedoesdev/webm-muxer.js.

guest271314 commented 1 year ago

@or-else Note, since you are evidently using, or considering using native applications, you can also write the duration with mkvmerge. Before Chrome Apps were deprecated I used Native Messaging to merge multiple audio, video, and combined audio and video tracks into a single WebM (Matroska) file https://github.com/guest271314/native-messaging-mkvmerge. MKVToolNix https://gitlab.com/mbunkus/mkvtoolnix is very well maintained.

or-else commented 1 year ago

Then take the time to figure it out.

Which I would definitely do if I had unlimited time.

There is nothing cryptic going on here.

I'm taking about ts-eblm-min.js. It's minified js, pretty much unreadable and unmodifiable. That makes it cryptic in my book.

Chrome refuses to support...

Yes, I know that. If you look at the ExoPlayer bug I filed and linked here, it describes this problem with Chrome.

There are multiple options available.

Yes, that's a problem too. It's hard to choose a path which solves the problem with minimum effort. Nothing seems to work without issues.

guest271314 commented 1 year ago

I'm taking about ts-eblm-min.js. It's minified js, pretty much unreadable and unmodifiable. That makes it cryptic in my book.

That is not true. You can unminify and mofigy the script right in Chrome DevTools sources panel.

Yes, that's a problem too. It's hard to choose a path which solves the problem with minimum effort. Nothing seems to work without issues.

ts-ebml works.

or-else commented 1 year ago

That is not true. You can unminify and mofigy the script right in Chrome DevTools sources panel.

It's software, so anything is possible. It's all about the amount of effort. The ts-eblm-min.js as is is cryptic. That's why I asked if you have the original build config for it (minimum effort).

ts-ebml works.

I'm sure it does, just not without issues. For example, it depends on Buffer:

tools.js:44 Uncaught (in promise) ReferenceError: Buffer is not defined
    at Object.writeVint (tools.js:44:1)
    at Object.encodeTag (tools.js:26:1)
    at EBMLEncoder.writeTag (EBMLEncoder.js:55:1)
    at EBMLEncoder.encodeChunk (EBMLEncoder.js:29:1)
    at EBMLEncoder.js:16:1
    at Array.reduce (<anonymous>)
    at EBMLEncoder.encode (EBMLEncoder.js:15:1)
    at tools.js:478:57
    at Array.reduce (<anonymous>)
    at encodedSizeOfEbml (tools.js:478:1)

As I said in the previous message: Nothing seems to work without issues.

guest271314 commented 1 year ago

I linked to the unminified version yesterday https://plnkr.co/plunk/QijGTcjFreeNvnKd.

How was that error generated?

or-else commented 1 year ago

I linked to the unminified version yesterday

Thanks!

How was that error generated?

https://github.com/tinode/webapp/blob/eblm/src/widgets/audio-recorder.jsx#L275

guest271314 commented 1 year ago

You didn't use the minified script I compiled, which includes require() and Buffer polyfills.

I am not sure why you are hesitant to just use the script I invested time to compile?

or-else commented 1 year ago

You didn't use the minified script I compiled, which includes require() and Buffer polyfills.

I did not use it because, as I explained before, it's not truly open source.

I am not sure why you are hesitant to just use the script I invested time to compile?

I'm not hesitant. You told me about it just half an hour ago. I will try it. Thanks again.

guest271314 commented 1 year ago

I did not use it because, as I explained before, it's not truly open source.

Yes, it is.

Why do you think the code is not FOSS?

I'm not hesitant. You told me about it just half an hour ago. I will try it. Thanks again.

No. I linked to the code yesterday. And posted a pull request in this repository some time ago.

or-else commented 1 year ago

Why do you think the code is not FOSS?

As I explained before, "Open Source" means the source is open, i.e. readable and modifiable. A minified JS is not particularly readable or modifiable.

No. I linked to the code yesterday.

I found out about it 30 minutes ago when you said so in this conversation.

guest271314 commented 1 year ago

As I explained before, "Open Source" means the source is open, i.e. readable and modifiable.

Yes. That file is readable and modifiable.

A minified JS is not particularly readable or modifiable.

Sure it is.

I found out about it 30 minutes ago when you said so in this conversation.

Then you havn't really been reading this issue or following links herein. See

et al.

guest271314 commented 1 year ago

Just for your own edification, on Chrome or Chromium browsers you can copy/paste or load a local file in DevTools: Sources => Snippets => New snippet, then paste the code, then click the icon {} in the left-corner of the editor 'Format Script snippet #1'.

or-else commented 1 year ago

Then you havn't really been reading this issue or following links herein. See

I'm very very sorry that I disappointed you.

guest271314 commented 1 year ago

You ain't disappointing me. I'm trying to help you.

guest271314 commented 1 year ago

I'm sure it does, just not without issues. For example, it depends on Buffer:

tools.js:44 Uncaught (in promise) ReferenceError: Buffer is not defined
    at Object.writeVint (tools.js:44:1)
    at Object.encodeTag (tools.js:26:1)
    at EBMLEncoder.writeTag (EBMLEncoder.js:55:1)
    at EBMLEncoder.encodeChunk (EBMLEncoder.js:29:1)
    at EBMLEncoder.js:16:1
    at Array.reduce (<anonymous>)
    at EBMLEncoder.encode (EBMLEncoder.js:15:1)
    at tools.js:478:57
    at Array.reduce (<anonymous>)
    at encodedSizeOfEbml (tools.js:478:1)

https://github.com/feross/buffer

guest271314 commented 1 year ago

@or-else This is the original version of ts-ebml-min.js I compiled https://github.com/guest271314/MediaFragmentRecorder/tree/169d5ffc690604e9a6c94956c1b0a28a00d20984/ts-ebml.

guest271314 commented 1 year ago

This https://bundle.run/buffer@6.0.3 is the lastest release that I could find of https://github.com/feross/buffer.

Then you can do something like https://plnkr.co/edit/uI2OMJE2klrD89yF?preview

self.Buffer = self.buffer.Buffer;
console.log(Buffer, new Buffer([1]));
or-else commented 1 year ago

It looks like https://github.com/buynao/webm-duration-fix works as is.

guest271314 commented 1 year ago

Still uses Buffer. ts-ebml works, too. If that code works for you, of course, use that source code.

guest271314 commented 1 year ago

The source code in the online demo uses the same code I do in ts-ebml-min.js

 * The buffer module from node.js, for the browser.
 *
 * @author   Feross Aboukhadijeh <https://feross.org>
 * @license  MIT
 */
(function(e) {
    const t = Gi
      , n = sa
      , r = typeof Symbol == "function" && typeof Symbol.for == "function" ? Symbol.for("nodejs.util.inspect.custom") : null;
    e.Buffer = s,
    e.SlowBuffer = y,
    // ...
guest271314 commented 1 year ago

@or-else The source code for Buffer polyfill might not be exactly the same when you read and compare them. The same original author.

Your concern expressed earlier in this issue was that the minified ts-ebml-min.js I cobbled together in 2017 was "cryptic". It looks like https://media-recorder-demo.vercel.app/assets/index.edf6e09e.js includes the require() and Buffer polyfills I included in ts-ebml-min.js and other code.

So, the claim that ts-ebml-min.js is "cryptic" must also apply to the code linked above.