add FlvChecker

This commit is contained in:
tursom 2020-01-21 22:58:32 +08:00
parent 3b9054193b
commit 5131da5bfa
2 changed files with 174 additions and 1 deletions

View File

@ -0,0 +1,157 @@
package cn.tursom.core
import java.io.*
/**
* 原理 https://www.cnblogs.com/lidabo/p/9018548.html
*/
class FlvChecker {
// 用于缓冲
private val buffer = ByteArray(1024 * 1024 * 16)
/**
* 从头部开始Check, 重新锚定时间戳, 将最后一帧(不管是否完整)去掉
*
* @param path
* @throws IOException
*/
// 用于统计时间戳
private val lastTimestampRead = intArrayOf(-1, -1)
private val lastTimestampWrite = intArrayOf(-1, -1)
/**
* 从头部开始Check, 重新锚定时间戳, 将最后一帧(不管是否完整)去掉
*/
fun check(raf: InputStream, rafNew: OutputStream) { // 用于排除无效尾巴帧
// 复制头部
raf.read(buffer, 0, 9)
rafNew.write(buffer, 0, 9)
var currentLength = 9L
//var latsValidLength = currentLength
try {
var remain = 40
var timestamp = 0
while (true) { // && remain>=0
remain--
// 读取前一个tag size
readBytesToInt(raf, 4)
// Logger.print("前一个长度为:" + predataSize);
// 读取tag
// tag 类型
val tagType = raf.read()
if (tagType == 8 || tagType == 9) {
rafNew.write(buffer, 0, 4)
rafNew.write(tagType)
// tag data size 3个字节。表示tag data的长度。从streamd id 后算起。
val dataSize = readBytesToInt(raf, 3)
rafNew.write(buffer, 0, 3)
// Logger.print(" ,当前tag data 长度为:" + dataSize);
// 时间戳 3
timestamp = readBytesToInt(raf, 3)
val timestampEx = raf.read() shl 24
timestamp += timestampEx
dealTimestamp(rafNew, timestamp, tagType - 8)
raf.read(buffer, 0, 3 + dataSize)
rafNew.write(buffer, 0, 3 + dataSize)
} else if (tagType == 18) {
// 18 scripts
// 如果是scripts脚本默认为第一个tag此时将前一个tag Size 置零
//rafNew.seek(rafNew.filePointer - 4)
val zeroTimestamp = byteArrayOf(0, 0, 0, 0)
rafNew.write(zeroTimestamp)
rafNew.write(tagType)
val dataSize = readBytesToInt(raf, 3)
rafNew.write(buffer, 0, 3)
raf.read(buffer, 0, 4)
val zeros = byteArrayOf(0, 0, 0)
rafNew.write(zeros) // 时间戳 0
rafNew.write(0) // 时间戳扩展 0
raf.read(buffer, 0, 3 + dataSize)
rafNew.write(buffer, 0, 3 + dataSize)
} else {
break
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 处理音/视频时间戳
*
* @param raf
* @param timestamp
* @throws IOException
* @return 是否忽略该tag
*/
private fun dealTimestamp(raf: OutputStream, timestamp: Int, tagType: Int): Boolean {
// 如果是首帧
if (lastTimestampRead[tagType] == -1) {
lastTimestampWrite[tagType] = 0
} else if (timestamp >= lastTimestampRead[tagType]) {
// 如果时序正常
// 间隔十分巨大(1s),那么重新开始即可
if (timestamp > lastTimestampRead[tagType] + 1000) {
lastTimestampWrite[tagType] += 10
} else {
lastTimestampWrite[tagType] = timestamp - lastTimestampRead[tagType] + lastTimestampWrite[tagType]
}
} else {
// 如果出现倒序时间戳
// 如果间隔不大,那么如实反馈
if (lastTimestampRead[tagType] - timestamp < 5 * 1000) {
var tmp = timestamp - lastTimestampRead[tagType] + lastTimestampWrite[tagType]
tmp = if (tmp > 0) tmp else 1
lastTimestampWrite[tagType] = tmp
} else { // 间隔十分巨大,那么重新开始即可
lastTimestampWrite[tagType] += 10
}
}
lastTimestampRead[tagType] = timestamp
// 低于0xffffff部分
val lowCurrentTime = lastTimestampWrite[tagType] and 0xffffff
raf.write(int2Bytes(lowCurrentTime), 1, 3)
// 高于0xffffff部分
val highCurrentTime = lastTimestampWrite[tagType] shr 24
raf.write(highCurrentTime)
return true
}
/**
* @param raf
* @param byteLength
* @return
* @throws IOException
*/
private fun readBytesToInt(raf: InputStream, byteLength: Int): Int {
raf.read(buffer, 0, byteLength)
return bytes2Int(buffer, byteLength)
}
private fun int2Bytes(value: Int): ByteArray {
val byteRet = ByteArray(4)
for (i in 0..3) {
byteRet[3 - i] = (value shr 8 * i and 0xff).toByte()
}
return byteRet
}
private fun bytes2Int(bytes: ByteArray, byteLength: Int): Int {
var result = 0
for (i in 0 until byteLength) {
result = result or (bytes[byteLength - 1 - i].toInt() and 0xff shl i * 8)
// System.out.printf("%x ",(bytes[i] & 0xff));
}
return result
}
}
fun main() {
val checker = FlvChecker()
checker.check(
File("test.flv").inputStream().buffered(),
File("1.flv").outputStream().buffered()
)
}

View File

@ -2,6 +2,7 @@ package cn.tursom.core.buffer
import cn.tursom.core.forEachIndex
import java.io.Closeable
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import kotlin.math.min
@ -202,6 +203,7 @@ interface ByteBuffer : Closeable {
fun put(inputStream: InputStream) {
if (hasArray) {
val read = inputStream.read(array, writeOffset, writeable)
if (read < 0) throw IOException("stream closed")
writePosition += read
} else {
val buffer = ByteArray(10 * 1024)
@ -210,6 +212,19 @@ interface ByteBuffer : Closeable {
}
}
fun put(inputStream: InputStream, size: Int) {
assert(size <= writeable)
if (hasArray) {
val read = inputStream.read(array, writeOffset, size)
if (read < 0) throw IOException("stream closed")
writePosition += read
} else {
val buffer = ByteArray(size)
val read = inputStream.read(buffer)
put(buffer, 0, read)
}
}
fun putByte(byte: Byte): Unit = put(byte)
fun putChar(char: Char): Unit = put(char)
fun putShort(short: Short): Unit = put(short)
@ -256,4 +271,5 @@ interface ByteBuffer : Closeable {
readPosition += size
return size
}
}
}