Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit11e2363

Browse files
committed
feat: parsed matrix
1 parent7739f69 commit11e2363

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

‎packages/av-cliper/src/clips/__tests__/mp4-clip.test.ts‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
importmp4box,{MP4ArrayBuffer}from'@webav/mp4box.js';
22
import{file,write}from'opfs-tools';
33
import{expect,test,vi}from'vitest';
4+
import{parseMatrix}from'../../mp4-utils/mp4box-utils';
45
import{MP4Clip}from'../mp4-clip';
56

67
constmp4_123=`//${location.host}/video/123.mp4`;
@@ -179,15 +180,24 @@ test('get file header data', async () => {
179180
hasMoov:true,
180181
}),
181182
);
183+
182184
expect(boxfile.moov?.mvhd.matrix.length).toBe(9);
185+
expect(parseMatrix(boxfile.moov?.mvhd.matrix!)).toEqual({
186+
perspective:1,
187+
rotationDeg:0,
188+
rotationRad:0,
189+
scaleX:1,
190+
scaleY:1,
191+
translateX:0,
192+
translateY:0,
193+
});
183194
});
184195

185196
test('decode incorrectFrameTypeMp4',async()=>{
186197
constclip=newMP4Clip((awaitfetch(incorrectFrameTypeMp4)).body!);
187198
awaitclip.ready;
188-
console.log(clip.meta.duration);
189199
expect(Math.round(clip.meta.duration/1e6)).toBe(5);
190-
const{ state, video}=awaitclip.tick(clip.meta.duration-30e3);
200+
// 获取最后一帧
201+
const{ state}=awaitclip.tick(clip.meta.duration-30e3);
191202
expect(state).toBe('success');
192-
expect(video?.timestamp).toBe(5e6);
193203
});

‎packages/av-cliper/src/clips/mp4-clip.ts‎

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { file, tmpfile, write } from 'opfs-tools';
44
import{audioResample,extractPCM4AudioData,sleep}from'../av-utils';
55
import{
66
extractFileConfig,
7+
parseMatrix,
78
quickParseMP4File,
89
}from'../mp4-utils/mp4box-utils';
910
import{DEFAULT_AUDIO_CONF,IClip}from'./iclip';
@@ -85,6 +86,7 @@ export class MP4Clip implements IClip {
8586

8687
#localFile:OPFSToolFile;
8788

89+
/** 存储视频头(box: ftyp, moov)的二进制数据 */
8890
#headerBoxPos:Array<{start:number;size:number}>=[];
8991
/**
9092
* 提供视频头(box: ftyp, moov)的二进制数据
@@ -103,6 +105,17 @@ export class MP4Clip implements IClip {
103105
).arrayBuffer();
104106
}
105107

108+
/**存储视频平移旋转信息,目前只还原旋转 */
109+
#parsedMatrix={
110+
perspective:1,
111+
rotationDeg:0,
112+
rotationRad:0,
113+
scaleX:1,
114+
scaleY:1,
115+
translateX:0,
116+
translateY:0,
117+
};
118+
106119
#volume=1;
107120

108121
#videoSamples:ExtMP4Sample[]=[];
@@ -160,11 +173,18 @@ export class MP4Clip implements IClip {
160173
?mp4FileToSamples(source,this.#opts)
161174
:Promise.resolve(source)
162175
).then(
163-
async({ videoSamples, audioSamples, decoderConf, headerBoxPos})=>{
176+
async({
177+
videoSamples,
178+
audioSamples,
179+
decoderConf,
180+
headerBoxPos,
181+
parsedMatrix,
182+
})=>{
164183
this.#videoSamples=videoSamples;
165184
this.#audioSamples=audioSamples;
166185
this.#decoderConf=decoderConf;
167186
this.#headerBoxPos=headerBoxPos;
187+
this.#parsedMatrix=parsedMatrix;
168188

169189
const{ videoFrameFinder, audioFrameFinder}=genDecoder(
170190
{
@@ -355,6 +375,7 @@ export class MP4Clip implements IClip {
355375
audioSamples:preAudioSlice??[],
356376
decoderConf:this.#decoderConf,
357377
headerBoxPos:this.#headerBoxPos,
378+
parsedMatrix:this.#parsedMatrix,
358379
},
359380
this.#opts,
360381
);
@@ -365,6 +386,7 @@ export class MP4Clip implements IClip {
365386
audioSamples:postAudioSlice??[],
366387
decoderConf:this.#decoderConf,
367388
headerBoxPos:this.#headerBoxPos,
389+
parsedMatrix:this.#parsedMatrix,
368390
},
369391
this.#opts,
370392
);
@@ -382,6 +404,7 @@ export class MP4Clip implements IClip {
382404
audioSamples:[...this.#audioSamples],
383405
decoderConf:this.#decoderConf,
384406
headerBoxPos:this.#headerBoxPos,
407+
parsedMatrix:this.#parsedMatrix,
385408
},
386409
this.#opts,
387410
);
@@ -408,6 +431,7 @@ export class MP4Clip implements IClip {
408431
audio:null,
409432
},
410433
headerBoxPos:this.#headerBoxPos,
434+
parsedMatrix:this.#parsedMatrix,
411435
},
412436
this.#opts,
413437
);
@@ -426,6 +450,7 @@ export class MP4Clip implements IClip {
426450
video:null,
427451
},
428452
headerBoxPos:this.#headerBoxPos,
453+
parsedMatrix:this.#parsedMatrix,
429454
},
430455
this.#opts,
431456
);
@@ -524,6 +549,15 @@ async function mp4FileToSamples(otFile: OPFSToolFile, opts: IMP4ClipOpts = {}) {
524549
letvideoSamples:ExtMP4Sample[]=[];
525550
letaudioSamples:ExtMP4Sample[]=[];
526551
letheaderBoxPos:Array<{start:number;size:number}>=[];
552+
constparsedMatrix={
553+
perspective:1,
554+
rotationDeg:0,
555+
rotationRad:0,
556+
scaleX:1,
557+
scaleY:1,
558+
translateX:0,
559+
translateY:0,
560+
};
527561

528562
letvideoDeltaTS=-1;
529563
letaudioDeltaTS=-1;
@@ -537,6 +571,8 @@ async function mp4FileToSamples(otFile: OPFSToolFile, opts: IMP4ClipOpts = {}) {
537571
constmoov=data.mp4boxFile.moov!;
538572
headerBoxPos.push({start:moov.start,size:moov.size});
539573

574+
Object.assign(parsedMatrix,parseMatrix(moov.mvhd.matrix));
575+
540576
let{videoDecoderConf:vc,audioDecoderConf:ac}=extractFileConfig(
541577
data.mp4boxFile,
542578
data.info,
@@ -599,6 +635,7 @@ async function mp4FileToSamples(otFile: OPFSToolFile, opts: IMP4ClipOpts = {}) {
599635
audioSamples,
600636
decoderConf,
601637
headerBoxPos,
638+
parsedMatrix,
602639
};
603640
}
604641

‎packages/av-cliper/src/mp4-utils/mp4box-utils.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,36 @@ export async function quickParseMP4File(
179179
mp4boxFile.stop();
180180
}
181181
}
182+
183+
exportfunctionparseMatrix(matrix:Uint32Array){
184+
if(matrix.length!==9){
185+
thrownewError('Matrix must have 9 elements');
186+
}
187+
188+
// 提取并转成浮点数
189+
consta=matrix[0]/65536.0;
190+
constb=matrix[1]/65536.0;
191+
constc=matrix[3]/65536.0;
192+
constd=matrix[4]/65536.0;
193+
consttx=matrix[6]/65536.0;// 一般是 0
194+
constty=matrix[7]/65536.0;// 一般是 0
195+
constw=matrix[8]/(1<<30);// 一般是 1
196+
197+
// 缩放
198+
constscaleX=Math.sqrt(a*a+c*c);
199+
constscaleY=Math.sqrt(b*b+d*d);
200+
201+
// 旋转角度(弧度)
202+
constrotationRad=Math.atan2(c,a);
203+
constrotationDeg=(rotationRad*180)/Math.PI;
204+
205+
return{
206+
scaleX,
207+
scaleY,
208+
rotationRad,
209+
rotationDeg,
210+
translateX:tx,
211+
translateY:ty,
212+
perspective:w,
213+
};
214+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp