Skip to content

Commit

Permalink
feat:mp4转码
Browse files Browse the repository at this point in the history
  • Loading branch information
hellowmonkey committed Oct 3, 2022
1 parent 55a9c34 commit fd8f303
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 18 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"dependencies": {
"cropperjs": "^1.5.12",
"dayjs": "^1.10.8",
"mux.js": "^6.2.0",
"naive-ui": "^2.33.2",
"normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
Expand Down
2 changes: 2 additions & 0 deletions src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ declare let electronAPI: {
};

declare module "qrcode-decoder";

declare module "mux.js";
78 changes: 61 additions & 17 deletions src/page/video/m3u8.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DownloadStatus, downloadStatusList, IM3u8Item, ITsItem } from "@/servic
import { NAlert, NButton, NCard, NInput, NInputGroup, NInputGroupLabel, NProgress, NTag, NText } from "naive-ui";
import { computed, defineComponent, onActivated, onMounted, reactive, ref } from "vue";
import { useRoute } from "vue-router";
import muxjs from "mux.js";

export default defineComponent({
props: {},
Expand All @@ -30,6 +31,7 @@ export default defineComponent({
const total = list.length;
const doneNum = list.filter(li => li.status === DownloadStatus.FINISHED).length;
const percentage = Number(((doneNum / total) * 100).toFixed(2));
const duration = list.reduce((t, v) => t + v.duration, 0);
if (tsList.value.some(t => t.status === DownloadStatus.DOWNLOADING)) {
status = DownloadStatus.DOWNLOADING;
} else if (tsList.value.some(t => t.status === DownloadStatus.ERROR)) {
Expand All @@ -45,6 +47,7 @@ export default defineComponent({
percentage,
total,
doneNum,
duration,
};
});
return data;
Expand All @@ -69,8 +72,16 @@ export default defineComponent({
}

const tempArr: ITsItem[] = [];
data.split(/\s/).forEach(item => {
const lines = data.split(/\s/);
lines.forEach((item, index) => {
if (/((\.ts)|(\.jpg)|(\.png)|(\.gif)|(\.image))(\?.+)?$/i.test(item)) {
// 计算持续时间
let duration = 0;
const durationItem = lines[index - 1];
const extinf = "#EXTINF:";
if (durationItem.includes(extinf)) {
duration = parseFloat(durationItem.split(extinf)[1]) || 0;
}
const src = getFullUrl(origin, item);
tempArr.push({
status: DownloadStatus.WAITING,
Expand All @@ -79,6 +90,7 @@ export default defineComponent({
filePath: form.filePath,
src,
file: undefined,
duration,
});
}
});
Expand Down Expand Up @@ -106,27 +118,50 @@ export default defineComponent({
downloadTs();
}
}
function downloadTs() {
async function downloadTs() {
const index = tsList.value.findIndex(v => v.status === DownloadStatus.WAITING);
if (index === -1) {
return;
}
const item = tsList.value[index];
tsList.value[index].status = DownloadStatus.DOWNLOADING;
ajax<Buffer>(tsList.value[index].src, "arraybuffer")
.then(data => {
tsList.value[index].status = DownloadStatus.FINISHED;
tsList.value[index].file = data;
const m3u8 = m3u8List.value.find(v => v.src === tsList.value[index].m3u8Src);
if (m3u8?.status === DownloadStatus.FINISHED) {
downloadFile(m3u8);
}
})
.catch(() => {
tsList.value[index].status = DownloadStatus.ERROR;
})
.finally(() => {
downloadTs();
try {
const data = await ajax<Buffer>(item.src, "arraybuffer");
// 转码mp4
const file: Uint8Array = await new Promise(resolve => {
const { duration } = m3u8List.value.find(v => v.src === item.m3u8Src)!;
const opts = duration
? {
keepOriginalTimestamps: true,
duration,
}
: undefined;
const transmuxer = new muxjs.mp4.Transmuxer(opts);
const timer = setTimeout(() => {
resolve(data);
}, 2000);
transmuxer.on("data", (segment: any) => {
clearTimeout(timer);
const data = new Uint8Array(segment.initSegment.byteLength + segment.data.byteLength);
data.set(segment.initSegment, 0);
data.set(segment.data, segment.initSegment.byteLength);
resolve(data);
});
transmuxer.push(new Uint8Array(data));
transmuxer.flush();
});

tsList.value[index].status = DownloadStatus.FINISHED;
tsList.value[index].file = file;
const m3u8 = m3u8List.value.find(v => v.src === item.m3u8Src);
if (m3u8?.status === DownloadStatus.FINISHED) {
downloadFile(m3u8);
}
} catch (e) {
tsList.value[index].status = DownloadStatus.ERROR;
} finally {
downloadTs();
}
}

// 文件下载
Expand Down Expand Up @@ -332,7 +367,16 @@ export default defineComponent({
downloadFile(item);
}}
>
保存视频
下载视频
</NButton>
) : item.percentage > 0 ? (
<NButton
class="mar-r-3-item"
onClick={() => {
downloadFile(item);
}}
>
强制下载
</NButton>
) : null}
{config.isElectron ? (
Expand Down
4 changes: 3 additions & 1 deletion src/service/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export interface ITsItem {
m3u8Src: string;
name: string;
filePath: string;
file?: Buffer;
file?: Uint8Array;
duration: number;
}
export interface IM3u8Item {
status: DownloadStatus;
Expand All @@ -46,6 +47,7 @@ export interface IM3u8Item {
percentage: number;
total: number;
doneNum: number;
duration: number;
}

export const circuits: { label: string; value: string }[] = [
Expand Down
45 changes: 45 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/plugin-syntax-typescript" "^7.18.6"

"@babel/runtime@^7.11.2":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
dependencies:
regenerator-runtime "^0.13.4"

"@babel/template@^7.0.0", "@babel/template@^7.18.10":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
Expand Down Expand Up @@ -1888,6 +1895,11 @@ dom-serializer@^1.0.1:
domhandler "^4.2.0"
entities "^2.0.0"

dom-walk@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==

domelementtype@^2.0.1, domelementtype@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
Expand Down Expand Up @@ -2637,6 +2649,14 @@ global-tunnel-ng@^2.7.1:
npm-conf "^1.1.3"
tunnel "^0.0.6"

global@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
dependencies:
min-document "^2.19.0"
process "^0.11.10"

globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
Expand Down Expand Up @@ -3320,6 +3340,13 @@ mimic-response@^1.0.0, mimic-response@^1.0.1:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==

min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==
dependencies:
dom-walk "^0.1.0"

min-indent@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
Expand Down Expand Up @@ -3397,6 +3424,14 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==

mux.js@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-6.2.0.tgz#158a4fcf5d83b087ab9037d325527ea993f830a3"
integrity sha512-SKuxIcbmK/aJoz78aQNuoXY8R/uEPm1gQMqWTXL6DNl7oF8UPjdt/AunXGkPQpBouGWKDgL/TzSl2VV5NuboRg==
dependencies:
"@babel/runtime" "^7.11.2"
global "^4.4.0"

naive-ui@^2.33.2:
version "2.33.2"
resolved "https://registry.yarnpkg.com/naive-ui/-/naive-ui-2.33.2.tgz#c74e8b7c944f6af18cd850bd640f6d3485a47f05"
Expand Down Expand Up @@ -3973,6 +4008,11 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==

process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==

progress@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
Expand Down Expand Up @@ -4218,6 +4258,11 @@ redent@^3.0.0:
indent-string "^4.0.0"
strip-indent "^3.0.0"

regenerator-runtime@^0.13.4:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==

regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
Expand Down

0 comments on commit fd8f303

Please sign in to comment.