Giter VIP home page Giter VIP logo

hls.js's Introduction

HLS.js

What?

HLS.js is a pure-JS+HTML5, no-Flash, no-plugins, implementation of an HTTP Live Streaming video player. Development is sponsored by the Brigham Young University Office of Digital Humanities.

HLS.js is aimed at developers creating more featureful video players who want to include HLS support on non-Apple devices. It is not aimed at people who just want to drop a video into a webpage with a pre-made embed code and forget about it. HLS.js will take you from "URL to an m3u8 manifest file" to "drawing pixels on the screen and piping sound to the speakers", and attempts to duplicate the standard HTML5 MediaElement API as closely as possible, but it does not come with any built-in UI. You have to build that yourself.

At the moment, HLS.js only supports Media Playlists (not Master Playlists) in VOD (not live streaming) mode. However, more features are planned, and contributions are welcome.

Why?

Initial development was motivated by the need for a simple HLS plugin for the Ayamel Media Player to allow for encrypted streaming of long-form video content for university language courses, where a simple HTML5 video element is considered insufficiently secure against potential piracy, directly from privately-controlled servers and without requiring students to install any plugins. Previous solutions either required uploading content to a third-party content management system (e.g., Youtube, Vimeo, Ooyala, Brightcove, etc.), the use of Flash video players, which will not run on all devices, unacceptable technology licensing restrictions, or some combination of the above.

hls.js's People

Contributors

gliese1337 avatar dependabot[bot] avatar johnlarson avatar donato avatar

Stargazers

 avatar baitian avatar ROBERT MCDOWELL avatar  avatar Maik Marschner avatar Ravi van Rooijen avatar fralonra avatar Jignesh Patil avatar Rishi avatar Chad Smith avatar Daniel Schultz avatar W. ❝Mac❞ McMeans avatar  avatar Dave luo avatar movii avatar Tareq Halaby avatar TonyYan avatar zeromike avatar Ian Zhang avatar Sokolov Yura avatar Michael Forrest avatar Brian Riley avatar  avatar Blain Smith avatar Leandro Moreira avatar Flavio Ribeiro avatar 僵尸浩 avatar Bob Junior avatar Edward Zhu avatar David Laster avatar Chris Marshall avatar François LASSERRE avatar Luca Nils Schmid avatar Eli avatar  avatar albert avatar Rack Lin (阿土伯) avatar Hsin-lin Cheng avatar Zhiping Yang avatar Tony Yet avatar Chia-liang Kao avatar John McMellen avatar Ed Glazer avatar Sfia Daniel-Andrei avatar  avatar europelee avatar Tom Jenkinson avatar MKZE avatar Mihail Chilyashev avatar John Manos avatar Kyle Parisi avatar  avatar Jarom McDonald avatar

Watchers

Flavio Ribeiro avatar Nate Burr avatar Clément Vasseur avatar Gary hilgemann avatar  avatar James Cloos avatar Tony Yet avatar Guillaume du Pontavice avatar  avatar Jarom McDonald avatar  avatar

hls.js's Issues

SPS parse failure

Here's the sprop-parameter-sets:

a=fmtp:96 packetization-mode=1;profile-level-id=4D0029;sprop-parameter-sets=J00AKedAPAET8s1AQEB8AAADAAQAAAMAoNGADqYAFfl//wKA,KO48gA==
const sps = Buffer.from('J00AKedAPAET8s1AQEB8AAADAAQAAAMAoNGADqYAFfl//wKA', 'base64');
const pps = Buffer.from('KO48gA==', 'base64');

This may be invalid data? But it is what Wyze cameras are returning in their SDP (and throwing during parse).

/Volumes/Dev/scrypted/plugins/prebuffer-mixin/node_modules/h264-sps-parser/dist/bitstream.js:17
            byt = view.getUint8(byteoffset);
                       ^

Uncaught RangeError: Offset is outside the bounds of the DataView
    at DataView.getUint8 (<anonymous>)
    at ExpGolomInit (/Volumes/Dev/scrypted/plugins/prebuffer-mixin/node_modules/h264-sps-parser/dist/bitstream.js:17:24)
    at Bitstream.ExpGolomb (/Volumes/Dev/scrypted/plugins/prebuffer-mixin/node_modules/h264-sps-parser/dist/bitstream.js:30:49)
    at hrd_parameters (/Volumes/Dev/scrypted/plugins/prebuffer-mixin/node_modules/h264-sps-parser/dist/vui.js:9:40)
    at Object.getVUIParams (/Volumes/Dev/scrypted/plugins/prebuffer-mixin/node_modules/h264-sps-parser/dist/vui.js:105:9)
    at Object.parse (/Volumes/Dev/scrypted/plugins/prebuffer-mixin/node_modules/h264-sps-parser/dist/index.js:111:34)
    at /Volumes/Dev/scrypted/plugins/prebuffer-mixin/<repl>.ts:1:4
    at Script.runInThisContext (node:vm:129:12)
    at runInContext (/Users/koush/.nvm/versions/node/v18.14.2/lib/node_modules/ts-node/src/repl.ts:673:19)
    at Object.execCommand (/Users/koush/.nvm/versions/node/v18.14.2/lib/node_modules/ts-node/src/repl.ts:639:28)

Suggestions on getting pts_time?

First: thank you so much for this project, it's going to be a huge help for something we're building.

I want to convert the dts to an actual timestamp. My understanding is that this is based on the stream timebase. My further understanding is that this defaults to 90,000 for mpegts, but I'm worried about relying on a default rather than expliclty parsing the timebase for a given stream.

Do you know if TSDecoder might eventually parse that timebase and use it to expose a pts_time?

Respect X-BYTERANGE Tags

Byte ranges are described in the following section of the spec: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.2.2

The M3U8 parser already handles extracting the necessary metadata for a byterange segment, but this is ignored when actually requesting files.

We can use XMLHttpRequest.prototype.setRequestHeader to set the "Range" header to request only the needed bytes, but some servers will ignore that. Hopefully, anybody who produces a manifest file with byteranges would also configure their host server to serve them properly, but just in case we'll need to check the actual returned range in the response as well (we should get a 206 Partial Content response with a Content-Range header field).

It might also make sense to move the logic for requesting data chunks into the M3U8Manifest object rather than keeping it in player.js.

Handling PTS rollovers

While we're talking about PTS over in #15 -- my understanding is that MPEGTS can actually have PTS rollovers after a few weeks of a constant stream (since PTS eventually does max out, no matter how many bits the demuxer can handle!)

Right now there is logic to explicitly prevent pts from decreasing. I'm not sure if that is part of other demuxers out there / wonder if maybe that logic should be removed in order to support those rare rollovers.

Firefox Doesn't Like Our ESDS

The ESDS box, part of the metadata for audio tracks, is generated at

function esds(trkdata){

I attempted to write this straight from the MPEG specs, but it is entirely possible that I screwed something up. Chrome and Windows Media Player play the generated files just fine, but Firefox chokes on them and claims the files are corrupted. I know it's the ESDS box that is the problem because copying an ESDS block (and updating all of the appropriate box size fields) from an equivalent MP4 file generated by https://github.com/RReverser/mpegts or ffmpeg for the same .ts input and substituting it into my generated MP4 files in a hex editor produces files that Firefox is perfectly happy to play.

So, not sure if it's a problem with my ESDS box, which other players are somehow capable of ignoring, or a problem with Firefox. Probably the former, but either way I have no clue how to fix it.

Demuxed opus packet is corrupt

I generated an opus stream in gstreamer and muxed it into ts: gst-launch-1.0 audiotestsrc ! opusenc ! mpegtsmux ! filesink location=out.ts.

The opus stream in this file has 160 byte packets, but when I decode it with ts-demuxer, it returns 163 byte packets, where the first 3 bytes are always the same: [127, 224, 160]. If I remove the first 3 bytes manually, the decoder can decode the stream again.

I don't have a good understanding of the ts format, so I don't why this happens. For now, I can work around this by slicing off the first three bytes, but it would be nice to have this fixed here.

Too much audio, too little video.

Comparison with other transmuxers shows that I'm dropping a small amount of data at the end of the video stream. Thought I fixed this once already, but apparently it's happening somewhere after the demuxer.

Audio data, however, is getting extra bytes inserted into it sporadically, throughout the audio data stream.

One or both of these problems is probably responsible for the audio corruption issue in Windows Media & Firefox.

Integer overflows when processing PTS

When a single stream is processed for a while (around 5.5 hours) the PTS values actually get so large that they go past 2147479560 and overflow.

In the C code that the demuxer was ported from the use an unsigned 64 bit int to store the PTS values -- JavaScript is a bit different unfortunately and stores numbers as floats. For me this results in PTS values swappin' over to negative.

One solution would be to use BigInt but that is not supported in Internet Explorer.

SPS parsing incorrect

hi! just wanted to report a quick bug in the SPS parser. for the following SPS:

6764001fad84010c20086100430802184010c200843b502802dd35010101400145d8c04c4b4025

the parser reports:

  num_units_in_tick: 4295300963,
  time_scale: 12904901888,
  fixed_frame_rate_flag: 1,

instead of

  num_units_in_tick: 333667,
  time_scale: 20000000,
  fixed_frame_rate_flag: 1,

Refactor M3U8 parser as object

At the moment, the only interface to the M3U8 implementation is a single parseHLS function which takes the text of an m3u8 file and returns a promise for a list of segments. This makes it very difficult to handle live streams, which requires re-requesting the manifest file at regular intervals to get the updated segment lists.

Ideally, we'd instead have an M3U8 object that knows the URL to the manifest file and fires events to notify the player when new segments are available. This will, of course, also require refactoring in the player to handle the changed interface.

Offset is outside the bounds of the DataView

Piping an ffmpeg-generated mpegts stream and after a few minutes I occasionally get the following error:

/Users/slifty/Dropbox/Code/NodeJS/tvkitchen/appliances/node_modules/ts-demuxer/dist/index.js:402
  	throw e
  	^

RangeError: Offset is outside the bounds of the DataView
    at DataView.getUint8 (<anonymous>)
    at demux_packet (/Users/slifty/Dropbox/Code/NodeJS/tvkitchen/appliances/node_modules/ts-demuxer/dist/index.js:398:13)
    at TSDemuxer.process (/Users/slifty/Dropbox/Code/NodeJS/tvkitchen/appliances/node_modules/ts-demuxer/dist/index.js:477:23)
    at Transform._transform (/Users/slifty/Dropbox/Code/NodeJS/tvkitchen/appliances/packages/core/lib/AbstractVideoIngestionAppliance.js:82:26)
    at Transform._read (_stream_transform.js:191:10)
    at Transform._write (_stream_transform.js:179:12)
    at doWrite (_stream_writable.js:454:12)
    at writeOrBuffer (_stream_writable.js:436:5)
    at Transform.Writable.write (_stream_writable.js:327:11)
    at Socket.ondata (_stream_readable.js:708:22)
error Command failed with exit code 1.

I did some debugging and it turns out that ptr has a negative value (e.g. -112), so it makes sense that is out of bounds. I haven't yet figured out what about the data leads ptr to that state but I will spend some time on that.

More broadly, though, I know that you're not actively working on this project. If I do come up with a patch are you in a position to integrate it or should I look into forking and releasing a new package?

Why mux AAC into mp4?

Hey @gliese1337, I just realized we can push aac directly into the video tag - is there a benefit to muxing it into mp4 first?
I imagine it may work better for synchronization, but I'm curious if you've considered this already.

PMT decode fails to recognise AAC audio

Hi,

I needed to parse MPEG-TS in the browser, and came across this project which looks absolutely great. Thanks for your work!

I have however run into a problem: I can't seem to get audio packets demuxed. I've debugged the code, and I believe I have found a bug in the PMT parsing logic:

Assume a PMT with an entry for audio PID 0x22 encoded with AAC (stream_type 0x0f). The PMT will contain (hex): 0f e0 22. During parsing, https://github.com/gliese1337/HLS.js/blob/master/demuxer/src/pmt.ts#L125 will map the 0x0f into stream_type.aac_audio, which equals 7.
Later in the same function, this type is mapped again by a call to get_media_type(), but that function doesn't recognise the value 7/stream_type.aac_audio. This results in stream_type.unknown, which is ignored for further decoding.

I tried to understand why the mapping is done in two phases, so I could create a Pull Request with a patch. But I don't understand the logic behind the code (yet). Also, AAC seems to be a very popular codec nowadays, so I'm a bit surprised this doesn't "just work" and I suspect I may be missing things...

Thank you in advance for looking into this

Potential bug(s) with leftover processing

I'm currently in the process of mapping out the processing logic and I'm trying to understand the current logic around partial packet processing / think there might be a bug lurking.

I wanted to run it by you in case I should open a patch.

It's related to this code:

    // If we ended on a partial packet last
    // time, finish that packet first.
    if (remainder > 0) {
      if (len < remainder) {
        this.leftover.set(buffer.subarray(offset, offset + len), this.ptr);
        return 1; // still have an incomplete packet
      }

In particular, I'm not sure of a few things here:

  1. Why is the conditional if (len < remainder) as opposed to if (len + remainder < PACKET_LEN)

It seems to me that the logic as written could result in a situation where the remainder was, say, 150, and the new data had a length of 140. The result would be 150 + 140 = 290 which is well above PACKET_LEN (188) and could very well be a new packet (but is being skipped).

  1. Why isn't this.ptr updated? My understanding is that this.ptr is supposed to indicate how much data is in this.leftover. When we add data to the leftover and return without processing, but without updating this.ptr that data would be overwritten the next time process() is invoked, right?

  2. this.ptr is also potentially not updated later in this conditional.

Hopefully this makes sense; please forgive me if I'm just misunderstanding the point of this.ptr / len / remainder

Support for WebCodecs

Is there a way to make ts-demuxer work with new browser features like WebCodecs and Streams API?
As mentioned in this article from web.dev, three parameters are needed to create an EncodedVideoChunk instance.

  • A BufferSource of encoded video data
  • the chunk's start timestamp in microseconds (media time of the first encoded frame in the chunk)
  • the chunk's type (possible values - 'key' or 'delta')

As of now, ts-demuxer gives the BufferSource, but not the timestamp and the chunk's type. Is it possible to determine/calculate these two values from the existing output to make it work with WebCodecs?

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.