Code Monkey home page Code Monkey logo

ts-ebml's Introduction

ts-ebml

ebml encoder and decoder written in TypeScript.

Fork of node-ebml

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

install

npm install ts-ebml --save

usage

show EBML structure on console

$ ts-ebml foo.webm
0	m	0	EBML
5	u	1	EBMLVersion 1
9	u	1	EBMLReadVersion 1
13	u	1	EBMLMaxIDLength 4
17	u	1	EBMLMaxSizeLength 8
21	s	1	DocType webm
28	u	1	DocTypeVersion 2
32	u	1	DocTypeReadVersion 2
36	m	0	Segment
48	m	1	Info
53	u	2	TimecodeScale 1000000
...

try to convert a MediaRecorder WebM to seekable WebM

$ ts-ebml -s input.webm | cat > seekable.webm

node

import * as ebml from 'ts-ebml';
const fs = require('fs');

const decoder = new ebml.Decoder();

fs.createReadStream('media/test.webm').on('data', (buf)=>{
  const ebmlElms = decoder.decode(buf);
  console.log(ebmlElms);
});

browser

<script src="./dist/ebml.min.js"></script>
<script>
const decoder = new ebml.Decoder();

fetch('media/test.webm')
  .then((res)=> res.arrayBuffer() )
  .then((buf)=>{
    const ebmlElms = decoder.decode(buf);
    console.log(ebmlElms);
  });  
</script>

bundle

import * as ebml from 'ts-ebml';

const decoder = new ebml.Decoder();

fetch('media/test.webm')
  .then((res)=> res.arrayBuffer() )
  .then((buf)=>{
    const ebmlElms = decoder.decode(buf);
    console.log(ebmlElms);
  });

features

  • get WebP frame from MediaRecorder WebM VP8 Stream
  • create seekable webm from media-recoder
  • create playable webm to media-stream-api from media-recorder

see src/test.ts and src/example_seekable.ts

stable API

class Decoder {
  constructor();
  decode(chunk: ArrayBuffer): EBMLElementDetail[];
}

class Encoder {
  constructor();
  encode(elms: EBMLElementBuffer[]): ArrayBuffer;
}

type EBMLElementBuffer = MasterElement | ChildElementBuffer;
type EBMLElementDetail = (MasterElement | ChildElementValue) & ElementDetail;

type MasterElement = {
  name: string;
  type: "m";
  isEnd: boolean;
  unknownSize?: boolean;
};
type ChildElementBuffer = {
  name: string;
  type: "u" | "i" | "f" | "s" | "8" | "b" | "d";
  data: Buffer;
};
type ChildElementValue = ChildElementBuffer & {
  value: number|string|Buffer|Date;
};
type ElementDetail = {
  tagStart: number;
  tagEnd: number;
  sizeStart: number;
  sizeEnd: number;
  dataStart: number;
  dataEnd: number;
};
namespace tools {
  export function readVint(buffer: Buffer, start: number): null | ({length: number; value: number; });
  export function writeVint(val: number): Buffer;
  export function readBlock(buf: ArrayBuffer): EBML.SimpleBlock;
}

develop

npm install
npm run build   # build js code
npm run lint    # tslint
npm run doc     # typedoc
npm run lint   # type check (watch)
npm test        # build and run tests

debugging tools

license

MIT

related info

related issues

media recorder seekable webm

chrome

firefox

others

media recorder media source gap

chrome

others

chrome

firefox

related works

ts-ebml's People

Contributors

davedoesdev avatar legokichi avatar singingtree avatar somebee avatar thijstriemstra avatar tjenkinson avatar willemkokke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ts-ebml's Issues

Can't use Buffer in browser

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.

Can we use ts-ebml to implement the functionality of $ mkvmerge -w -o full.webm 1.webm + N.webm ?

Can we use ts-ebml to implement the functionality of

$ mkvmerge -w -o full.webm 1.webm + N.webm ?

First attempt to filter SimpleBlocks

          const decoder = new EBML.Decoder();
          const encoder = new EBML.Encoder();
          const reader = new EBML.Reader();
          const tools = EBML.tools;
          console.log(tools, reader, encoder, decoder);
          const ebmlElms = decoder.decode(ab);
          
          reader.drop_default_duration = true;

          ebmlElms.forEach((elm) => {
            reader.read(elm);
          });

          reader.stop();

          console.log(reader.metadatas, reader.duration, reader.cues);

          console.log(ebmlElms.filter(({name:n}) => n === "SimpleBlock"));

How do we append the SimpleBlocks from e.g., webm_file_1 to the Cluster of webm_file_2, change values of timecode elements to be sequential (webm_file_1 through webm_file_2) and reset Duration to create a new webm file (webm_file_3) having Duration value set to the sum of webm_file_1 and webm_file_2?

"Couldn't determine next keyframe time" on firefox

related: #3 (comment)

MOZ_LOG_FILE="log.txt" MOZ_LOG="MediaDemuxer:5" /Applications/Firefox.app/Contents/MacOS/firefox-bin

として起動した Firefox 53.0.2 (64 bit) で seekable にした動画を最後まで再生すると

[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11e63f480)::SetNextKeyFrameTime: Couldn't determine next keyframe time  (0 queued)

が発生し、以後再生しようとしても

[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11f008400)::GetBuffered: Duration: 9.371000 StartTime: 0.000000
[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11f008400)::GetBuffered: limit range to duration, end: 9.466000 duration: 9.371000
[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11f008400)::GetBuffered: add range 0.000000-9.371000
[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11e63f480)::Reset: Seek to start point: 0.000000
[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11f008400)::SeekInternal: Seek Target: 0.000000
[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11f008400)::SeekInternal: SeekPreroll: 0.080000 StartTime: 0.000000 Adjusted Target: 0.000000
[MediaPlayback #1]: D/MediaDemuxer WebMDemuxer(11e63f480)::SetNextKeyFrameTime: Couldn't determine next keyframe time  (0 queued)

が繰り返されて再生できない。

ts-ebml is crashing firefox on buffers corresponding with videos > 3 minutes?

I'm using the readAsArrayBuffer tactic. Is my implementation naive or incorrect? No issue on latest Chrome.

import { Decoder, Reader, tools } from 'ts-ebml'

const FILE_TYPE = 'video/webm'

function startMediaRecorder (stream, onMediaRecorderInit, success, error) {
  const mediaFile = new MediaFile(stream, FILE_TYPE, success, error)
  onMediaRecorderInit(mediaFile.mediaRecorder)
  mediaFile.mediaRecorder.start(10)
}

class MediaFile {
  constructor (stream, fileType, fileSuccess, fileError) {
    this.stream = stream
    this.fileType = fileType
    this.fileSuccess = fileSuccess
    this.fileError = fileError

    this.tasks = Promise.resolve()
    this.decoder = new Decoder()
    this.reader = new Reader()
    this.webM = new Blob([], { type: this.fileType })

    this.mediaRecorder = new MediaRecorder(stream, { mimeType: this.fileType })
    this.mediaRecorder.ondataavailable = this.addToChunks
    this.mediaRecorder.onerror = this.onError
    this.mediaRecorder.onstop = this.onStop
  }

  addToChunks = (e) => {
    this.webM = new Blob([this.webM, e.data], { type: e.data.type })
    const task = () => this.readAsArrayBuffer(e.data).then((buf) => {
      const elms = this.decoder.decode(buf)
      elms.forEach((elm) => { this.reader.read(elm) })
    }).catch((e) => {
      this.onError(e)
    })

    return this.tasks.then(() => task() )
  }

  readAsArrayBuffer = (blob) => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader()
      reader.readAsArrayBuffer(blob)
      reader.onloadend = () => { resolve(reader.result) }
      reader.onerror = (ev) => { reject(ev.error) }
    })
  }

  onError = (e) => {
    this.fileError(e)
  }

  onStop = () => {
    return this.tasks.then(() => {
      this.reader.stop()
      const refinedMetadataBuf = tools.makeMetadataSeekable(
        this.reader.metadatas, this.reader.duration, this.reader.cues
      )

      this.readAsArrayBuffer(this.webM).then((webMBuf) => {
        const body = webMBuf.slice(this.reader.metadataSize)
        const refinedWebM = new Blob([refinedMetadataBuf, body], { type: 'video/webm' })
        this.fileSuccess(refinedWebM)
      }).catch((e) => {
        this.onError(e)
      })
    })
  }

TypeError: data.readUIntBE is not a function at EBMLDecoder.readContent (EBMLDecoder.js:215:1)

Hello, testing this library in react project (v17). The error that occurs is :
TypeError: data.readUIntBE is not a function
at EBMLDecoder.readContent (EBMLDecoder.js:215:1)

Tried :

'ebml': path.resolve(__dirname, 'node_modules/ebml/lib/ebml.esm.js'),
    'buffer':path.resolve(__dirname, 'node_modules/buffer/index.js'),

in webpack config. But it does not to work. Any other solutions?

Modifying frames of existing WebM video

I have a WebM file (single video track encoded with VP9) and was wondering if I can use ts-ebml to perform the following:

  1. Parse the file and extract each frame
  2. Decode parsed frames (using W3C VideoDecoder)
  3. Apply some transformation on the frame (for example draw a rectangle in the middle)
  4. Encode the new frame back using VP9
  5. Assemble the new frames back to a WebM container file

No reader.cues and reader.duration for audio-only webm files

In testing example_seekable.ts it seems that switching from audio & video to audio-only files causes the library to fail to generate cues or a duration value for files (both for the main_from_file and main_from_recorder tests).

You can verify this by modifying main_from_recorder to call getUserMedia with video: false (and a couple of other changes to indicate the proper mime type & audio tags). reader.duration seems to be 0 in all cases where the file is audio-only.

Issue with video seekable only as a multiplier of 20 seconds

Hello,
I'm developing solution which is capturing video from Canvas with usage of Media Recorder API.
Due to files produced by it are not seekable, I have tried to use your solution to resolve my issues.
It is working and made seekable files but on Chrome in version 60 I have experienced that time of video is only set as multiplier of 20 seconds. If I made 13 seconds record in VLC video is unseekable (on bar 0 is shown), and if I made 25 seconds video, time is set only to 20 seconds. In VLC when it play 20 seconds it is always playing rest 5 seconds but they are unseekable.
It doesn't matter which codec I use (vp8/vp9) it always generate me the same issue.
Do you have maybe any idea what could happen ?

ReferenceError: Buffer is not defined in tools.js

ReferenceError: Buffer is not defined
    at Object.writeVint (tools.js:44)
    at Object.encodeTag (tools.js:26)
    at EBMLEncoder.push.../../node_modules/ts-ebml/lib/EBMLEncoder.js.EBMLEncoder.writeTag (EBMLEncoder.js:55)
    at EBMLEncoder.push.../../node_modules/ts-ebml/lib/EBMLEncoder.js.EBMLEncoder.encodeChunk (EBMLEncoder.js:29)

I have this issue on web, my build system is based on TypeScript 2.9.2, relevant lines from tsconfig:

{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es5",
    "lib": ["es2017", "dom"],
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  }
}

For now I can work around it by setting Buffer on window.

import { Buffer } from 'buffer';
window.Buffer = Buffer;

SimpleBlock encoding support

I'm trying to parse a webm file, drop some SimpleBlocks, and adjust the Timecodes on each block so that I can effectively trim the video. I can create Clusters and Cluster Timecodes without an issue but encoding a SimpleBlocks is a problem. Although there is an Encoder() present, there seems to be no way to create/edit a SimpleBlock. I'm looking a function that can do the inverse of tools.readBlock.

(Currently I'm using ffmpeg (wasm) but it's a bit expensive on data.)

React application: Uncaught ReferenceError: require is not defined at ebml.esm.js:8741:15

Locally I run the application and it works, but when I upload it to the dev server and connect to this dev url I get this message in chrome inspector:

image image

Any ideas? I am using a nx monorepo with vite as bundler.

In the vite.config.ts file I included:

  resolve: {
    alias: {
      // Alias the ebml module to the CommonJS/ESM version
      ebml: "ebml/lib/ebml.esm.js",
    },
  },

ArrayBuffer memory leak issue

Range Error: Array buffer allocation failed

This error occurs with large recorded video(1 hours) blob in low power PC(windows 10 32bit 4 GB ram)

IMG_20211008_224824

Any idea?

Making seekable blob corrupts the video

I have a webm video captured using Media Recorder API representing the current browser tab. In order to produce a seekable video I use the ts-ebml package like so:

ts-ebml -s input.webm | cat > input-seekable.webm

Most of the time this works pretty well, but I have noticed that with still videos (no moving frames), this produces corrupted video.

Here's an example of such input video:

input.webm.zip

After applying the seekable transformation on this input video I get the following corrupt video:

input-seekable.webm.zip

If you try opening the resulting video, playing it and then seeking towards the end, the playback stops.

Also if you open this video with some js player (such as shaka player) it throws the following error:

{
	"severity": 2,
	"category": 3,
	"code": 3016,
	"data": [3, null, "PIPELINE_ERROR_DECODE: {\"causes\":[],\"data\":{},\"stack\":[{\"file\":\"media/filters/vpx_video_decoder.cc\",\"line\":197}],\"status_code\":271,\"status_message\":\"\"}"],
	"handled": false
}

v3.0.1: _tools is undefined

I'm trying to upgrade to v3.0.0 using import * as ebml from 'ts-ebml'; but it fails with

Uncaught TypeError: _tools is undefined

There are references to _tools in readVint and writeVint:

/***/ "./node_modules/ts-ebml/lib/tools.js":
/*!*******************************************!*\
  !*** ./node_modules/ts-ebml/lib/tools.js ***!
  \*******************************************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {

"use strict";

var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.convertEBMLDateToJSDate = exports.createFloatBuffer = exports.createIntBuffer = exports.createUIntBuffer = exports.encodeValueToBuffer = exports.concat = exports.putRefinedMetaData = exports.extractElement = exports.removeElement = exports.makeMetadataSeekable = exports.createRIFFChunk = exports.VP8BitStreamToRiffWebPBuffer = exports.WebPBlockFilter = exports.WebPFrameFilter = exports.encodeTag = exports.readBlock = exports.ebmlBlock = exports.writeVint = exports.readVint = void 0;
const int64_buffer_1 = __webpack_require__(/*! int64-buffer */ "./node_modules/int64-buffer/int64-buffer.js");
const EBMLEncoder_1 = __importDefault(__webpack_require__(/*! ./EBMLEncoder */ "./node_modules/ts-ebml/lib/EBMLEncoder.js"));
const { tools: _tools } = __webpack_require__(/*! ebml */ "./node_modules/ebml/lib/ebml.iife.js");
const _block = __webpack_require__(/*! ebml-block */ "./node_modules/ebml-block/index.js");
exports.readVint = _tools.readVint;
exports.writeVint = _tools.writeVint;

but ./node_modules/ebml/lib/ebml.iife.js doesn't exist.

vp9 support

hi,

First, this library really helps me!

I wonder if it is possible to use it for adding duration metadata to vp9 stream same way "example_seekable.ts" works for vp8.

thanks,
Roey

global is not defined

Uncaught ReferenceError: global is not defined
    at Object.../node_modules/buffer/index.js (background.js:1009)
    at __webpack_require__ (background.js:724)
    at fn (background.js:101)
    at Object.../node_modules/int64-buffer/int64-buffer.js (background.js:4580)
    at __webpack_require__ (background.js:724)
    at fn (background.js:101)
    at Object.../node_modules/ts-ebml/lib/tools.js (background.js:14299)
    at __webpack_require__ (background.js:724)
    at fn (background.js:101)
    at Object.../node_modules/ts-ebml/lib/EBMLDecoder.js (background.js:13520)

Chrome 76.0.3809.132
background.js of a Chrome extension

new maintainer

i dont have enough time to maintain this repository
anybody help?

ts-ebml - freezes all of Chrome when used in a Chrome Packaged App

Hey there - thanks for creating this awesome tool!

I'm trying to use this in my Chrome Packaged app for ChromeOS and I'm running into some strange behavior. Ts-ebml seems to cause both my app and the entire Chrome browser to freeze while it's processing. Given a small enough video file (about 1 minute or less on my Chromebook) Chrome will eventually unfreeze and ts-embl will create a seekable file. However larger files will crash and restart ChromeOS.

You can replicate this behavior on OSX by creating a Chrome Packaged app using example_seekable.html and the generated example_seekable.js files from your test folder along with the video file you're using to test. Then add the following manifest.json file.

{
  "name": "Seekable webm",
  "description": "Creating a seekable wemb using ts-ebml",
  "version": "1",
  "manifest_version": 2,
  "icons": {
    "16": "your_icon.png",
    "128": "your_icon.png"
  },
  "app": {
    "background": {
      "scripts": ["background.js"]
    }
  },
}

Load the app using the Chrome Apps & Extensions Tool. You'll notice that

  1. The video file takes longer to process in the Chrome Packaged app than it did in the browser.
  2. The app and the browser both freeze and cannot be interacted with while ts-ebml is processing.

These issues become more apparent when trying out longer video files. I'd appreciate any thoughts you may have on the subject.

正しいSeekHeadとCuesにする

CueClusterPositionSegment の中の最初の要素 (例えば SeekHead) のファイル先頭からのオフセットからの相対位置である必要がある。

example

mkvinfo matroska-test-files/test_files/test1.mkv -g

+ EBML head
+ Segment at 24
|+ Seek head at 32
|+ Segment information at 96
|+ Segment tracks at 307
|+ Tags at 472
|+ Cues at 634
| + Cue point at 640
|  + Cue time: 0.000s at 642
|  + Cue track position at 645
|   + Cue track: 1 at 647
|   + Cue cluster potision: 771 at 650
|   + ...
|+ Cluster at 803
| + Cluster timecode: 0.000s at 810
|+ ...

803 - 771 = 32

CueTrack は video track で良い。
CueTime は Cluster timecode` を使うと良い。

SeekHead は Segment 最初の要素かつ info, tracks, cues, (tags) のみ含むようにする

Cluster への参照は Cues のみにする。

performance of making a MediaRecorder webm seekable

Hi there,

This is more of a question / feature request.

Your example_seekable.ts works very well. However when the recording is big it will take a long time to process. E.g. I have a 2 and half hours recording of 2.5GB, the tools.makeMetadataSeekable function alone takes around 1 minute to complete.

I'm wondering can this be improved? Specifically, as we know the duration is roughly just the time between recording start and stop. With that, is it possible to just fill that duration information to the metadata of the original file to make it seeable?

Thanks!

The duration obtained from the webm is incorrect.Sometimes the length is correct, sometimes it's just tens of milliseconds. Ask for help !!!

code:
getSeekableBlob (inputBlob) {
return new Promise((resolve, reject) => {
var _this = this
var reader = new EBML.Reader()
var decoder = new EBML.Decoder()
var tools = EBML.tools
reader.logging = false
reader.drop_default_duration = true
_this.readAsArrayBuffer(inputBlob).then((buffer) => {
const elms = decoder.decode(buffer)
elms.forEach((elm) => { reader.read(elm) })
reader.stop()
console.log(reader.duration)
var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues)
var body = buffer.slice(reader.metadataSize)
const result = new Blob([refinedMetadataBuf, body], { type: inputBlob.type })
resolve(result)
})
})
},
readAsArrayBuffer (blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsArrayBuffer(blob)
reader.onloadend = () => { resolve(reader.result) }
reader.onerror = (ev) => { reject(ev.error) }
})
},

Error while using

I am getting the following error from ts compiler when I try to use this library:

TypeScript error: node_modules/ts-ebml/lib/ebml.d.ts(1,23): Error TS2688: Cannot find type definition file for 'node'.

Extraneous matroska dependency

As far as I understand, most of the changes from #42 were merged in but the matroska dependency was left around. I don't believe any code still uses it instead of matroska-schema so it should be removed. That would also then fix #40

Support reconstructing the length and cues in a webm

Hi! After w3c/mediacapture-record#119 (comment) I have been playing with emscripten-compiling libwebm, but I found this repo that might be able to produce the same result using more succinct code. The problem is essentially that MediaRecorder produces files that are not seekable, one because they have no Duration and second, perhaps, because they have no Cues. Is it something you could help with?

No duration data after convert

Good afternoon,
i'm try to detect the video duration but after finished converting there are no duration data in blob file.

Here the option code:

var options = {
controls: true,
fluid: false,
plugins: {
record: {
audio: true,
video: {
mandatory: {
minWidth: 1280,
minHeight: 720,
},
},
frameWidth: 1920,
frameHeight: 1080,
videoMimeType: 'video/webm;codecs=H264',
maxLength: 100,
debug: true,
convertEngine: 'ts-ebml'
}
}
};
schermata 2019-02-05 alle 11 10 45

ts-ebml reports wrong duration occasionally

Hey legokichi,

I'm still looking for a reproduction case here, but I've seen a couple of cases of this, so I wanted to report it to you. The setup is as follows:

In Chrome v60, hook MediaRecorder (audio-only) up to a ts-ebml Decoder. Start MediaRecorder with a timeslice of 5000ms. Each 5000ms chunk is fed into the Decoder, and the ts-ebml duration value is logged after each chunk. At a couple of points in a long (1hr) recording, ts-ebml suddenly reports a shorter duration, which is then correct again after the next chunk.

For example, here are the duration values reported after each chunk is decoded:

2017-09-07T19:50:56.052Z metadata.duration=1775299ms
2017-09-07T19:51:01.087Z metadata.duration=1780339ms
2017-09-07T19:51:06.127Z metadata.duration=1785379ms
2017-09-07T19:51:11.171Z metadata.duration=1790419ms
2017-09-07T19:51:16.211Z metadata.duration=1795459ms
2017-09-07T19:51:21.252Z metadata.duration=1770499ms	<--- suddenly reporting a *shorter* duration than previous
2017-09-07T19:51:26.298Z metadata.duration=1805539ms
2017-09-07T19:51:31.329Z metadata.duration=1810579ms

I also saw a point (in the same recording) where the duration increased, but not by the expected 5000ms, but after processing the next 5s chunk the duration was back to normal:

2017-09-07T19:42:40.818Z metadata.duration=1280069
2017-09-07T19:42:45.862Z metadata.duration=1285109
2017-09-07T19:42:50.911Z metadata.duration=1290151
2017-09-07T19:42:55.943Z metadata.duration=1295191
2017-09-07T19:43:02.332Z metadata.duration=1296929     <--- not 5s longer, as expected
2017-09-07T19:43:07.335Z metadata.duration=1306589
2017-09-07T19:43:12.374Z metadata.duration=1311629
2017-09-07T19:43:17.422Z metadata.duration=1316669

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.