Giter Club home page Giter Club logo

hls-stream-creator's Introduction

HLS-Stream-Creator

Introduction

HLS-Stream-Creator is a simple BASH Script designed to take a media file, segment it and create an M3U8 playlist for serving using HLS. There are numerous tools out there which are far better suited to the task, and offer many more options. This project only exists because I was asked to look into HTTP Live Streaming in depth, so after reading the IETF Draft I figured I'd start with the basics by creating a script to encode arbitrary video into a VOD style HLS feed.

Usage

Usage is incredibly simple

./HLS-Stream-Creator.sh -[CeflnS2] [-c segmentcount] -i [inputfile] -s [segmentlength(seconds)] -o [outputdir] -b [bitrates]

Deprecated Legacy usage:
HLS-Stream-Creator.sh inputfile segmentlength(seconds) [outputdir='./output']

So to split a video file called example.avi into segments of 10 seconds, we'd run

./HLS-Stream-Creator.sh -i example.avi -s 10

Arguments

Mandatory Arguments:

-i [file]	Input file
-s [s]		Segment length (seconds)

Optional Arguments:

-b [bitrates]	Output video Bitrates in kb/s (comma seperated list for adaptive streams)
-c [count]	Number of segments to include in playlist (live streams only) - 0 is no limit
-k [prefix]	String to prepend to Key path when encrpytion is used (e.g. https://mykeyserver.com/)
-K [Name]	Name of file for decryption key (will have .key appended)
-o [directory]	Output directory (default: ./output)
-p [name]	Playlist filename prefix
-q [quality]	Change encoding to CFR with [quality]
-t [name]	Segment filename prefix
-u [prefix]	Prefix to prepend to segment and manifest paths
-C		Use constant bitrate as opposed to variable bitrate
-e      	Encrypt the HLS segments (a key will be generated automatically)
-f		Foreground encoding only (adaptive non-live streams only)
-h              Print Usage information
-l		Input is a live stream
    -n              Ignore audio track in input file
-S		Name of a subdirectory to put segments into
-2		Use two-pass encoding

Adaptive Streams

As of HLS-6 the script can now generate adaptive streams with a top-level variant playlist for both VoD and Linear input streams.

In order to create seperate bitrate streams, pass a comma seperated list in with the -b option

./HLS-Stream-Creator.sh -i example.avi -s 10 -b 28,64,128,256

By default, transcoding for each bitrate will be forked into the background - if you wish to process the bitrates sequentially, pass the -f option

./HLS-Stream-Creator.sh -i example.avi -s 10 -b 28,64,128,256 -f

In either case, in accordance with the HLS spec, the audio bitrate will remain unchanged.

Multiple Resolutions

As of HLS-27 it is possible to (optionally) specify a resolution as well as the desired bitrate by appending it to the bitrate it applies to:

./HLS-Stream-Creator.sh -i example.avi -s 10 -b 128-600x400,256-1280x720,2000

In the example above, the first two bitrates will use their specified resolutions, whilst the last will use whatever resolution the source video uses.

The format to use is

[bitrate]-[width]x[height]

Note: There are currently no checks to ensure the specified resolution isn't larger than the source media, so you'll need to check this yourself (for the time being).

You should consider the potential ramifications of player behaviour before using this functionality.

Encrypted Streams

HLS-Stream-Creator can also create encrypted HLS streams, it's enabled by passing -e

./HLS-Stream-Creator.sh -i example.avi -e -s 10 -b 28,64,128,256

The script will generate a 128 bit key and save it to a .key file in the same directory as the segments. Each segment will be AES-128 encrypted using an IV which corresponds to it's segment number (the default behaviour for HLS).

The manifests will then be updated to include the necessary EXT-X-KEY tag:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-KEY:METHOD=AES-128,URI=big_buck_bunny_720p_stereo.avi.key
#EXT-X-TARGETDURATION:17
#EXTINF:10.500000,
big_buck_bunny_720p_stereo.avi_1372_00000.ts

Output

As of version 1, the HLS resources will be output to the directory output (unless a different directory has been specified with -o). These will consist of video segments encoded in H.264 with AAC audio and an m3u8 file in the format

#EXTM3U  
#EXT-X-MEDIA-SEQUENCE:0  
#EXT-X-VERSION:3  
#EXT-X-TARGETDURATION:10  
#EXTINF:10, no desc  
example_00001.ts  
#EXTINF:10, no desc  
example_00002.ts  
#EXTINF:10, no desc  
example_00003.ts  
#EXTINF:5, no desc  
example_00004.ts  
#EXT-X-ENDLIST

Using a Specific FFMPEG binary

There may be occasions where you don't want to use the ffmpeg that appears in PATH. At the top of the script, the ffmpeg command is defined, so change this to suit your needs

FFMPEG='/path/to/different/ffmpeg'

H265 details

Check has been added for libx265 to enforce bitrate limits for H265 since it uses additional parameters.

Audio Codec Availability

Because libfdk_aac is a non-free codec, and is not available in all builds, commit 0796feb switched the default audio codec to aac.

However, in older versions of ffmpeg, aac was marked as experimental - this includes the packages currently in the repos for Ubuntu Xenial. As a result, when running the script, you may see the following error

The encoder 'aac' is experimental but experimental codecs are not enabled, add '-strict -2' if you want to use it.

There are two ways to work around this. If you have the libfdk_aac codec installed, you can specify that it should be used instead

export AUDIO_CODEC="libfdk_aac"

Alternatively, you can update the ffmpeg flags to enable experimental codecs

export FFMPEG_FLAGS='-strict -2'

And the re-run HLS-Stream-Creator.

HLS-23 will, in future, update the script to check for this automatically.

Additional Environment Variables

There are few environment variables which can control the ffmpeg behaviour.

  • VIDEO_CODEC - The encoder which will be used by ffmpeg for video streams. Examples: libx264, nvenc
  • AUDIO_CODEC - Encoder for the audio streams. Examples: aac, libfdk_acc, mp3, libfaac
  • NUMTHREADS - A number which will be passed to the -threads argument of ffmpeg. Newer ffmpegs with modern libx264 encoders will use the optimal number of threads by default.
  • FFMPEG_FLAGS - Additional flags for ffmpeg. They will be passed without any modification.
  • FFMPEG_INPUT_FLAGS - Additional flags for ffmpeg which apply to the input file only. They will also be passed without any modification.

Example usage:

export VIDEO_CODEC="nvenc"
export FFMPEG_FLAGS="-pix_fmt yuv420p -profile:v"
./HLS-Stream-Creator.sh example.avi 10

OS X Users

Segment encryption won't work out of the box on OS X as it relies on arguments which the BSD grep and sed commands don't support. In order to use encryption on OS X you must first install their GNU counterparts

brew install gnu-sed
brew install grep

Note: As of HLS-33 it is no longer necessary to force brew to expose default names (since support has been dropped for --with-default-names).

It should be possible to get HLS-Stream-Creator up and running on a Mac by running the following

# Install Xcode
xcode-select --install

# Install brew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install ffmpeg

# Needed for segment encryption
brew install openssl 
brew install gnu-sed 
brew install grep

# Clone the codebase
git clone [email protected]:bentasker/HLS-Stream-Creator.git

Automation

HLS-Stream-Creator was originally created as a short bit of research and has since grown significantly. The consequence of this, is that it was primarily focused on being run manually.

Although still not a perfect solution to automation, an example of automating HLS-Stream-Creator can be found here. Better automation support will hopefully be added sometime in the future (pull requests very welcome).

License

HLS-Stream-Creator is licensed under the BSD 3 Clause License and is Copyright (C) 2013 Ben Tasker

Issue Tracking

Although the Github issue tracker can be used, the bulk of project management (such as it is) happens in JIRA. See projects.bentasker.co.uk for a HTML mirror of the tracking.

hls-stream-creator's People

Contributors

404networkerror avatar bentasker avatar egyptianbman avatar ironsmile avatar japseyz avatar kavuri avatar ndamiens avatar scips avatar skoushan avatar stonio 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hls-stream-creator's Issues

Scaling

It would be great if the script can also resize the videos along with existing multiple bi-rate feature. Is there any plan to add resizing feature?

Can't play m3u8

Just used the basic command to check

./HLS-Stream-Creator.sh -i test_file.mp4 -s 60

I can see the files in the output directory, but I cannot play it on VLC/QuickTime.

Even tried running it on HTML

<video width="100%" controls>
    <source src="test_file.mp4.m3u8" type="application/x-mpegURL">
</video>

It still doesn't work.

Also,
I want to use encryption, since for OSX I had to install using --with-default-names.
I get error Error: invalid option: --with-default-names

Running :
Mojave, iTerm2, ZSH

encrypted mp4 not playing in vlc or safari

created encrypted parts using

hls-stream-creater.sh -i ./small.mp4 -e -s 10 ./

it created successfully but now its not playing.

m3u8 file contents:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-KEY:METHOD=AES-128,URI=small.mp4.key
#EXT-X-TARGETDURATION:6
#EXTINF:5.600000,
small.mp4_00000.ts
#EXT-X-ENDLIST

Audio Bitrate Switch Missing

The script seems great though missing audio bitrate control switches while encoding for Adaptive streams, Along with Video bitrates, audio can also be scaled down, is it missing or intentional?

Encrypt is not working

Ben is possible to give me a short example for encrypting? I have all things installed but when I try to call function with -e option is noting happens! Thanks in advance!
p.s. I put everything is needed to conf

line 230: * 1000 : syntax error: operand expected (error token is "* 1000

First, thank you for this script. It is very helpful

I'm getting the error below for some video. Is there anything I can do


COMMAND ==> bash /tmp/y-batch/jobs/encode/HLS-Stream-Creator.sh -i /tmp/ca-develop-cdn-private-caseactive/2cd35405-d7ab-48f7-8d28-c5ebab93d2a1.mp4 -s 10 -b  -o /tmp/2cd35405-d7ab-48f7-8d28-c5ebab93d2a1

ffmpeg command found.... continuing

Creating ./output

/tmp/y-batch/jobs/encode/HLS-Stream-Creator.sh: line 230: * 1000 : syntax error: operand expected (error token is "* 1000 ")

No master playlist?

Hi

Amazingly beautiful script :-) Only problem is, I'm having problems generating a master playlist?
Also when passing multiple bitrates, only the first bitrate is shown:
Encoding for bitrate 256k completed
Encoding for bitrate k completed
Encoding for bitrate k completed

Error: Measured peak bitrate compared to master playlist declared value exceeds error tolerance

Hi @bentasker

Not sure if this is an issue because I get the same error if I test with various streams but curious on why you think this may be occurring.

If you download the hls validation tools from here https://developer.apple.com/download/more/?=http%20live%20streaming%20tools

And then run the mediastreamvalidator tool on a created playlist you should see errors similar to this.

--------------------------------------------------------------------------------
MUST fix issues
--------------------------------------------------------------------------------

Error: Measured peak bitrate compared to master playlist declared value exceeds error tolerance
--> Detail:  Measured: 590.99 kb/s, Master playlist: 256.00 kb/s, Error: 130.86%
--> Source:  mermaid.mov_master.m3u8
--> Compare: mermaid.mov_256.m3u8

--> Detail:  Measured: 395.00 kb/s, Master playlist: 128.00 kb/s, Error: 208.59%
--> Source:  mermaid.mov_master.m3u8
--> Compare: mermaid.mov_128.m3u8

--> Detail:  Measured: 260.27 kb/s, Master playlist: 28.00 kb/s, Error: 829.52%
--> Source:  mermaid.mov_master.m3u8
--> Compare: mermaid.mov_28.m3u8

--> Detail:  Measured: 282.60 kb/s, Master playlist: 64.00 kb/s, Error: 341.55%
--> Source:  mermaid.mov_master.m3u8
--> Compare: mermaid.mov_64.m3u8

Is this something to be concerned about or is it just a guide to follow.

Thanks

thanks you very much

your project help me a lot. i have take amost ten days to test ffmpeg. unti i five your projuct,

The files created with this script will not play on Android devices

I've just realized that none of my files will play on Android devices. I've spent over 3 months rendering over 1,000 videos and now it has come to my attention because none of my students are able to view the videos from their Android devices, only from iPhones and Laptops/Desktops.

No exit error statuses

I was trying to use this as part of a general video pipeline, but the script doesn't exit with error codes if there are any problems (other than the one check to verify that ffmpeg exists). This makes it hard to know if it succeeded or not.

$ HLS-Stream-Creator.sh -i non-existent-file.mp4 -s 3

ffmpeg command found.... continuing
Creating ./output
Generating HLS segments - this may take some time
ffmpeg version 3.3.4 Copyright (c) 2000-2017 the FFmpeg developers
  built with Apple LLVM version 9.0.0 (clang-900.0.37)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/3.3.4 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-libfdk-aac --enable-libfontconfig --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-opencl --enable-videotoolbox --disable-lzma --enable-nonfree --enable-vda
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libavresample   3.  5.  0 /  3.  5.  0
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
  libpostproc    54.  5.100 / 54.  5.100
non-existent-file.mp4: No such file or directory

$ echo $?  # Show the last command's exit status
0

Add prefix to routes

Hey.

Would there be any interest in an -u command which could take a string or url to prefix the paths with?

We are experimenting with storing all our segments etc. in S3 for testing, and a CDN later-on, and the URL for the .key will not be just be /video.key as per #EXT-X-KEY:METHOD=AES-128,URI=video.key

So if we could supply a -u https://bucket.aws.com/videos/id_1/ which would prefix all routes in manifests like:

$name$_master.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=512000
$prefix$video_512.m3u8

$name$_$bitrate$.m3u8

#EXT-X-KEY:METHOD=AES-128,URI=$prefix$video.key

My bash skills aren't superior, but I am sure I could cook something up if this would benefit the repo?

Bitrate missing from output when encoding forks are done

Hi,
great script. I've found a cosmetic issue, here's the output from a run. Note the bitrate number is missing from some of the the "encoding completed" lines.

#HLS-Stream-Creator.sh -i camera-01-20160209T101155.mp4 -s 10 -b 28,96,512,1600
ffmpeg command found.... continuing
Generating HLS segments for bitrate 28k - this may take some time
Generating HLS segments for bitrate 96k - this may take some time
Generating HLS segments for bitrate 512k - this may take some time
Generating HLS segments for bitrate 1600k - this may take some time
All transcoding processes started, awaiting completion
Encoding for bitrate (0) 28k completed
Encoding for bitrate (0) k completed
Encoding for bitrate (0) k completed
Encoding for bitrate (0) k completed

I believe it's to do with the way the PIDS array is emptied. If you reverse the order of the bitrates (and hence they are likely to finish last to first, then the output is ok.

Thanks

Works great but...

Hi

It seems to work well but seems to be creating video files that are way bigger than the set bitrates:

I checked a stream made with this at http://krishnatube.com/output/1.mp4_master.m3u8 and the apple mediastreamvalidator is giving the following error messages:

Error: Measured peak bitrate compared to master playlist declared value exceeds error tolerance
--> Detail: Measured: 222.58 kb/s, Master playlist: 28.00 kb/s, Error: 87.42%
--> Source: http://krishnatube.com/output/1.mp4_master.m3u8
--> Compare: 1.mp4_28.m3u8

--> Detail: Measured: 344.47 kb/s, Master playlist: 128.00 kb/s, Error: 62.84%
--> Source: http://krishnatube.com/output/1.mp4_master.m3u8
--> Compare: 1.mp4_128.m3u8

--> Detail: Measured: 270.08 kb/s, Master playlist: 64.00 kb/s, Error: 76.30%
--> Source: http://krishnatube.com/output/1.mp4_master.m3u8
--> Compare: 1.mp4_64.m3u8

--> Detail: Measured: 512.63 kb/s, Master playlist: 256.00 kb/s, Error: 50.06%
--> Source: http://krishnatube.com/output/1.mp4_master.m3u8
--> Compare: 1.mp4_256.m3u8

Also is there any chance of being able to specify the frame rate? If original video is 60 frames per second for example to change that to 25 frames per second, maybe even different frames per second for the different variants?

Audio Bitrate?

Hi,
I would like to know how to add a audio bitrate along with video bitrate

invalid command code f

Encoding for bitrate 1024k completed
Generating Encryption Key
Encrypting Segments
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]
Updating Manifests
sed: 1: "/Users/freenetwork/Desk ...": invalid command code f
sed: 1: "/Users/freenetwork/Desk ...": invalid command code f

MacOS Sierra

Issue on Ubuntu

Hi,

First of all, thank you so much for your script. Its really awesome. I've been using it on my mac for a couple of months.

I've just attempted to move the script to my Ubuntu 16.04 server and I'm getting lots of syntax error's such as:

"(" unexpected

for the function:

function print_usage(){

Should this work ok on Ubuntu or do I need to do some work on it?

Thanks,
Jamie

Let limit

The let command has "limit size of base".

./HLS-Stream-Creator.sh: línea 173: let: 09: valor demasiado grande para la base (el elemento de error es "09")

I changed to expr and I solved

# Calculate the duration in seconds
DURATION_S=$(expr \( $DUR_H \* 60 + $DUR_M \) \* 60 + $DUR_X)

Question about ad insertion

Hi Ben,

Not an issue more of a question we are looking into adding add cue tags into our m3u8 manifest file and don't understand the process from what I understand you need to add.

#EXT-X-CUE-OUT:60.00
#EXT-X-CUE-IN

Throughout the manifest Is this possible with your repo or do you know how this would be achieved programmatically.

Feel free to just close if this is not related or doesn't interest you thought it was worth asking?

Thanks

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.