|
|
@@ -1,11 +1,375 @@
|
|
|
-<script setup lang="ts">
|
|
|
+<template>
|
|
|
+ <div class="video-settings">
|
|
|
+ <!-- 主码流 -->
|
|
|
+ <fieldset class="stream-section">
|
|
|
+ <legend>Main Stream</legend>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Resolution:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="mainStream.MainResolution">
|
|
|
+ <el-option v-for="item in mainResolutionOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Encoding Format:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="mainStream.encodeType">
|
|
|
+ <el-option v-for="item in encodeTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Frame Rate:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="mainStream.MainFps">
|
|
|
+ <el-option v-for="item in frameRateOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Bitrate:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-input-number v-model="mainStream.MainBitRate" :min="1024" :max="3072" :controls="false" />
|
|
|
+ <span class="form-item__hint">(1024,3072)</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Bitrate Control:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="mainStream.MainEcdFmat">
|
|
|
+ <el-option v-for="item in bitRateControlOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">I-Frame Interval:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-input-number v-model="mainStream.MainFrameTime" :min="100" :max="200" :controls="false" />
|
|
|
+ <span class="form-item__hint">(100,200)</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </fieldset>
|
|
|
|
|
|
-</script>
|
|
|
+ <!-- 子码流 -->
|
|
|
+ <fieldset class="stream-section">
|
|
|
+ <legend>Sub Stream</legend>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Resolution:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="subStream.SecondResolution">
|
|
|
+ <el-option v-for="item in subResolutionOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Encoding Format:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="subStream.encodeType">
|
|
|
+ <el-option v-for="item in encodeTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Frame Rate:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="subStream.SecondFps">
|
|
|
+ <el-option v-for="item in frameRateOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Bitrate:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-input-number v-model="subStream.SecondBitRate" :min="1024" :max="3072" :controls="false" />
|
|
|
+ <span class="form-item__hint">(1024,3072)</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">Bitrate Control:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-select v-model="subStream.SecondEcdFmat">
|
|
|
+ <el-option v-for="item in bitRateControlOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="form-item__label">I-Frame Interval:</span>
|
|
|
+ <div class="form-item__control">
|
|
|
+ <el-input-number v-model="subStream.SecondFrameTime" :min="100" :max="200" :controls="false" />
|
|
|
+ <span class="form-item__hint">(100,200)</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </fieldset>
|
|
|
|
|
|
-<template>
|
|
|
-
|
|
|
+ <!-- 实时模式 -->
|
|
|
+ <!-- <div class="realtime-section">
|
|
|
+ <span class="form-item__label">实时模式:</span>
|
|
|
+ <el-checkbox v-model="realtimeMode" />
|
|
|
+ <span class="realtime-tip">(开启后,夜视动态效果好,但可能会影响静态图像效果)</span>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- 底部按钮 -->
|
|
|
+ <div class="btn-wrapper">
|
|
|
+ <el-button round class="btn-reset" @click="resetDefaults">Restore Defaults</el-button>
|
|
|
+ <el-button round type="primary" class="btn-save" @click="saveParams">Save</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
+<script setup lang="ts">
|
|
|
+import { reactive, ref, onMounted } from 'vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import { getVideoEncodePara, putVideoEncodePara } from '@/api/setting'
|
|
|
+
|
|
|
+// 主码流参数
|
|
|
+const mainStream = reactive({
|
|
|
+ MainResolution: 5,
|
|
|
+ encodeType: 0,
|
|
|
+ MainFps: 25,
|
|
|
+ MainBitRate: 3072,
|
|
|
+ MainEcdFmat: 0,
|
|
|
+ MainFrameTime: 100
|
|
|
+})
|
|
|
+
|
|
|
+// 子码流参数
|
|
|
+const subStream = reactive({
|
|
|
+ SecondResolution: 0,
|
|
|
+ encodeType: 0,
|
|
|
+ SecondFps: 25,
|
|
|
+ SecondBitRate: 3072,
|
|
|
+ SecondEcdFmat: 0,
|
|
|
+ SecondFrameTime: 100
|
|
|
+})
|
|
|
+
|
|
|
+// 实时模式
|
|
|
+const realtimeMode = ref(false)
|
|
|
+
|
|
|
+
|
|
|
+// 主码流分辨率选项
|
|
|
+const mainResolutionOptions = [
|
|
|
+ { value: 5, label: '2880*1620 (5M)' },
|
|
|
+ { value: 4, label: '2560*1440 (4M)' },
|
|
|
+ { value: 3, label: '2304*1296 (3M)' },
|
|
|
+ { value: 2, label: '1920*1080 (1080P)' },
|
|
|
+ { value: 1, label: '1280*720 (720P)' },
|
|
|
+ { value: 0, label: '640*360' },
|
|
|
+]
|
|
|
+
|
|
|
+// 子码流分辨率选项
|
|
|
+const subResolutionOptions = [
|
|
|
+ { value: 0, label: '640*360' },
|
|
|
+]
|
|
|
+
|
|
|
+// 编码格式选项
|
|
|
+const encodeTypeOptions = [
|
|
|
+ { value: 0, label: 'H264' },
|
|
|
+ // { value: 1, label: 'H265' }
|
|
|
+]
|
|
|
+
|
|
|
+// 帧率选项
|
|
|
+const frameRateOptions = [
|
|
|
+ { value: 10, label: '10' },
|
|
|
+ { value: 11, label: '11' },
|
|
|
+ { value: 12, label: '12' },
|
|
|
+ { value: 13, label: '13' },
|
|
|
+ { value: 14, label: '14' },
|
|
|
+ { value: 15, label: '15' },
|
|
|
+ { value: 16, label: '16' },
|
|
|
+ { value: 17, label: '17' },
|
|
|
+ { value: 18, label: '18' },
|
|
|
+ { value: 19, label: '19' },
|
|
|
+ { value: 20, label: '20' },
|
|
|
+ { value: 21, label: '21' },
|
|
|
+ { value: 22, label: '22' },
|
|
|
+ { value: 23, label: '23' },
|
|
|
+ { value: 24, label: '24' },
|
|
|
+ { value: 25, label: '25' },
|
|
|
+]
|
|
|
+
|
|
|
+// 码率控制选项
|
|
|
+const bitRateControlOptions = [
|
|
|
+ { value: 0, label: 'AVBR' },
|
|
|
+ { value: 1, label: 'CBR' }
|
|
|
+]
|
|
|
+
|
|
|
+
|
|
|
+// 恢复默认设置
|
|
|
+async function resetDefaults() {
|
|
|
+ // 主码流
|
|
|
+ mainStream.MainResolution = 5
|
|
|
+ mainStream.encodeType = 0
|
|
|
+ mainStream.MainFps = 25
|
|
|
+ mainStream.MainBitRate = 3072
|
|
|
+ mainStream.MainEcdFmat = 0
|
|
|
+ mainStream.MainFrameTime = 100
|
|
|
+ // 子码流
|
|
|
+ subStream.SecondResolution = 0
|
|
|
+ subStream.encodeType = 0
|
|
|
+ subStream.SecondFps = 25
|
|
|
+ subStream.SecondBitRate = 3072
|
|
|
+ subStream.SecondEcdFmat = 0
|
|
|
+ subStream.SecondFrameTime = 100
|
|
|
+
|
|
|
+ // realtimeMode.value = false
|
|
|
+
|
|
|
+ await saveParams()
|
|
|
+}
|
|
|
+
|
|
|
+// 获取视频编码参数
|
|
|
+async function fetchParams() {
|
|
|
+ try {
|
|
|
+ const res = await getVideoEncodePara()
|
|
|
+ if (res.data) {
|
|
|
+ const d = res.data
|
|
|
+ // 主码流
|
|
|
+ if (d.MainResolution !== undefined) mainStream.MainResolution = d.MainResolution
|
|
|
+ // if (d.mainEncodeType !== undefined) mainStream.encodeType = d.mainEncodeType
|
|
|
+ if (d.MainFps !== undefined) mainStream.MainFps = d.MainFps
|
|
|
+ if (d.MainBitRate !== undefined) mainStream.MainBitRate = d.MainBitRate
|
|
|
+ if (d.MainEcdFmat !== undefined) mainStream.MainEcdFmat = d.MainEcdFmat
|
|
|
+ if (d.MainFrameTime !== undefined) mainStream.MainFrameTime = d.MainFrameTime
|
|
|
+ // // 子码流
|
|
|
+ if (d.SecondResolution !== undefined) subStream.SecondResolution = d.SecondResolution
|
|
|
+ // if (d.subEncodeType !== undefined) subStream.encodeType = d.subEncodeType
|
|
|
+ if (d.SecondFps !== undefined) subStream.SecondFps = d.SecondFps
|
|
|
+ if (d.SecondBitRate !== undefined) subStream.SecondBitRate = d.SecondBitRate
|
|
|
+ if (d.SecondEcdFmat !== undefined) subStream.SecondEcdFmat = d.SecondEcdFmat
|
|
|
+ if (d.SecondFrameTime !== undefined) subStream.SecondFrameTime = d.SecondFrameTime
|
|
|
+ // // 实时模式
|
|
|
+ // if (d.realtimeMode !== undefined) realtimeMode.value = !!d.realtimeMode
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取视频编码参数失败:', e)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 保存参数
|
|
|
+async function saveParams() {
|
|
|
+ try {
|
|
|
+ const data = {
|
|
|
+ MainResolution: mainStream.MainResolution,
|
|
|
+ // mainEncodeType: mainStream.encodeType,
|
|
|
+ MainFps: mainStream.MainFps,
|
|
|
+ MainBitRate: mainStream.MainBitRate,
|
|
|
+ MainEcdFmat: mainStream.MainEcdFmat,
|
|
|
+ MainFrameTime: mainStream.MainFrameTime,
|
|
|
+ SecondResolution: subStream.SecondResolution,
|
|
|
+ // subEncodeType: subStream.encodeType,
|
|
|
+ SecondFps: subStream.SecondFps,
|
|
|
+ SecondBitRate: subStream.SecondBitRate,
|
|
|
+ SecondEcdFmat: subStream.SecondEcdFmat,
|
|
|
+ SecondFrameTime: subStream.SecondFrameTime,
|
|
|
+ // realtimeMode: realtimeMode.value ? 1 : 0
|
|
|
+ }
|
|
|
+ const res = await putVideoEncodePara(data)
|
|
|
+ if (res.data === 'ok\n') {
|
|
|
+ ElMessage.success('Save Successful')
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ ElMessage.warning('Save Failed')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ fetchParams()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
<style scoped lang="scss">
|
|
|
+.video-settings {
|
|
|
+ padding: 10px 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.stream-section {
|
|
|
+ border: 1px solid #eee;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 20px 30px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ legend {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+ padding: 0 8px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.form-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 16px;
|
|
|
+
|
|
|
+ &__label {
|
|
|
+ flex: 0 0 120px;
|
|
|
+ text-align: right;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #606266;
|
|
|
+ padding-right: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__control {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .el-select {
|
|
|
+ width: 220px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input-number {
|
|
|
+ width: 220px;
|
|
|
+
|
|
|
+ :deep(.el-input__inner) {
|
|
|
+ text-align: left;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__hint {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.realtime-section {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 20px 0;
|
|
|
+ border-top: 1px solid #eee;
|
|
|
+
|
|
|
+ .form-item__label {
|
|
|
+ flex: 0 0 100px;
|
|
|
+ text-align: right;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #606266;
|
|
|
+ padding-right: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .realtime-tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ margin-left: 8px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.btn-wrapper {
|
|
|
+ display: flex;
|
|
|
+ // justify-content: space-between;
|
|
|
+ gap: 200px;
|
|
|
+ padding-top: 20px;
|
|
|
+
|
|
|
+ .btn-reset {
|
|
|
+ border-color: #409EFF;
|
|
|
+ color: #409EFF;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: #409EFF;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-</style>
|
|
|
+ .btn-save {
|
|
|
+ min-width: 100px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|