1
+ import window from 'global/window' ;
2
+
3
+ const regexs = {
4
+ // to determine mime types
5
+ mp4 : / ^ ( a v 0 ? 1 | a v c 0 ? [ 1 2 3 4 ] | v p 0 ? 9 | f l a c | o p u s | m p 3 | m p 4 a | m p 4 v ) / ,
6
+ webm : / ^ ( v p 0 ? [ 8 9 ] | a v 0 ? 1 | o p u s | v o r b i s ) / ,
7
+ ogg : / ^ ( v p 0 ? [ 8 9 ] | t h e o r a | f l a c | o p u s | v o r b i s ) / ,
8
+
9
+ // to determine if a codec is audio or video
10
+ video : / ^ ( a v 0 ? 1 | a v c 0 ? [ 1 2 3 4 ] | v p 0 ? [ 8 9 ] | h v c 1 | h e v 1 | t h e o r a | m p 4 v ) / ,
11
+ audio : / ^ ( m p 4 a | f l a c | v o r b i s | o p u s | a c - [ 3 4 ] | e c - 3 | a l a c | m p 3 ) / ,
12
+
13
+ // mux.js support regex
14
+ muxerVideo : / ^ ( a v c 0 ? 1 ) / ,
15
+ muxerAudio : / ^ ( m p 4 a ) /
16
+ } ;
17
+
1
18
/**
2
19
* Replace the old apple-style `avc1.<dd>.<dd>` codec string with the standard
3
20
* `avc1.<hhhhhh>`
@@ -66,31 +83,32 @@ export const mapLegacyAvcCodecs = function(codecString) {
66
83
* Parses a codec string to retrieve the number of codecs specified, the video codec and
67
84
* object type indicator, and the audio profile.
68
85
*
69
- * @param {string } [codecs ]
86
+ * @param {string } [codecString ]
70
87
* The codec string to parse
71
88
* @return {ParsedCodecInfo }
72
89
* Parsed codec info
73
90
*/
74
- export const parseCodecs = function ( codecs = '' ) {
75
- const result = {
76
- codecCount : 0
77
- } ;
91
+ export const parseCodecs = function ( codecString = '' ) {
92
+ const codecs = codecString . split ( ',' ) ;
93
+ const result = { } ;
78
94
79
- result . codecCount = codecs . split ( ',' ) . length ;
80
- result . codecCount = result . codecCount || 2 ;
95
+ codecs . forEach ( function ( codec ) {
96
+ codec = codec . trim ( ) ;
81
97
82
- // parse the video codec
83
- const parsed = ( / ( ^ | \s | , ) + ( a v c [ 1 3 ] | v p 0 9 | a v 0 1 ) ( [ ^ , ] * ) / i ) . exec ( codecs ) ;
98
+ [ ' video' , 'audio' ] . forEach ( function ( name ) {
99
+ const match = regexs [ name ] . exec ( codec . toLowerCase ( ) ) ;
84
100
85
- if ( parsed ) {
86
- result . videoCodec = parsed [ 2 ] ;
87
- result . videoObjectTypeIndicator = parsed [ 3 ] ;
88
- }
101
+ if ( ! match || match . length <= 1 ) {
102
+ return ;
103
+ }
104
+
105
+ // maintain codec case
106
+ const type = codec . substring ( 0 , match [ 1 ] . length ) ;
107
+ const details = codec . replace ( type , '' ) ;
89
108
90
- // parse the last field of the audio codec
91
- result . audioProfile =
92
- ( / ( ^ | \s | , ) + m p 4 a .[ 0 - 9 A - F a - f ] + \. ( [ 0 - 9 A - F a - f ] + ) / i) . exec ( codecs ) ;
93
- result . audioProfile = result . audioProfile && result . audioProfile [ 2 ] ;
109
+ result [ name ] = { type, details} ;
110
+ } ) ;
111
+ } ) ;
94
112
95
113
return result ;
96
114
} ;
@@ -106,7 +124,7 @@ export const parseCodecs = function(codecs = '') {
106
124
* @return {ParsedCodecInfo }
107
125
* Parsed codec info
108
126
*/
109
- export const audioProfileFromDefault = ( master , audioGroupId ) => {
127
+ export const codecsFromDefault = ( master , audioGroupId ) => {
110
128
if ( ! master . mediaGroups . AUDIO || ! audioGroupId ) {
111
129
return null ;
112
130
}
@@ -122,9 +140,59 @@ export const audioProfileFromDefault = (master, audioGroupId) => {
122
140
123
141
if ( audioType . default && audioType . playlists ) {
124
142
// codec should be the same for all playlists within the audio type
125
- return parseCodecs ( audioType . playlists [ 0 ] . attributes . CODECS ) . audioProfile ;
143
+ return parseCodecs ( audioType . playlists [ 0 ] . attributes . CODECS ) ;
126
144
}
127
145
}
128
146
129
147
return null ;
130
148
} ;
149
+
150
+ export const isVideoCodec = ( codec = '' ) => regexs . video . test ( codec . trim ( ) . toLowerCase ( ) ) ;
151
+ export const isAudioCodec = ( codec = '' ) => regexs . audio . test ( codec . trim ( ) . toLowerCase ( ) ) ;
152
+
153
+ export const getMimeForCodec = ( codecString ) => {
154
+ if ( ! codecString || typeof codecString !== 'string' ) {
155
+ return ;
156
+ }
157
+ const codecs = codecString
158
+ . toLowerCase ( )
159
+ . split ( ',' )
160
+ . map ( ( c ) => translateLegacyCodec ( c . trim ( ) ) ) ;
161
+
162
+ // default to video type
163
+ let type = 'video' ;
164
+
165
+ // only change to audio type if the only codec we have is
166
+ // audio
167
+ if ( codecs . length === 1 && isAudioCodec ( codecs [ 0 ] ) ) {
168
+ type = 'audio' ;
169
+ }
170
+
171
+ // default the container to mp4
172
+ let container = 'mp4' ;
173
+
174
+ // every codec must be able to go into the container
175
+ // for that container to be the correct one
176
+ if ( codecs . every ( ( c ) => regexs . mp4 . test ( c ) ) ) {
177
+ container = 'mp4' ;
178
+ } else if ( codecs . every ( ( c ) => regexs . webm . test ( c ) ) ) {
179
+ container = 'webm' ;
180
+ } else if ( codecs . every ( ( c ) => regexs . ogg . test ( c ) ) ) {
181
+ container = 'ogg' ;
182
+ }
183
+
184
+ return `${ type } /${ container } ;codecs="${ codecString } "` ;
185
+ } ;
186
+
187
+ export const browserSupportsCodec = ( codecString = '' ) => window . MediaSource &&
188
+ window . MediaSource . isTypeSupported &&
189
+ window . MediaSource . isTypeSupported ( getMimeForCodec ( codecString ) ) || false ;
190
+
191
+ export const muxerSupportsCodec = ( codecString = '' ) => codecString . toLowerCase ( ) . split ( ',' ) . every ( ( codec ) => {
192
+ codec = codec . trim ( ) ;
193
+
194
+ return regexs . muxerVideo . test ( codec ) || regexs . muxerAudio . test ( codec ) ;
195
+ } ) ;
196
+
197
+ export const DEFAULT_AUDIO_CODEC = 'mp4a.40.2' ;
198
+ export const DEFAULT_VIDEO_CODEC = 'avc1.4d400d' ;
0 commit comments