mirror of
https://github.com/bytedance/xgplayer.git
synced 2025-04-05 03:05:02 +08:00
fix(xgplayer-transmuxer): mp4 tkhd中matrix int取数问题
This commit is contained in:
parent
fb7fbb73e2
commit
b7e357cf05
128
packages/xgplayer-transmuxer/src/mp4/byte-reader.ts
Normal file
128
packages/xgplayer-transmuxer/src/mp4/byte-reader.ts
Normal file
@ -0,0 +1,128 @@
|
||||
export class ByteReader {
|
||||
private dv: DataView
|
||||
start: number
|
||||
offset: number
|
||||
end: number
|
||||
constructor(buf: ArrayBuffer, offset: number, len: number) {
|
||||
this.dv = new DataView(buf)
|
||||
this.start = this.offset = offset || this.dv.byteOffset
|
||||
this.end = len ? this.start + len : this.dv.byteLength
|
||||
}
|
||||
static fromUint8(uint8: Uint8Array) {
|
||||
return new ByteReader(uint8.buffer, uint8.byteOffset, uint8.byteLength)
|
||||
}
|
||||
static concatUint8s(args: Uint8Array[]) {
|
||||
const uint8 = new Uint8Array(args.reduce((ret, v) => ret + v.byteLength, 0))
|
||||
let offset = 0
|
||||
args.forEach((v) => {
|
||||
uint8.set(v, offset)
|
||||
offset += v.byteLength
|
||||
})
|
||||
return uint8
|
||||
}
|
||||
static concatUint8(...args: Uint8Array[]) {
|
||||
return this.concatUint8s(args)
|
||||
}
|
||||
get buffer() {
|
||||
return this.dv.buffer
|
||||
}
|
||||
get unreadLength() {
|
||||
return Math.max(this.end - this.offset, 0)
|
||||
}
|
||||
get size() {
|
||||
return this.end - this.start
|
||||
}
|
||||
readFloat(byteNum: number) {
|
||||
let val = 0
|
||||
switch (byteNum) {
|
||||
case 4:
|
||||
val = this.dv.getFloat32(this.offset)
|
||||
break
|
||||
case 8:
|
||||
val = this.dv.getFloat64(this.offset)
|
||||
break
|
||||
default:
|
||||
throw new Error(`read ${byteNum}-byte float is not supported`)
|
||||
}
|
||||
this.offset += byteNum
|
||||
return val
|
||||
}
|
||||
back(byteNum: number) {
|
||||
this.offset -= byteNum
|
||||
}
|
||||
skip(byteNum: number) {
|
||||
this.offset += byteNum
|
||||
}
|
||||
readInt(byteNum: number) {
|
||||
const offset = this.offset
|
||||
this.offset += byteNum
|
||||
switch (byteNum) {
|
||||
case 1:
|
||||
return this.dv.getInt8(offset)
|
||||
case 2:
|
||||
return this.dv.getInt16(offset)
|
||||
case 4:
|
||||
return this.dv.getInt32(offset)
|
||||
default:
|
||||
throw new Error(`read ${byteNum}-byte integers is not supported`)
|
||||
}
|
||||
}
|
||||
read(byteNum: number) {
|
||||
const offset = this.offset
|
||||
this.offset += byteNum
|
||||
switch (byteNum) {
|
||||
case 1:
|
||||
return this.dv.getUint8(offset)
|
||||
case 2:
|
||||
return this.dv.getUint16(offset)
|
||||
case 3:
|
||||
return (this.dv.getUint16(offset) << 8) + this.dv.getUint8(offset + 2)
|
||||
case 4:
|
||||
return this.dv.getUint32(offset)
|
||||
default:
|
||||
this.back(byteNum - 4)
|
||||
// js不支持32位左移,可通过+、Math.pow运算达到64位以内运算的目的
|
||||
return this.read(byteNum - 4) + this.dv.getUint32(offset) * Math.pow(256, byteNum - 4)
|
||||
}
|
||||
}
|
||||
write(byteNum: number, val: number) {
|
||||
const offset = this.offset
|
||||
this.offset += byteNum
|
||||
switch (byteNum) {
|
||||
case 1:
|
||||
return this.dv.setUint8(offset, val)
|
||||
case 2:
|
||||
return this.dv.setUint16(offset, val)
|
||||
case 3:
|
||||
return this.dv.setUint8(offset, val >>> 16),
|
||||
this.dv.setUint16(offset + 1, 0xffff & val)
|
||||
case 4:
|
||||
return this.dv.setUint32(offset, val)
|
||||
default:
|
||||
throw new Error(`write ${byteNum}-byte integers is not supported`)
|
||||
}
|
||||
}
|
||||
readToBuffer(len?: number) {
|
||||
let buffer: ArrayBuffer
|
||||
if (this.offset || len) {
|
||||
buffer = this.dv.buffer.slice(this.offset, len ? this.offset + len : undefined)
|
||||
} else {
|
||||
buffer = this.dv.buffer
|
||||
}
|
||||
this.offset += buffer.byteLength
|
||||
return buffer
|
||||
}
|
||||
readToUint8(len?: number) {
|
||||
const uint8 = new Uint8Array(this.dv.buffer, this.offset, len || this.unreadLength)
|
||||
this.offset += uint8.byteLength
|
||||
return uint8
|
||||
}
|
||||
readString(len: number) {
|
||||
let i = 0, str = ''
|
||||
for (; i < len; i++) {
|
||||
str += String.fromCharCode(this.dv.getUint8(this.offset))
|
||||
this.offset++
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { AudioCodecType, VideoCodecType } from '../model'
|
||||
import { getAvcCodec, readBig16, readBig24, readBig32, readBig64, combineToFloat, toDegree } from '../utils'
|
||||
import { AAC } from '../codec'
|
||||
import { ByteReader } from './byte-reader'
|
||||
export class MP4Parser {
|
||||
static findBox (data, names, start = 0) {
|
||||
const ret = []
|
||||
@ -126,26 +127,15 @@ export class MP4Parser {
|
||||
return parseBox(box, true, (ret, data) => {
|
||||
let start = 0
|
||||
if (ret.version === 1) {
|
||||
ret.createTime = readBig64(data, 0)
|
||||
ret.modifyTime = readBig64(data, 8)
|
||||
ret.timescale = readBig32(data, 16)
|
||||
ret.duration = readBig64(data, 20)
|
||||
start += 28
|
||||
} else {
|
||||
ret.createTime = readBig32(data, 0)
|
||||
ret.modifyTime = readBig32(data, 4)
|
||||
ret.timescale = readBig32(data, 8)
|
||||
ret.duration = readBig32(data, 12)
|
||||
start += 16
|
||||
}
|
||||
ret.rate = combineToFloat(readBig16(data, start), readBig16(data, start + 2))
|
||||
start += 4
|
||||
ret.volume = combineToFloat(data[start], data[start + 1])
|
||||
start += 2
|
||||
start += 10 // skip
|
||||
start += 36 // skip matrix, Because the rotate of the mp4 video track is determined by the matrix in tkhd box
|
||||
start += 24 // skip
|
||||
ret.nextTrackId = readBig32(data, start)
|
||||
ret.nextTrackId = readBig32(data, start + 76)
|
||||
})
|
||||
}
|
||||
|
||||
@ -158,36 +148,36 @@ export class MP4Parser {
|
||||
|
||||
static tkhd (box) {
|
||||
return parseBox(box, true, (ret, data) => {
|
||||
let start = 0
|
||||
const byte = ByteReader.fromUint8(data)
|
||||
if (ret.version === 1) {
|
||||
ret.trackId = readBig32(data, 16)
|
||||
ret.duration = readBig64(data, 24)
|
||||
start += 32
|
||||
byte.read(8) // createTime
|
||||
byte.read(8) // modifyTime
|
||||
ret.trackId = byte.read(4)
|
||||
byte.read(4)
|
||||
ret.duration = byte.read(8)
|
||||
} else {
|
||||
ret.trackId = readBig32(data, 8)
|
||||
ret.duration = readBig32(data, 16)
|
||||
start += 20
|
||||
byte.read(4) // createTime
|
||||
byte.read(4) // modifyTime
|
||||
ret.trackId = byte.read(4)
|
||||
byte.read(4)
|
||||
ret.duration = byte.read(4)
|
||||
}
|
||||
start += 8 // skip
|
||||
ret.layer = readBig16(data, start)
|
||||
start += 2
|
||||
ret.alternateGroup = readBig16(data, start)
|
||||
start += 2
|
||||
start += 4 // skip
|
||||
byte.skip(16) // reserved(8) + layer(2) + alternateGroup(2) + volume(2) + reserved(2)
|
||||
ret.matrix = [] // for remux
|
||||
for (let i = 0; i < 36; i++) {
|
||||
ret.matrix.push(data[start + i])
|
||||
ret.matrix.push(byte.read(1))
|
||||
}
|
||||
byte.back(36)
|
||||
const caculatedMatrix = [] // for caculation of rotation
|
||||
for (let i = 0; i < 9; i++) {
|
||||
caculatedMatrix.push(combineToFloat(readBig16(data, start + i * 2), readBig16(data, start + i * 2 + 2))) // 16.16 fixed point
|
||||
caculatedMatrix.push(combineToFloat(readBig16(data, start + i * 2 + 4), readBig16(data, start + i * 2 + 6))) // 16.16 fixed point
|
||||
caculatedMatrix.push(combineToFloat(data[start + i * 2 + 8] & 0x3, readBig32(data, start + i * 2 + 8) >>> 2)) // 2.30 fixed point
|
||||
for (let i = 0, int32; i < 3; i++) {
|
||||
caculatedMatrix.push(combineToFloat(byte.read(2), byte.read(2))) // 16.16 fixed point
|
||||
caculatedMatrix.push(combineToFloat(byte.read(2), byte.read(2))) // 16.16 fixed point
|
||||
int32 = byte.readInt(4)
|
||||
caculatedMatrix.push(combineToFloat(int32 >> 30, int32 & 0x3fffffff)) // 2.30 fixed point
|
||||
}
|
||||
start += 36
|
||||
ret.rotation = toDegree(caculatedMatrix)
|
||||
ret.width = readBig32(data, start) // 16.16 fixed point, no parsed
|
||||
ret.height = readBig32(data, start + 4) // 16.16 fixed point, no parsed
|
||||
ret.width = byte.read(4) // 16.16 fixed point, no parsed
|
||||
ret.height = byte.read(4) // 16.16 fixed point, no parsed
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user