UNPKG

8.91 kBJavaScriptView Raw
1/* eslint-disable */
2import flvparse from './flv/flvParse';
3import tagdemux from './flv/tagdemux';
4import mp4remux from './mp4/mp4remux';
5import mp4moof from './mp4/mp4moof';
6import { CustEvent } from 'chimee-helper';
7class flv2fmp4 {
8
9 /**
10 * Creates an instance of flv2fmp4.
11 * config 里面有_isLive属性,是否是直播
12 * @param {any} config
13 *
14 * @memberof flv2fmp4
15 */
16 constructor(config) {
17 this._config = { _isLive: false };
18 this._config = Object.assign(this._config, config);
19
20 // 外部方法赋值
21 this.onInitSegment = null;
22 this.onMediaSegment = null;
23 this.onMediaInfo = null;
24 this.seekCallBack = null;
25
26 // 内部使用
27 this.loadmetadata = false;
28 this.ftyp_moov = null;
29 this.metaSuccRun = false;
30 this.metas = [];
31 this.parseChunk = null;
32 this.hasVideo = false;
33 this.hasAudio = false;
34 this._error=null;
35 // 临时记录seek时间
36 this._pendingResolveSeekPoint = -1;
37
38 // 临时记录flv数据起始时间
39 this._tempBaseTime = 0;
40
41 // 处理flv数据入口
42 this.setflvBase = this.setflvBasefrist;
43
44 tagdemux._onTrackMetadata = this.Metadata.bind(this);
45 tagdemux._onMediaInfo = this.metaSucc.bind(this);
46 tagdemux._onDataAvailable = this.onDataAvailable.bind(this);
47 tagdemux._onError=this.error.bind(this);
48 this.m4mof = new mp4moof(this._config);
49 this.m4mof.onMediaSegment = this.onMdiaSegment.bind(this);
50 }
51 seek(baseTime) {
52 this.setflvBase = this.setflvBasefrist;
53 if (baseTime == undefined || baseTime == 0) {
54 baseTime = 0;
55 this._pendingResolveSeekPoint = -1;
56 }
57 if (this._tempBaseTime != baseTime) {
58 this._tempBaseTime = baseTime;
59 tagdemux._timestampBase = baseTime;
60 this.m4mof.seek(baseTime);
61 this.m4mof.insertDiscontinuity();
62 this._pendingResolveSeekPoint = baseTime;
63 }
64 }
65
66 /**
67 * 不要主动调用这个接口!!!!!!!!!!!!!!!!!!!!!!!!!!!!
68 * 第一次接受数据,和seek时候接受数据入口,
69 *
70 * @param {any} arraybuff
71 * @param {any} baseTime
72 * @returns
73 *
74 * @memberof flv2fmp4
75 */
76 setflvBasefrist(arraybuff, baseTime) {
77 let offset = 0;
78 try {
79 offset = flvparse.setFlv(new Uint8Array(arraybuff));
80 } catch (error) {
81 this.error(error);
82 }
83
84 if (flvparse.arrTag.length > 0) {
85 this.hasAudio = flvparse._hasAudio;
86 this.hasVideo = flvparse._hasVideo;
87 if (this._tempBaseTime != 0 && this._tempBaseTime == flvparse.arrTag[0].getTime()) {
88 tagdemux._timestampBase = 0;
89 }
90 try {
91 tagdemux.moofTag(flvparse.arrTag);
92 } catch (error) {
93 this.error(error);
94 }
95
96 this.setflvBase = this.setflvBaseUsually;
97 }
98
99 return offset;
100 }
101
102 /**
103 * 不要主动调用这个接口!!!!!!!!!!!!!!!!!!!!!!!!!!!!
104 * 后续接受数据接口
105 * @param {any} arraybuff
106 * @param {any} baseTime
107 * @returns
108 *
109 * @memberof flv2fmp4
110 */
111 setflvBaseUsually(arraybuff, baseTime) {
112 let offset = 0;
113 try {
114 offset = flvparse.setFlv(new Uint8Array(arraybuff));
115 } catch (error) {
116 this.error(error);
117 }
118 if (flvparse.arrTag.length > 0) {
119 try {
120 tagdemux.moofTag(flvparse.arrTag);
121 } catch (error) {
122 this.error(error);
123 }
124 }
125
126 return offset;
127 }
128
129 /**
130 * 不要主动调用这个接口!!!!!!!!!!!!!!!!!!!!!!!!!!!!
131 * moof回调
132 *
133 * @param {any} track
134 * @param {any} value
135 *
136 * @memberof flv2fmp4
137 */
138 onMdiaSegment(track, value) {
139
140 if (this.onMediaSegment) {
141 this.onMediaSegment(new Uint8Array(value.data));
142 }
143 if (this._pendingResolveSeekPoint != -1 && track == 'video') {
144 let seekpoint = this._pendingResolveSeekPoint;
145 this._pendingResolveSeekPoint = -1;
146 if (this.seekCallBack) {
147 this.seekCallBack(seekpoint);
148 }
149 }
150 }
151
152 /**
153 *
154 * 音频和视频的初始化tag
155 *
156 * @param {any} type
157 * @param {any} meta
158 *
159 * @memberof flv2fmp4
160 */
161 Metadata(type, meta) {
162 switch (type) {
163 case 'video':
164 this.metas.push(meta);
165 this.m4mof._videoMeta = meta;
166 if (this.hasVideo && !this.hasAudio) {
167 this.metaSucc();
168 return;
169 }
170 break;
171 case 'audio':
172 this.metas.push(meta);
173 this.m4mof._audioMeta = meta;
174 if (!this.hasVideo && this.hasAudio) {
175 this.metaSucc();
176 return;
177 }
178 break;
179 }
180 if (this.hasVideo && this.hasAudio && this.metaSuccRun && this.metas.length > 1) {
181 this.metaSucc();
182 }
183 }
184
185 /**
186 * metadata解读成功后触发及第一个视频tag和第一个音频tag
187 *
188 * @param {any} mi
189 * @returns
190 *
191 * @memberof flv2fmp4
192 */
193 metaSucc(mi) {
194 if (this.onMediaInfo) {
195 this.onMediaInfo(mi, { hasAudio: this.hasAudio, hasVideo: this.hasVideo });
196 }
197 // 获取ftyp和moov
198 if (this.metas.length == 0) {
199 this.metaSuccRun = true;
200 return;
201 }
202
203 this.ftyp_moov = mp4remux.generateInitSegment(this.metas);
204 if (this.onInitSegment && this.loadmetadata == false) {
205
206 this.onInitSegment(this.ftyp_moov);
207 this.loadmetadata = true;
208 }
209 }
210
211 onDataAvailable(audiotrack, videotrack) {
212 try{
213 this.m4mof.remux(audiotrack, videotrack);
214 }catch(e){
215 this.error(e);
216 }
217
218 }
219
220 /**
221 * 传入flv的二进制数据
222 * 统一入口
223 * @param {any} arraybuff
224 * @param {any} baseTime flv数据开始时间
225 * @returns
226 *
227 * @memberof flv2fmp4
228 */
229 setflv(arraybuff, baseTime) {
230 return this.setflvBase(arraybuff, baseTime);
231 }
232
233 /**
234 *
235 * 本地调试代码,不用理会
236 * @param {any} arraybuff
237 * @returns
238 *
239 * @memberof flv2fmp4
240 */
241 setflvloc(arraybuff) {
242 const offset = flvparse.setFlv(new Uint8Array(arraybuff));
243
244 if (flvparse.arrTag.length > 0) {
245 return flvparse.arrTag;
246 }
247 }
248
249
250 /**
251 *
252 * 异常抛出处理
253 * @param {any} e
254 * @memberof flv2fmp4
255 */
256 error(e) {
257 if(this._error){
258 this._error(e);
259 }
260 }
261
262}
263
264/**
265 * 封装的对外类,有些方法不想对外暴露,所以封装这么一个类
266 *
267 * @class foreign
268 */
269class CPU extends CustEvent {
270 constructor(config) {
271 super();
272 this.f2m = new flv2fmp4(config);
273 this.f2m._error=this.error;
274 // 外部方法赋值
275 this._onInitSegment = null;
276 this._onMediaSegment = null;
277 this._onMediaInfo = null;
278 this._seekCallBack = null;
279 }
280
281 error(e){
282 this.emit('error',e.type);
283 }
284 /**
285 *
286 * 跳转
287 * @param {any} basetime 跳转时间
288 *
289 * @memberof foreign
290 */
291 seek(basetime) {
292 this.f2m.seek(basetime);
293 }
294
295 /**
296 * 传入flv的二进制数据
297 * 统一入口
298 * @param {any} arraybuff
299 * @returns
300 *
301 * @memberof flv2fmp4
302 */
303 setflv(arraybuff) {
304 return this.f2m.setflv(arraybuff, 0);
305 }
306
307 /**
308 *
309 * 本地调试代码,不用理会
310 * @param {any} arraybuff
311 * @returns
312 *
313 * @memberof flv2fmp4
314 */
315 setflvloc(arraybuff) {
316 return this.f2m.setflvloc(arraybuff);
317 }
318
319 /**
320 * 赋值初始化seg接受方法
321 *
322 *
323 * @memberof foreign
324 */
325 set onInitSegment(fun) {
326 this._onInitSegment = fun;
327 this.f2m.onInitSegment = fun;
328 }
329
330 /**
331 * 赋值moof接受方法
332 *
333 *
334 * @memberof foreign
335 */
336 set onMediaSegment(fun) {
337 this._onMediaSegment = fun;
338 this.f2m.onMediaSegment = fun;
339 }
340
341 /**
342 * 赋值metadata接受方法
343 *
344 *
345 * @memberof foreign
346 */
347 set onMediaInfo(fun) {
348 this._onMediaInfo = fun;
349 this.f2m.onMediaInfo = fun;
350 }
351
352 /**
353 * 赋值是否跳转回调接受方法
354 *
355 *
356 * @memberof foreign
357 */
358 set seekCallBack(fun) {
359 this._seekCallBack = fun;
360 this.f2m.seekCallBack = fun;
361 }
362}
363module.exports=CPU;
364// export CPU;
\No newline at end of file