溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java怎么實現(xiàn)提取QSV文件視頻內(nèi)容

發(fā)布時間:2023-05-06 11:30:24 來源:億速云 閱讀:88 作者:zzz 欄目:開發(fā)技術(shù)

今天小編給大家分享一下Java怎么實現(xiàn)提取QSV文件視頻內(nèi)容的相關(guān)知識點,內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

創(chuàng)建類

第一步新建一個java類QSV,構(gòu)造函數(shù)傳入需要解析的文件名稱。

public class QSV {
    
    private RandomAccessFile randomAccessFile;
    private String name;

    public QSV(String name) throws FileNotFoundException {
        randomAccessFile = new RandomAccessFile(name, "r");
        this.name = name;
    }

}

通用方法

逐字節(jié)讀取文件

我們需要逐個字節(jié)讀取文件,這邊就需要jdk自帶的類RandomAccessFile,先定義一個通用函數(shù),輸出偏移位置和字節(jié)大小獲取字節(jié)數(shù)組。

/**
* @param offset 偏移未知
* @param size   字節(jié)大小
* @return 字節(jié)數(shù)組
* @throws IOException
*/
private byte[] getByteFromFile(int offset, int size) throws IOException {
    //指針移動至偏移位置
    randomAccessFile.seek(offset);
    //需要讀取的字節(jié)數(shù)
    byte[] bs = new byte[size];
    randomAccessFile.read(bs);
    return bs;
}

字節(jié)數(shù)組轉(zhuǎn)16進(jìn)制字符串

private static final char[] HEX_VOCABLE = {'0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/**
* 字節(jié)數(shù)組轉(zhuǎn)16進(jìn)制字符串
*
* @param bs
* @return
*/
public String bytesToHex(byte[] bs) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bs) {
        int high = (b >> 4) & 0x0f;
        int low = b & 0x0f;
        sb.append(HEX_VOCABLE[high]);
        sb.append(HEX_VOCABLE[low]);
    }
    return sb.toString();
}

字節(jié)數(shù)組轉(zhuǎn)int

/**
* 字節(jié)數(shù)組轉(zhuǎn)int
*
* @param b
* @return
*/
public int toInt(byte[] b) {
    int res = 0;
    for (int i = 0; i < b.length; i++) {
        res += (b[i] & 0xff) << (i * 8);
    }
    return res;
}

老版本解密算法

老版本解密方法比較簡單,先看下C的寫法:

// 定義1個字節(jié)內(nèi)存
typedef uint8_t BYTE;
// 定義4個字節(jié)內(nèi)存
typedef uint32_t DWORD;
// decryption algorithm for some segments in qsv version 0x1
void decrypt_1(BYTE* buffer, DWORD size) {
    static BYTE dict[] = {0x62, 0x67, 0x70, 0x79};
    for(int i = 0; i < size; ++i) {
        DWORD j = ~i & 0x3;
        buffer[i] ^= dict[j];
    }
}

可以直接用byte數(shù)組和long類型替換c的內(nèi)存定義,這邊沒問題時因為沒有位移算法,后面新版本解密算法會講到。

private void decrypt_1(byte[] bs, long len) {
    byte[] b = new byte[]{0x62, 0x67, 0x70, 0x79};
    for (int i = 0; i < len; i++) {
        //先取反再與運算
        int j = ~i & 0x3;
        //異或運算
        bs[i] ^= b[j];
    }
}

新版本解密算法

新版本解密算法比較復(fù)雜,同樣先看下c的寫法:

// 定義1個字節(jié)內(nèi)存
typedef uint8_t BYTE;
// 定義4個字節(jié)內(nèi)存
typedef uint32_t DWORD;
// decryption algorithm for some segments in qsv version 0x2
void decrypt_2(BYTE* buffer, DWORD size) {
    DWORD x = 0x62677079;
    for(DWORD i = size - 1; i != 0; --i) {
        x = (x << 1) | (x >> 31);
        x ^= buffer[i];
    }
    for(DWORD i = 1; i < size; ++i) {
        x ^= buffer[i] & 0xFF;
        x = (x >> 1) | (x << 31);
        DWORD j = x % i;
        BYTE tmp = buffer[j];
        buffer[j] = tmp ^ (BYTE)~buffer[i];
        buffer[i] = tmp;
    }
}

這邊注意c的寫法有位移,定義的DWORD占32位內(nèi)存,而java與之對應(yīng)的int類型也是占32位內(nèi)存,取值范圍是-2^31~2^31-1(即-2147483648~2147483647),如果超出這個范圍java需要用long,而long占64位內(nèi)存取反和位移都是按64位進(jìn)行的與C的32位取反位移計算結(jié)果肯定有差異。

比如:2147483648,轉(zhuǎn)換位二進(jìn)制表示:10000000000000000000000000000000,C的寫法由于DWORD占32位內(nèi)存,左移一位后超出32為故就變成00000000000000000000000000000000,而java已經(jīng)超出了int的取值范圍,只能用long定義,由于long占64位,左移一位不會超出,結(jié)果也就不一樣了。

又比如:9147483648,轉(zhuǎn)為二進(jìn)制表示:1000100001001110111000011000000000,已經(jīng)超出32位,存到DWORD中的只保留右邊的32位,即00100001001110111000011000000000,左移以為變成01000010011101110000110000000000,轉(zhuǎn)為10進(jìn)制為1115098112,而java采用long定義不會超出64位,左移結(jié)果位10001000010011101110000110000000000,轉(zhuǎn)為十進(jìn)制表示為18294967296,與C的結(jié)果相差較大。那么有辦法解決嗎,答案肯定是有的,我們需要重新寫一個位移算法。

/**
* 左移
*
* @param value long
* @param i     位移量
* @return long
*/
private long longLeftShift(long value, int i) {
    String binary = format32(value);
    binary = binary.substring(i) + String.format("%0" + i + "d", 0);
    return Long.parseLong(binary, 2);
}

/**
* 右移
*
* @param value long
* @param i     位移量
* @return long
*/
private long longRightShift(long value, int i) {
    String binary = format32(value);
    binary = String.format("%0" + i + "d", 0) + binary.substring(0, binary.length() - i);
    return Long.parseLong(binary, 2);
}

private String format32(long value) {
    String binary = Long.toBinaryString(value);
    if (binary.length() < 32) {
        //補(bǔ)滿32位
        binary = String.format("%0" + (32 - binary.length()) + "d", 0) + binary;
    } else {
        //多余的截取掉
        binary = binary.substring(binary.length() - 32);
    }
    return binary;
}

有了新定義的位移算法,解密算法就可以修改為:

private void decrypt_2(byte[] buffer, int size) {
    long x = 0x62677079;
    for (int i = size - 1; i != 0; --i) {
        x = longLeftShift(x, 1) | longRightShift(x, 31);
        x ^= buffer[i] & 0xFF;
    }
    for (int i = 1; i < size; ++i) {
        x ^= buffer[i] & 0xFF;
        x = longRightShift(x, 1) | longLeftShift(x, 31);
        int j = (int) (x % i);
        byte tmp = buffer[j];
        int a = buffer[i];
        buffer[j] = (byte) (tmp ^ ~a);
        buffer[i] = tmp;
    }
}

獲取QSV頭部信息

上一篇文章講到,頭部信息共90個字節(jié),signature(10byte)+version(4byte)+vid(16byte)+_unknown1(4byte)+_unknown2(32byte)+_unknown3(4byte)+_unknown4(4byte)+json_offset(8byte)+json_size(4byte)+nb_indices(4byte)

public static void main(String[] args) throws IOException {
    QSV qsv = new QSV("D:\\workspace\\c\\風(fēng)吹半夏第1集-藍(lán)光1080P.qsv");
    qsv.readHead();
    qsv.close();
}

public void readHead() throws IOException {
    //signature:10byte
    byte[] signature = getByteFromFile(0x0, 0xA);
    //version:4byte
    byte[] version = getByteFromFile(0xA, 0x4);
    //vid:16byte
    byte[] vid = getByteFromFile(0xE, 0x10);
    //_unknown1:4byte
    byte[] _unknown1 = getByteFromFile(0x1E, 0x4);
    //_unknown2:32byte
    byte[] _unknown2 = getByteFromFile(0x22, 0x20);
    //_unknown3:4byte
    byte[] _unknown3 = getByteFromFile(0x42, 0x4);
    //_unknown4:4byte
    byte[] _unknown4 = getByteFromFile(0x46, 0x4);
    //json_offset:8byte
    byte[] json_offset = getByteFromFile(0x4A, 0x8);
    //json_size:4byte
    byte[] json_size = getByteFromFile(0x52, 0x4);
    //nb_indices:4byte
    byte[] nb_indices = getByteFromFile(0x56, 0x4);
    System.out.println(String.format("signature:%s\nversion:%s\nvid:%s\n_unknown1:%s\n_unknown2:%s\n_unknown3:%s\n_unknown4:%s\njson_offset:0x%s\njson_size:0x%s\nnb_indices:0x%s",
            new String(signature), toInt(version), bytesToHex(vid), bytesToHex(_unknown1), bytesToHex(_unknown2), bytesToHex(_unknown3),
            bytesToHex(_unknown4), Integer.toHexString(toInt(json_offset)), Integer.toHexString(toInt(json_size)), Integer.toHexString(toInt(nb_indices))));
}

運行結(jié)果:

signature:QIYI VIDEO
version:2
vid:A90EA47D4333331BB85F331C1130504C
_unknown1:01000000
_unknown2:0000000000000000000000000000000000000000000000000000000000000000
_unknown3:01000000
_unknown4:01000000
json_offset:0x167
json_size:0x1d81
nb_indices:0x7

獲取json數(shù)據(jù)

獲取json數(shù)據(jù)需要先獲取頭部信息記錄的json的偏移位置和字節(jié)大小,獲取到的字節(jié)數(shù)組再通過老版本解密算法解密即可。

public static void main(String[] args) throws IOException {
    QSV qsv = new QSV("D:\\workspace\\c\\風(fēng)吹半夏第1集-藍(lán)光1080P.qsv");
    qsv.readJson();
    qsv.close();
}

public void readJson() throws IOException {
    //json_offset:8byte
    byte[] json_offset = getByteFromFile(0x4A, 0x8);
    //json_size:4byte
    byte[] json_size = getByteFromFile(0x52, 0x4);
    //json
    byte[] bs = getByteFromFile(toInt(json_offset), toInt(json_size));
    decrypt_1(bs, bs.length);
    System.out.println(String.format("json_offset:0x%s\njson_size:0x%s", Integer.toHexString(toInt(json_offset)), Integer.toHexString(toInt(json_size))));
    System.out.println(new String(bs, StandardCharsets.UTF_8));
}

運行結(jié)果:

json_offset:0x167
json_size:0x1d81
QYVI   {"qsv_info":{"ad":{},"aid":"3644740799867701","bid":600,"dr":-1,"independentaudio":true,"m3u8":"","pano":{"type":1},"qsvinfo_version":2,"sdv":"","st":"","thdt":1,"tht":0,"title":"","title_tail_info":{"bt":99,"bts":-1,"et":2621,"ete":-1,"fe":1,"le":0},"tvid":"3185901936393500","vd":{"seg":{"duration":["376140","365508","370300","371477","368311","368308","554319"],"rid":["a8c47c2906b88ae47e8503c96dae0494","4c8578cecbdfa3137a61b7e2bd1c68dc","4bc76f9b4d4ce995f40b42c467d206f8","8ed13ccd56aa2367f5eaabee12043d89","247b4612415c5b452f5965894a967e19","309400bef063cfd6baf19feb0d4a73a9","9771b1042cabfc9828767a3d0350f655"],"size":["75624801","84329329","90135782","82093900","91974933","75298884","111399115"]},"time":{"et":"2621000","st":"99000"}},"vi":"{\"writer\":\"\",\"authors\":\"\",\"upOrder\":36,\"rewardAllowed\":0,\"fl\":[],\"allowEditVVIqiyi\":0,\"isPopup\":1,\"payMark\":0,\"an\":\"風(fēng)吹半夏\",\"pvu\":\"\",\"subType\":1,\"rewardMessage\":\"\",\"ipLimit\":1,\"pubTime\":\"1673306651000\",\"mainActorRoles\":[],\"up\":\"2023-01-17 20:20:02\",\"un\":\"\",\"qiyiProduced\":1,\"platforms\":[],\"vn\":\"風(fēng)吹半夏第1集\",\"plc\":{\"4\":{\"downAld\":1,\"coa\":1},\"40\":{\"downAld\":1,\"coa\":1},\"10\":{\"downAld\":1,\"coa\":1},\"5\":{\"downAld\":1,\"coa\":1},\"41\":{\"downAld\":1,\"coa\":1},\"22\":{\"downAld\":1,\"coa\":1},\"32\":{\"downAld\":1,\"coa\":1},\"11\":{\"downAld\":1,\"coa\":1},\"12\":{\"downAld\":1,\"coa\":1},\"7\":{\"downAld\":1,\"coa\":1},\"13\":{\"downAld\":1,\"coa\":1},\"14\":{\"downAld\":1,\"coa\":1},\"91\":{\"downAld\":1,\"coa\":1},\"34\":{\"downAld\":1,\"coa\":1},\"9\":{\"downAld\":1,\"coa\":1},\"6\":{\"downAld\":1,\"coa\":1},\"16\":{\"downAld\":1,\"coa\":1},\"17\":{\"downAld\":1,\"coa\":1},\"27\":{\"downAld\":1,\"coa\":1},\"28\":{\"downAld\":1,\"coa\":1},\"18\":{\"downAld\":1,\"coa\":1},\"29\":{\"downAld\":1,\"coa\":1},\"1\":{\"downAld\":1,\"coa\":1},\"50\":{\"downAld\":1,\"coa\":1},\"31\":{\"downAld\":1,\"coa\":1},\"15\":{\"downAld\":1,\"coa\":1},\"2\":{\"downAld\":1,\"coa\":1},\"3\":{\"downAld\":1,\"coa\":1},\"21\":{\"downAld\":1,\"coa\":1},\"30\":{\"downAld\":1,\"coa\":1},\"19\":{\"downAld\":1,\"coa\":1},\"8\":{\"downAld\":1,\"coa\":1},\"20\":{\"downAld\":1,\"coa\":1}},\"sm\":0,\"st\":200,\"startTime\":99,\"showChannelId\":2,\"vu\":\"http:\\/\\/www.iqiyi.com\\/v_uvxuws1kkw.html\",\"povu\":\"\",\"ppsuploadid\":0,\"qiyiPlayStrategy\":\"非會員每日20:00轉(zhuǎn)免1集\",\"ar\":\"內(nèi)地\",\"cc\":0,\"videoQipuId\":3185901936393500,\"albumQipuId\":3644740799867701,\"pano\":{\"type\":1},\"subt\":\"許半夏幫童驍騎驅(qū)霉運\",\"endTime\":2621,\"cpa\":1,\"userVideocount\":0,\"es\":36,\"plg\":2774,\"stl\":{\"d\":\"http:\\/\\/meta.video.iqiyi.com\",\"stl\":[]},\"subKey\":\"3644740799867701\",\"tvFocuse\":\"趙麗穎歐豪攜手創(chuàng)業(yè)\",\"qtId\":0,\"ty\":0,\"ppsInfo\":{\"shortTitle\":\"風(fēng)吹半夏第1集\",\"name\":\"風(fēng)吹半夏第1集\"},\"sid\":0,\"etm\":\"\",\"keyword\":\"風(fēng)吹半夏\",\"pturl\":\"\",\"a\":\"\",\"isTopChart\":0,\"idl\":0,\"albumAlias\":\"許半夏幫童驍騎驅(qū)霉運\",\"stm\":\"\",\"pd\":1,\"tags\":[],\"coa\":0,\"c\":2,\"producers\":\"\",\"nurl\":\"\",\"tvEname\":\"wild bloom\",\"uid\":\"0\",\"asubt\":\"\",\"d\":\"傅東育|毛溦\",\"vid\":\"a90ea47d4333331bb85f331c1130504c\",\"dts\":\"20230117202002\",\"editorInfo\":\"\",\"tvSeason\":0,\"ntvd\":3185901936393500,\"vpic\":\"http:\\/\\/pic6.iqiyipic.com\\/image\\/20221127\\/e2\\/52\\/v_170312139_m_601_m1.jpg\",\"vType\":0,\"cType\":1,\"payMarkUrl\":\"\",\"apic\":\"http:\\/\\/pic8.iqiyipic.com\\/image\\/20230104\\/6c\\/00\\/a_100498846_m_601_m26.jpg\",\"shortTitle\":\"風(fēng)吹半夏第1集\",\"tvid\":3185901936393500,\"aid\":3644740799867701,\"au\":\"http:\\/\\/www.iqiyi.com\\/a_yq6d69gtw9.html\",\"tvPhase\":0,\"ifs\":0,\"is\":0,\"tpl\":[],\"actors\":[],\"isVip\":\"\",\"votes\":[],\"previewImageUrl\":\"http:\\/\\/preimage3.iqiyipic.com\\/preimage\\/20230110\\/6a\\/a6\\/v_170312139_m_611_m6.jpg\",\"e\":\"\",\"cnPremTime\":0,\"s\":\"\",\"ma\":\"趙麗穎|歐豪|李光潔|劉威|柯藍(lán)|任重|馮嘉怡|孫千|黃澄澄|是安|宋熹|王西|黃義威|王勁松|劉威葳|尤靖茹|林鵬(大陸男演員)|郝平|淮文|顏世魁|薛淑杰|劉碩|丁冠中|豆藝?yán)寇鐘吁|楊德民|傅宜箴|朱超藝|黃子琪|榮飛|田玲|周小鑌|孔琳|方曉莉|陳創(chuàng)|韓朔|高遠(yuǎn)\",\"supName\":\"\",\"sc\":0,\"categoryKeywords\":\"電視劇,3644740799867701,0,http:\\/\\/list.iqiyi.com\\/www\\/2\\/------------------.html 自制,12791537149997,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-12791537149997-----------------.html 浙江衛(wèi)視,20291787825994,0,http:\\/\\/list.iqiyi.com\\/www\\/2\\/------------------.html 家庭,23757144288056,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-23757144288056-----------------.html 言情,23789230921965,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-23789230921965-----------------.html 勵志,29717236536467,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-29717236536467-----------------.html 商戰(zhàn),32284167249109,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-32284167249109-----------------.html 劇情,37979544767779,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-37979544767779-----------------.html 都市,80141381722890,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-80141381722890-----------------.html 內(nèi)地,80526421329786,0,http:\\/\\/list.iqiyi.com\\/www\\/2\\/------------------.html 愛情,87328787718281,2,http:\\/\\/list.iqiyi.com\\/www\\/2\\/-87328787718281-----------------.html\",\"onlineStatus\":1,\"mdown\":0,\"bmsg\":{\"t\":\"20230117202002\",\"f\":\"web\",\"mid\":\"\",\"sp\":\"26173601,\"},\"nvid\":\"8ec7f862076f40ee17c908e2bbc3fae2\",\"flpps\":[],\"supType\":\"\",\"lg\":2,\"is3D\":0,\"bossStatus\":0,\"isDisplayCircle\":0,\"actorRoles\":[],\"exclusive\":1,\"circle\":{\"type\":0,\"id\":0},\"commentAllowed\":1,\"tg\":\"忠犬 大女主 自制 工業(yè)強(qiáng)國 毒舌 重組家庭 渣男 浙江衛(wèi)視 家庭 言情 霸道總裁 御姐 勵志 個人成長 虐戀 雙強(qiáng) 普通話 商戰(zhàn) 硬漢 劇情 出軌 兄弟反目 女強(qiáng)人 爽劇 初戀 青年奮斗 熱血 女性勵志 群像 個人奮斗 接地氣 女青年 大佬 原生家庭 豬隊友 都市 內(nèi)地 組團(tuán) 愛情\",\"info\":\"1996年的秋天,陽光炫目。許半夏開著一輛桑塔納,接著剛出獄的童驍騎駛往鷺州出差。一路上童驍騎默默無言,二人之間氣氛尷尬。到了酒店后,許半夏的指示很清楚:洗澡,看電視,睡覺,第二天一早,她來接童驍騎一起出差。童驍騎點點頭,在許半夏離開后,他開始洗澡,記憶也回到了五年前&hellip;&hellip;\\n1991年的一個雨夜,童驍騎因為急著給媽媽籌醫(yī)藥費,撬了一堆下水井蓋,蹬著三輪車?yán)搅嗽S半夏和小陳的廢品站。小陳認(rèn)定童驍騎就是個騙子,不愿幫忙,但善良的半夏相信童驍騎,給了他錢,并且三個人一大早一起把井蓋都送了回去。童驍騎為表感激,愿意替二人做事。許半夏提到當(dāng)?shù)劁搹S有很多廢了的下腳料,他們可以去收,但缺一輛大車。于是司機(jī)班出身的童驍騎真的把廠里的東風(fēng)偷偷開了出來,三人搖搖晃晃進(jìn)了鋼廠,掙到了人生的第一桶金,但童驍騎也因為私自用車被廠里開除了?;氐綇U品站的童驍騎心灰意冷,許半夏卻安慰道正好,今后他們?nèi)齻€人就一塊兒干,而這些錢就是他們的第一筆合伙資金。\",\"supId\":0,\"issueTime\":0,\"dtype\":3,\"producer\":\"\",\"presentor\":[],\"followerCount\":0}","vid":"a90ea47d4333331bb85f331c1130504c","videotype":0}}s

提取視頻信息

獲取視頻信息,首先要先提取索引信息,根據(jù)索引信息中的偏移位置和字節(jié)大小獲取,獲取到的字節(jié)數(shù)組前1024個字節(jié)需要解密,根據(jù)頭部信息中的version判斷,如果是1則用老版本算法解密,如果是2則用新版本算法解密。

一個QSV文件包含多段視頻數(shù)據(jù),已發(fā)現(xiàn)的視頻格式有flv(舊版客戶端)、mpeg-ts(新版客戶端)??梢酝ㄟ^前三個字節(jié)判斷,如果前三個字節(jié)轉(zhuǎn)字符串為FLV則為FLV格式。

public static void main(String[] args) throws IOException {
    QSV qsv = new QSV("D:\\workspace\\c\\風(fēng)吹半夏第1集-藍(lán)光1080P.qsv");
    qsv.readIndex("D:\\workspace\\c");
    qsv.close();
}

public void readIndex(String outPath) throws IOException {
    //nb_indices
    byte[] nb_indices = getByteFromFile(0x56, 0x4);
    //索引
    //_unknown_flag
    byte[] _unknown_flag = getByteFromFile(0x5A, toInt(nb_indices) + 7 >> 3);
    System.out.println(String.format("nb_indices:0x%s\n_unknown_flag:%s", Integer.toHexString(toInt(nb_indices)), bytesToHex(_unknown_flag)));
    //version:4byte
    byte[] version = getByteFromFile(0xA, 0x4);
    //索引體
    byte[] indices = getByteFromFile(0x5A + (toInt(nb_indices) + 7 >> 3), toInt(nb_indices) * 0x1C);
    for (int i = 0; i < toInt(nb_indices); i++) {
        byte[] indice = new byte[0x1C];
        System.arraycopy(indices, 0x1C * i, indice, 0, 0x1C);
        if (toInt(version) == 1) {
            decrypt_1(indice, indice.length);
        } else if (toInt(version) == 2) {
            decrypt_2(indice, indice.length);
        }
        //索引體
        //_codetable
        byte[] _codetable = new byte[0x10];
        System.arraycopy(indice, 0, _codetable, 0, 0x10);
        //segment_offset
        byte[] segment_offset = new byte[0x8];
        System.arraycopy(indice, 0x10, segment_offset, 0, 0x8);
        //segment_size
        byte[] segment_size = new byte[0x4];
        System.arraycopy(indice, 0x18, segment_size, 0, 0x4);
        System.out.println(String.format("_codetable:%s,segment_offset:0x%s,segment_size:0x%s", bytesToHex(_codetable), Integer.toHexString(toInt(segment_offset)), Integer.toHexString(toInt(segment_size))));
        exportVideo(i + 1, segment_offset, segment_size, outPath);
    }
}

private void exportVideo(int fileindex, byte[] segment_offset, byte[] segment_size, String outPath) throws IOException {
    byte[] file = getByteFromFile(toInt(segment_offset), toInt(segment_size));
    //前1024字節(jié)加密
    decrypt_2(file, 1024);
    byte[] head = new byte[0x3];
    System.arraycopy(file, 0, head, 0, 0x3);
    //System.out.println(new String(head));
    String outname = name.substring(name.lastIndexOf(File.separator) + 1);
    String outFile = outPath + File.separator + outname.substring(0, outname.lastIndexOf(".")) + "-第" + fileindex + "段." + new String(head).toLowerCase();
    RandomAccessFile write = new RandomAccessFile(outFile, "rw");
    System.out.println("export:" + outFile);
    write.write(file);
    write.close();
}

運行結(jié)果:

nb_indices:0x7
_unknown_flag:7F
_codetable:A8C47C2906B88AE47E8503C96DAE0494,segment_offset:0x1ee8,segment_size:0x481f161
export:D:\workspace\c\風(fēng)吹半夏第1集-藍(lán)光1080P-第1段.flv
_codetable:4C8578CECBDFA3137A61B7E2BD1C68DC,segment_offset:0x4821049,segment_size:0x506c371
export:D:\workspace\c\風(fēng)吹半夏第1集-藍(lán)光1080P-第2段.flv
_codetable:4BC76F9B4D4CE995F40B42C467D206F8,segment_offset:0x988d3ba,segment_size:0x55f5ce6
export:D:\workspace\c\風(fēng)吹半夏第1集-藍(lán)光1080P-第3段.flv
_codetable:8ED13CCD56AA2367F5EAABEE12043D89,segment_offset:0xee830a0,segment_size:0x4e4a74c
export:D:\workspace\c\風(fēng)吹半夏第1集-藍(lán)光1080P-第4段.flv
_codetable:247B4612415C5B452F5965894A967E19,segment_offset:0x13ccd7ec,segment_size:0x57b6d15
export:D:\workspace\c\風(fēng)吹半夏第1集-藍(lán)光1080P-第5段.flv
_codetable:309400BEF063CFD6BAF19FEB0D4A73A9,segment_offset:0x19484501,segment_size:0x47cf844
export:D:\workspace\c\風(fēng)吹半夏第1集-藍(lán)光1080P-第6段.flv
_codetable:9771B1042CABFC9828767A3D0350F655,segment_offset:0x1dc53d45,segment_size:0x6a3d0cb
export:D:\workspace\c\風(fēng)吹半夏第1集-藍(lán)光1080P-第7段.flv

以上就是“Java怎么實現(xiàn)提取QSV文件視頻內(nèi)容”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI