forked from bytedance/xgplayer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into xgplayer-2
- Loading branch information
Showing
67 changed files
with
4,115 additions
and
12,829 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,3 @@ | ||
module.exports = { | ||
"parser": "babel-eslint", | ||
"extends": "standard", | ||
"rules": { | ||
"semi": 0 | ||
}, | ||
"overrides": [ | ||
{ | ||
"files": ["packages/**/**.js"], | ||
"globals": { | ||
"fetch": true, | ||
"Headers": true | ||
} | ||
} | ||
] | ||
}; | ||
"extends": "standard" | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,12 +12,17 @@ | |
<img src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg" alt="commitizen"> | ||
</a> | ||
</div> | ||
<br> | ||
|
||
English | [简体中文](README.zh-CN.md) | ||
|
||
### Introduction | ||
|
||
xgplayer is a web video player library. It has designed a separate, detachable UI component based on the principle that everything is componentized. More importantly, it is not only flexible in the UI layer, but also bold in its functionality: it gets rid of video loading, buffering, and format support for video dependence. Especially on mp4 | ||
it can be staged loading for that does not support streaming mp4. This means seamless switching with clarity, load control, and video savings. It also integrates on-demand and live support for FLV, HLS, and dash. [Document](http://h5player.bytedance.com/en/) | ||
xgplayer is a web video and audio player library, designed with separate, detachable UI components. Since everything is componentized. the UI layer is very flexable. | ||
xgplayer is bold in its functionality: it gets rid of video loading, buffering, and format support for video dependence. | ||
For mp4 that does not support streaming, you can use staged loading. This means load control, seamless switching without artifacts, and video bandwidth savings. It also integrates on-demand and live support for FLV, HLS, and dash. | ||
|
||
For more details, please read the [Documentation](http://h5player.bytedance.com/en/). | ||
|
||
### Start | ||
|
||
|
@@ -45,7 +50,7 @@ it can be staged loading for that does not support streaming mp4. This means sea | |
}) | ||
``` | ||
This is the easiest way to configure the player, then it runs with video. For more advanced content, see the plug-in section or documentation. [more config](http://h5player.bytedance.com/en/config/) | ||
This is the easiest way to configure the video player. For more advanced content, see the plug-in section or documentation. [more config](http://h5player.bytedance.com/en/config/) | ||
|
@@ -72,13 +77,13 @@ const player = new Player({ | |
|
||
### Mobile Support | ||
|
||
xgplayer supports mobile terminal, but android device brand and system are numerous, there are much compatibility problems, the player provides whitelist mechanism to ensure the perfect operation in mobile terminal. [whitelist](http://h5player.bytedance.com/en/config/#whitelist) | ||
xgplayer supports mobile devices, but android brands and system customizations are numerous. Since there may be compatibility problems, the player provides a whitelist mechanism to ensure perfect operation in mobile devices. [whitelist configuration](http://h5player.bytedance.com/en/config/#whitelist) | ||
|
||
|
||
|
||
### Dev | ||
|
||
For debugging, we provide the example video resource which size is large in github. You can clone the whole git repository which includes codes and example videos with 'git clone --recurse-submodules -j8'. With 'git clone' you will pull only codes of xgplayer and its plugins. | ||
For debugging, we provide example video files in github. You can clone the whole git repository, which includes both code and example videos with 'git clone --recurse-submodules -j8'. With 'git clone' you will pull only xgplayer code and its plugins. | ||
|
||
``` | ||
$ git clone --recurse-submodules -j8 [email protected]:bytedance/xgplayer.git # OR git clone [email protected]:bytedance/xgplayer.git | ||
|
@@ -87,7 +92,7 @@ $ npm install | |
$ npm run dev | ||
``` | ||
|
||
please visit [http://localhost:9090/examples/index.html](http://localhost:9090/examples/index.html) | ||
Then visit [http://localhost:9090/examples/index.html](http://localhost:9090/examples/index.html) | ||
|
||
|
||
### Agreement | ||
|
@@ -96,3 +101,7 @@ Welcome to use xgplayer! Please read the following terms carefully. Using xgplay | |
1. Xgplayer is licensed under the [MIT](http://opensource.org/licenses/MIT) License. You comply with its obligations by default. | ||
2. By default, you authorize us to place your logo in xgplayer website, which using xgplayer. | ||
If you have any problem, please let us know. | ||
|
||
|
||
### Join Us | ||
We welcome anyone with an interest in web media technology to join! Please contact us at [email protected] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
</a> | ||
</div> | ||
|
||
[English](README.md) | 简体中文 | ||
|
||
### 概述 | ||
|
||
|
@@ -98,3 +99,14 @@ $ npm run dev | |
1. 本开源项目中所有代码基于 [MIT](http://opensource.org/licenses/MIT) 许可协议,您默认遵守许可协议中约定的义务。 | ||
2. 您默认授权我们将您使用西瓜播放器所在业务的Logo放置在本官网展示。 | ||
若您有任何问题,请联系我们。 | ||
|
||
### 加入我们 | ||
欢迎各位对前端音视频感兴趣的小伙伴加入我们的技术团队! | ||
|
||
工作地点:北京、上海、深圳等 | ||
|
||
岗位类型:社招、校招、实习 | ||
|
||
发送简历:[email protected] | ||
|
||
邮件标题格式:【简历】+ 姓名 + 前端开发工程师 + 来源:xgplayer github |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule examples
updated
from 5a1973 to 231af2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,5 +17,5 @@ | |
}, | ||
"cacheDir": ".changelog" | ||
}, | ||
"version": "1.1.6-alpha.0" | ||
"version": "1.1.5" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
// refrence: https://github.com/video-dev/hls.js/blob/master/src/demux/adts.js | ||
import Demuxer from './Demuxer' | ||
import DataView4Read from '../../utils/DataView4Read' | ||
// import { mp3Versions, mp3BitRate, audioSampleRate } from '../../constants/types'; | ||
import { | ||
soundRateTypes, | ||
samplingFrequencyTypes, | ||
EventTypes, | ||
browserTypes | ||
} from '../../constants/types' | ||
import sniffer from '../../utils/sniffer' | ||
import Buffer from '../../write/Buffer' | ||
export default class AudioDemuxer extends Demuxer { | ||
constructor (store) { | ||
super(store) | ||
this.CLASS_NAME = this.constructor.name | ||
this.currentTag = null | ||
this.data = new Uint8Array(0) | ||
this.readOffset = 0 | ||
this._store.audioMetaData = null | ||
this.handleDataReady = () => {} | ||
this.handleMetaDataReady = () => {} | ||
this.handleMediaInfoReady = () => {} | ||
} | ||
resolve (tag) { | ||
this.readOffset = 0 | ||
const { _store: store } = this | ||
const { audioTrack: track } = store | ||
this.currentTag = tag | ||
this.data = tag.body | ||
let { | ||
audioMetaData: meta | ||
} = store | ||
|
||
if (!meta) { | ||
meta = store.audioMetaData = {} | ||
store.audioMetaData = this.initAudioMeta(meta) | ||
} | ||
|
||
const dv = new DataView4Read(tag.body.buffer, this) | ||
|
||
const sound = dv.getUint8() | ||
|
||
const soundFormatIdx = sound >>> 4 // UInt4 | ||
const soundRate = (sound & 12) >>> 2 // UInt2 | ||
// const soundSize = (sound & 2) >>> 1 // UInt1 | ||
const soundType = (sound % 1) // UInt1 | ||
|
||
meta.audioSampleRate = soundRateTypes[soundRate] | ||
meta.channelCount = soundType === 0 ? 1 : 2 | ||
|
||
if (soundFormatIdx !== 10 && soundFormatIdx !== 2) { | ||
this.error('only support AAC Audio format so far') | ||
return | ||
} else if (soundFormatIdx === 10) { // AAC | ||
const aacInfo = this._parseAACAudio() | ||
if (!aacInfo) { | ||
return | ||
} | ||
|
||
const { data: aacData, data: { sampleFreq } } = aacInfo | ||
if (aacInfo.packetType === 0) { // AAC sequence header | ||
meta.sampleRate = sampleFreq | ||
meta.channelCount = aacData.channelCount | ||
meta.codec = aacData.codec | ||
meta.manifestCodec = aacData.manifestCodec | ||
meta.config = aacData.config | ||
meta.refSampleDuration = 1024 / sampleFreq * meta.timeScale | ||
if (store.hasInitialMetaDispatched) { | ||
if (store.videoTrack.length || store.audioTrack.length) { | ||
this.handleDataReady(store.videoTrack, store.audioTrack) | ||
} | ||
} else { | ||
store.state._audioInitialMetadataDispatched = true | ||
} | ||
|
||
this.handleMetaDataReady('audio', meta) | ||
|
||
const { mediaInfo: mi } = store | ||
mi.audioCodec = meta.codec | ||
mi.audioSampleRate = meta.sampleRate | ||
mi.audioChannelCount = meta.channelCount | ||
mi.audioConfig = meta.config | ||
if (mi.hasVideo) { | ||
if (mi.videoCodec) { | ||
mi.mimeType = `video/x-flv; codecs="${mi.videoCodec},${mi.audioCodec}"` | ||
mi.codec = mi.mimeType.replace('x-flv', 'mp4') | ||
} | ||
} else { | ||
mi.mimeType = `video/x-flv; codecs="${mi.audioCodec}"` | ||
mi.codec = mi.mimeType.replace('x-flv', 'mp4') | ||
} | ||
|
||
if (mi.isComplete) { | ||
this.handleMediaInfoReady(mi) | ||
} | ||
} else if (aacInfo.packetType === 1) { // AAC raw frame data | ||
let dts = store.state.timeStampBase + this.currentTag.getTime() | ||
let aacSample = { unit: aacInfo.data, length: aacInfo.data.byteLength, dts: dts, pts: dts } | ||
track.samples.push(aacSample) | ||
track.length += aacInfo.data.length | ||
} | ||
} | ||
|
||
this.resetStatus() | ||
} | ||
|
||
_parseAACAudio () { | ||
if (this.unreadLength <= 1) { | ||
return | ||
} | ||
const aacData = {} | ||
let aacArray = new Uint8Array(this.data.buffer, this.readOffset, this.unreadLength) | ||
const packetType = aacArray[0] | ||
this.readOffset += 1 | ||
aacData.packetType = packetType | ||
if (!packetType) { | ||
const { position, tagSize } = this.currentTag | ||
this._store.metaEndPosition = position + Buffer.readAsInt(tagSize) + 4 | ||
aacData.data = this._parseAACAudioSpecificConfig() // AAC Sequence header | ||
} else { | ||
aacData.data = aacArray.slice(1) | ||
} | ||
|
||
return aacData | ||
} | ||
_parseAACAudioSpecificConfig () { | ||
const dv = new DataView4Read(this.data.buffer, this) | ||
const { getAndNum } = DataView4Read | ||
|
||
let resultObj = { | ||
samplingFrequency: null, | ||
extAudioObjectType: null, | ||
extAudioSamplingIdx: null | ||
} | ||
let config = {} | ||
const UInt0 = dv.getUint8() | ||
const UInt1 = dv.getUint8() | ||
|
||
let tempAudioObjectType | ||
let audioObjectType = tempAudioObjectType = UInt0 >>> 3 // UInt5 | ||
let samplingIdx = ((UInt0 & getAndNum(5, 7)) << 1) | (UInt1 >>> 7) // UInt4 | ||
if (samplingIdx < 0 || samplingIdx > samplingFrequencyTypes.length) { | ||
this.emitError('decoder', { | ||
line: '141', | ||
handle: '_parseAACAudioSpecificConfig', | ||
msg: `invalid samplingFrequencyIndex ${samplingIdx}` | ||
}) | ||
this.dispatch(EventTypes.ERROR, `error samplingFrequencyIndex: ${samplingIdx}`) | ||
return | ||
} | ||
|
||
resultObj.samplingFrequency = samplingFrequencyTypes[samplingIdx] | ||
|
||
let channelCount = resultObj.channelCount = (UInt1 & getAndNum(1, 4)) >>> 3 | ||
if (channelCount < 0 || channelCount > 7) { | ||
this.emitError('decoder', { | ||
line: '154', | ||
handle: '_parseAACAudioSpecificConfig', | ||
msg: `invalid Audio Channel Count: ${channelCount}` | ||
}) | ||
this.dispatch(EventTypes.ERROR, `error Audio Channel Count: ${channelCount}`) | ||
return | ||
} | ||
|
||
if (audioObjectType === 5) { // HE-AAC | ||
const UInt2 = dv.getUint8() | ||
resultObj.extAudioSamplingIdx = ((UInt1 & getAndNum(5, 7)) << 1) | UInt2 >>> 7 | ||
resultObj.extAudioObjectType = (UInt2 & getAndNum(1, 5)) >>> 2 | ||
} | ||
|
||
if (sniffer.browser === browserTypes.FIRE_FOX) { | ||
if (samplingIdx >= 6) { | ||
// HE-AAC uses SBR, high frequencies are constructed from low frequencies | ||
audioObjectType = 5 | ||
config = new Array(4) | ||
resultObj.extAudioSamplingIdx = samplingIdx - 3 | ||
} else { | ||
audioObjectType = 2 | ||
config = new Array(2) | ||
resultObj.extAudioSamplingIdx = samplingIdx | ||
} | ||
} else if (sniffer.os.isAndroid) { | ||
// Android : always use AAC | ||
audioObjectType = 2 | ||
config = new Array(2) | ||
resultObj.extAudioSamplingIdx = samplingIdx | ||
} else { | ||
/* for other browsers (Chrome/Vivaldi/Opera ...) | ||
always force audio type to be HE-AAC SBR, as some browsers do not support audio codec switch properly (like Chrome ...) | ||
*/ | ||
audioObjectType = 5 | ||
resultObj.extensionSamplingIndex = samplingIdx | ||
config = new Array(4) | ||
|
||
if (samplingIdx >= 6) { | ||
resultObj.extensionSamplingIdx = samplingIdx - 3 | ||
} else if (channelCount === 1) { | ||
audioObjectType = 2 | ||
config = new Array(2) | ||
resultObj.extensionSamplingIndex = samplingIdx | ||
} | ||
} | ||
|
||
config[0] = audioObjectType << 3 | ||
config[0] |= (samplingIdx & 0x0E) >> 1 | ||
config[1] |= (samplingIdx & 0x01) << 7 | ||
config[1] |= channelCount << 3 | ||
if (audioObjectType === 5) { | ||
config[1] |= (resultObj.extAudioSamplingIdx & 0x0E) >> 1 | ||
config[2] = (resultObj.extensionSamplingIdx & 0x01) << 7 | ||
// adtsObjectType (force to 2, chrome is checking that object type is less than 5 ??? | ||
// https://chromium.googlesource.com/chromium/src.git/+/master/media/formats/mp4/aac.cc | ||
config[2] |= 2 << 2 | ||
config[3] = 0 | ||
} | ||
|
||
return { | ||
config, | ||
sampleFreq: resultObj.samplingFrequency, | ||
channelCount, | ||
codec: `mp4a.40.${audioObjectType}`, | ||
manifestCodec: `mp4a.40.${tempAudioObjectType}` | ||
} | ||
} | ||
|
||
initAudioMeta (meta) { | ||
const { state, audioTrack: track } = this._store | ||
|
||
meta.duration = state.duration | ||
meta.timeScale = state.timeScale | ||
meta.type = 'audio' | ||
meta.id = track.id | ||
|
||
return meta | ||
} | ||
|
||
resetStatus () { | ||
this.currentTag = null | ||
this.data = new Uint8Array(0) | ||
this.readOffset = 0 | ||
} | ||
get dataSize () { | ||
return this.data.length | ||
} | ||
|
||
get unreadLength () { | ||
return this.dataSize - this.readOffset | ||
} | ||
} |
Oops, something went wrong.