Skip to content

Commit

Permalink
Very first draft of the WebUI, preliminary support for hisi-gen1, new…
Browse files Browse the repository at this point in the history
… toolchain options
  • Loading branch information
wberube committed Aug 8, 2024
1 parent ac156c5 commit 4421f90
Show file tree
Hide file tree
Showing 17 changed files with 3,112 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

- name: Build
run: |
list="arm-musl arm-muslhf arm-glibc arm9-musl arm9-uclibc mips-musl"
list="arm-musl arm9-musl3 arm9-musl4 arm9-uclibc armhf-musl armhf-glibc mips-musl"
for lib in $list; do
sh build.sh $lib
zip $lib divinus*
Expand Down
14 changes: 8 additions & 6 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ fi

if [ "$1" = "arm-musl" ]; then
toolchain cortex_a7_thumb2-gcc13-musl-4_9 arm
elif [ "$1" = "arm-muslhf" ]; then
toolchain cortex_a7_thumb2_hf-gcc13-musl-4_9 arm
elif [ "$1" = "arm-glibc" ]; then
toolchain cortex_a7_thumb2_hf-gcc13-glibc-4_9 arm -lm
elif [ "$1" = "arm9-musl" ]; then
elif [ "$1" = "arm9-musl3" ]; then
toolchain arm926t-gcc13-musl-3_0 arm
elif [ "$1" = "arm9-musl4" ]; then
toolchain arm926t-gcc13-musl-4_9 arm
elif [ "$1" = "arm9-uclibc" ]; then
toolchain arm926t-gcc13-uclibc-3_3 arm
elif [ "$1" = "armhf-glibc" ]; then
toolchain cortex_a7_thumb2_hf-gcc13-glibc-4_9 arm -lm
elif [ "$1" = "armhf-musl" ]; then
toolchain cortex_a7_thumb2_hf-gcc13-musl-4_9 arm
elif [ "$1" = "mips-musl" ]; then
toolchain mips_xburst-gcc13-musl-3_10 mipsel
else
echo "Usage: $0 [arm-musl|arm-muslhf|arm-glibc|arm9-musl|arm9-uclibc|mips-musl]"
echo "Usage: $0 [arm-musl|arm9-musl3|arm9-musl4|arm9-uclibc|armhf-glibc|armhf-musl|mips-musl]"
fi
243 changes: 243 additions & 0 deletions res/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<html>
<head>
<title>Divinus</title>
<style>
*{box-sizing:border-box}*+*{margin:.5em 0}pre{overflow:auto}@media(min-width:35em){.col{display:table-cell}.\31{width:5%}.\33{width:22%}.\34{width:30%}.\35{width:40%}.\32{width:15%}.\36{width:50%}.row{display:table;border-spacing:1em 0}}.row,.w-100{width:100%}.card:focus,hr{outline:0;border:solid #fa0}.card,pre{padding:1em;border:solid #eee}.btn:hover,a:hover{opacity:.6}.c{padding:1em;margin:auto;font:1em/1.6 sans-serif}h6{font:400 1em sans-serif}h5{font:400 1.2em sans-serif}h3{font:400 2em sans-serif}h4{font:400 1.5em sans-serif}h2{font:400 2.2em sans-serif}h1{font:400 2.5em sans-serif}a{color:#fa0;text-decoration:none}.btn.primary{color:#fff;background:#fa0;border:solid #fa0}td,th{padding:1em;text-align:left;border-bottom:solid #eee}.btn{padding:1em;text-transform:uppercase;background:#fff;border:solid;font:.7em sans-serif}a.btn{display:inline-block}input,select{font-family:sans-serif}
.white{color:#fff}.bg-white{background-color:#fff}.b-white{border-color:#fff}.gray{color:#ccc}.bg-gray{background-color:#ccc}.b-gray{border-color:#ccc}.black{color:#000}.bg-black{background-color:#000}.b-black{border-color:#000}.accent{color:#fa0}.bg-accent{background-color:#fa0}.b-accent{border-color:#fa0}.warning{color:#ffd600}.bg-warning{background-color:#ffd600}.b-warning{border-color:#ffd600}.error{color:#d50000}.bg-error{background-color:#d50000}.b-error{border-color:#d50000}.success{color:#00c853}.bg-success{background-color:#00c853}.b-success{border-color:#00c853}.info{color:#2962ff}.bg-info{background-color:#2962ff}.b-info{border-color:#2962ff}.m0{margin:0}.m1{margin:.5em}.m2{margin:1em}.m3{margin:2em}.m4{margin:4em}.mt0{margin-top:0}.mt1{margin-top:.5em}.mt2{margin-top:1em}.mt3{margin-top:2em}.mt4{margin-top:4em}.mr0{margin-right:0}.mr1{margin-right:.5em}.mr2{margin-right:1em}.mr3{margin-right:2em}.mr4{margin-right:4em}.mb0{margin-bottom:0}.mb1{margin-bottom:.5em}.mb2{margin-bottom:1em}.mb3{margin-bottom:2em}.mb4{margin-bottom:4em}.ml0{margin-left:0}.ml1{margin-left:.5em}.ml2{margin-left:1em}.ml3{margin-left:2em}.ml4{margin-left:4em}.p0{padding:0}.p1{padding:.5em}.p2{padding:1em}.p3{padding:2em}.p4{padding:4em}.pv0{padding-top:0;padding-bottom:0}.pv1{padding-top:.5em;padding-bottom:.5em}.pv2{padding-top:1em;padding-bottom:1em}.pv3{padding-top:2em;padding-bottom:2em}.pv4{padding-top:4em;padding-bottom:4em}.ph0{padding-right:0;padding-left:0}.ph1{padding-right:.5em;padding-left:.5em}.ph2{padding-right:1em;padding-left:1em}.ph3{padding-right:2em;padding-left:2em}.ph4{padding-right:4em;padding-left:4em}.gapless{border-spacing:0}.vc{position:relative;top:40%;transform:perspective(1px) translateY(-45%)}.pill{border-radius:9999px}.rounded{border-radius:4px}.tc{text-align:center}.mega{font-size:3.5em}.large{font-size:1.5em}.small{font-size:.7em}.caps{text-transform:uppercase}.tracked{letter-spacing:.1em}.vh-100{height:100vh}.inline{display:inline-block}.bold{font-weight:700}.normal{font-weight:400}.light{font-weight:300}.dim{opacity:1;transition:opacity .15s ease-in}.dim:focus,.dim:hover{opacity:.5;transition:opacity .15s ease-in}
dialog{display:block;border:0;padding:0!important}dialog:not(:target):not([open]){display:none}.hid{display:none}
</style>
<script>
var ua = window.navigator.userAgent;
var isIe = ua.indexOf('MSIE ') > -1 || ua.indexOf('Trident/') > -1;

function apiApply(endp) {
var dest = "/api/"+endp+"?", req = new XMLHttpRequest();
var elems = document.getElementsByTagName('*');
for (var i = 0; i < elems.length; i++) {
if (!elems[i].name || elems[i].name.lastIndexOf(endp + '_', 0)) continue;
dest += elems[i].name.substring(endp.length + 1) + '=' + elems[i].value + '&';
}
dest = dest.slice(0, -1);
req.open('GET', dest);
req.send();
}

function apiRead(endp) {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (this.readyState != 4 || this.status != 200) return;
var dec = JSON.parse(req.responseText);
for (var key in dec) {
if (!dec.hasOwnProperty(key)) continue;
var elem = document.getElementById(endp + '_' + key);
if (!elem) continue;
elem.value = dec[key];
}
}
req.open('GET', '/api/'+endp);
req.send();
}

function logout() {
if (isIe)
document.execCommand('ClearAuthenticationCache', 'false');
else
window.location = window.location.href.replace('://', '://log:out@');
}

function setSource(id, src) {
var frame = document.getElementById(id), ext = ".mp4";
if (frame.firstChild) frame.firstChild.src = "#";
if (src.indexOf(ext, src.length - ext.length) > -1)
frame.innerHTML = '<video id="player" src="'+src+'" width="100%" autoplay controls>';
else if (src)
frame.innerHTML = '<img src="'+src+'" width="100%">';
else
while (frame.firstChild) frame.removeChild(frame.firstChild);
}

function onLoad() {
apiRead('audio');
apiRead('mp4');
apiRead('mjpeg');
apiRead('jpeg');
apiRead('night');
}
</script>
</head>
<body class="m0" onload="onLoad()">
<noscript>
<div class="tc vh-100 bg-info">
<div class="vc c white">
<h1 class="mega mb0">Divinus</h1>
<p class="large mb2">Error: JavaScript is required to access this page!</p>
</div>
</div>
</noscript>
<dialog id="live" class="c vh-100 w-100">
<div class="c bg-black pv2 row">
<div class="col">
<b><a href="./" class="white ph2">Divinus</a></b>
<span class="ph2 gray">Live</span>
<a href="javascript:setSource('preview', 'video.mp4')" class="ph2">MP4</a>
<a href="javascript:setSource('preview', 'mjpeg')" class="ph2">MJPEG</a>
<a href="javascript:setSource('preview', '')" class="ph2">Stop</a>
</div>
<div class="1 col">
<a class="btn primary" href="#!">Close</a>
</div>
</div>
<div id="preview" width="100%">
</dialog>
<dialog id="media" class="c vh-100 w-100">
<div class="c bg-black pv2 row">
<div class="col">
<b><a href="./" class="white ph2">Divinus</a></b>
<span class="ph2 gray">Media</span>
</div>
<div class="1 col">
<a class="btn primary" href="#!">Close</a>
</div>
</div>
<div class="c row">
<fieldset>
<legend>Audio</legend>
<table>
<tr>
<td><label for="audio_bitrate">Bitrate (kbps)</label></td>
<td><input type="number" id="audio_bitrate" name="audio_bitrate"></td>
</tr>
<tr>
<td><label for="audio_srate">Sample rate (Hz)</label></td>
<td><input type="number" id="audio_srate" name="audio_srate"></td>
</tr>
</table>
<a href="javascript:apiApply('audio')" class="btn">Apply</a>
</fieldset>
</div>
<div class="c row">
<fieldset>
<legend>MP4</legend>
<table>
<tr>
<td><label for="mp4_width">Width</label></td>
<td><input type="number" id="mp4_width" name="mp4_width"></td>
</tr>
<tr>
<td><label for="mp4_height">Height</label>
<td><input type="number" id="mp4_height" name="mp4_height"></td>
</tr>
<tr>
<td><label for="mp4_fps">Framerate</label></td>
<td><input type="number" id="mp4_fps" name="mp4_fps"></td>
</tr>
<tr>
<td><label for="mp4_bitrate">Bitrate (kbps)</label></td>
<td><input type="number" id="mp4_bitrate" name="mp4_bitrate"></td>
</tr>
<tr>
<td><label for="mp4_h265">Codec</label></td>
<td><select id="mp4_h265" name="mp4_h265">
<option value="false">H.264</option>
<option value="true">H.265</option>
</select></td>
</tr>
<tr>
<td><label for="mp4_mode">Rate control</label></td>
<td><select id="mp4_mode" name="mp4_mode">
<option value="CBR">CBR</option>
<option value="VBR">VBR</option>
<option value="QP">QP</option>
<option value="ABR">ABR</option>
<option value="AVBR">AVBR</option>
</select></td>
</tr>
<tr>
<td><label for="mp4_profile">Profile</label></td>
<td><select id="mp4_profile" name="mp4_profile">
<option value="BP">Baseline</option>
<option value="MP">Main</option>
<option value="HP">High</option>
</select></td>
</tr>
</table>
<a href="javascript:apiApply('mp4')" class="btn">Apply</a>
</fieldset>
</div>
<div class="c row">
<fieldset>
<legend>MJPEG</legend>
<table>
<tr>
<td><label for="mjpeg_width">Width</label></td>
<td><input type="number" id="mjpeg_width" name="mjpeg_width"></td>
</tr>
<tr>
<td><label for="mjpeg_height">Height</label></td>
<td><input type="number" id="mjpeg_height" name="mjpeg_height"></td>
</tr>
<tr>
<td><label for="mjpeg_fps">Framerate</label></td>
<td><input type="number" id="mjpeg_fps" name="mjpeg_fps"></td>
</tr>
<tr>
<td><label for="mjpeg_mode">Rate control</label></td>
<td><select id="mjpeg_mode" name="mjpeg_mode">
<option value="CBR">CBR</option>
<option value="VBR">VBR</option>
<option value="QP">QP</option>
</select></td>
</tr>
</table>
<a href="javascript:apiApply('mjpeg')" class="btn">Apply</a>
</fieldset>
</div>
<div class="c row">
<fieldset>
<legend>JPEG</legend>
<table>
<tr>
<td><label for="jpeg_width">Width</label></td>
<td><input type="number" id="jpeg_width" name="jpeg_width"></td>
</tr>
<tr>
<td><label for="jpeg_height">Height</label></td>
<td><input type="number" id="jpeg_height" name="jpeg_height"></td>
</tr>
<tr>
<td><label for="jpeg_qfactor">Quality (%)</label></td>
<td><input type="number" id="jpeg_qfactor" name="jpeg_qfactor"></td>
</tr>
</table>
<a href="javascript:apiApply('jpeg')" class="btn">Apply</a>
</fieldset>
</div>
<div class="c row">
<fieldset>
<legend>Night</legend>
<table>
<tr>
<td><label for="night_active">Manual</label></td>
<td><select id="night_active" name="night_active">
<option value="false">OFF</option>
<option value="true">ON</option>
</select></td>
</tr>
</table>
<a href="javascript:apiApply('night')" class="btn">Apply</a>
</fieldset>
</div>
</dialog>
<div class="c bg-black pv2 row">
<div class="col">
<b><a href="./" class="ph2 white">Divinus</a></b>
<a href="#live" class="ph2 white">Live</a>
<a href="#media" class="ph2 white">Media</a>
<a href="image.jpg" class="ph2 white" target="_blank">Snapshot</a>
</div>
<div class="1 col">
<a href="javascript:logout()" class="btn ph2 black">Logout</a>
</div>
</div>
</body>
</html>
108 changes: 108 additions & 0 deletions src/hal/hisi/v1_aud.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#pragma once

#include "v1_common.h"

#define V1_AUD_CHN_NUM 2

typedef enum {
V1_AUD_BIT_8,
V1_AUD_BIT_16,
V1_AUD_BIT_24
} v1_aud_bit;

typedef enum {
V1_AUD_INTF_I2S_MASTER,
V1_AUD_INTF_I2S_SLAVE,
V1_AUD_INTF_PCM_SLAVE_STD,
V1_AUD_INTF_PCM_SLAVE_NSTD,
V1_AUD_INTF_PCM_MASTER_STD,
V1_AUD_INTF_PCM_MASTER_NSTD,
V1_AUD_INTF_END
} v1_aud_intf;

typedef struct {
// Accept industry standards from
// 8000 to 96000Hz, plus 64000Hz
int rate;
v1_aud_bit bit;
v1_aud_intf intf;
int stereoOn;
// 8-to-16 bit, expand mode
unsigned int expandOn;
unsigned int frmNum;
unsigned int packNumPerFrm;
unsigned int chnNum;
unsigned int syncRxClkOn;
} v1_aud_cnf;

typedef struct {
v1_aud_bit bit;
int stereoOn;
void *addr[2];
unsigned int phy[2];
unsigned long long timestamp;
unsigned int sequence;
unsigned int length;
unsigned int poolId[2];
} v1_aud_frm;

typedef struct {
v1_aud_frm frame;
char isValid;
char isSysBound;
} v1_aud_efrm;

typedef struct {
void *handle;

int (*fnDisableDevice)(int device);
int (*fnEnableDevice)(int device);
int (*fnSetDeviceConfig)(int device, v1_aud_cnf *config);

int (*fnDisableChannel)(int device, int channel);
int (*fnEnableChannel)(int device, int channel);

int (*fnFreeFrame)(int device, int channel, v1_aud_frm *frame, v1_aud_efrm *encFrame);
int (*fnGetFrame)(int device, int channel, v1_aud_frm *frame, v1_aud_efrm *encFrame, int millis);
} v1_aud_impl;

static int v1_aud_load(v1_aud_impl *aud_lib) {
if (!(aud_lib->handle = dlopen("libmpi.so", RTLD_LAZY | RTLD_GLOBAL)))
HAL_ERROR("v1_aud", "Failed to load library!\nError: %s\n", dlerror());

if (!(aud_lib->fnDisableDevice = (int(*)(int device))
hal_symbol_load("v1_aud", aud_lib->handle, "HI_MPI_AI_Disable")))
return EXIT_FAILURE;

if (!(aud_lib->fnEnableDevice = (int(*)(int device))
hal_symbol_load("v1_aud", aud_lib->handle, "HI_MPI_AI_Enable")))
return EXIT_FAILURE;

if (!(aud_lib->fnSetDeviceConfig = (int(*)(int device, v1_aud_cnf *config))
hal_symbol_load("v1_aud", aud_lib->handle, "HI_MPI_AI_SetPubAttr")))
return EXIT_FAILURE;

if (!(aud_lib->fnDisableChannel = (int(*)(int device, int channel))
hal_symbol_load("v1_aud", aud_lib->handle, "HI_MPI_AI_DisableChn")))
return EXIT_FAILURE;

if (!(aud_lib->fnEnableChannel = (int(*)(int device, int channel))
hal_symbol_load("v1_aud", aud_lib->handle, "HI_MPI_AI_EnableChn")))
return EXIT_FAILURE;

if (!(aud_lib->fnFreeFrame = (int(*)(int device, int channel, v1_aud_frm *frame, v1_aud_efrm *encFrame))
hal_symbol_load("v1_aud", aud_lib->handle, "HI_MPI_AI_ReleaseFrame")))
return EXIT_FAILURE;

if (!(aud_lib->fnGetFrame = (int(*)(int device, int channel, v1_aud_frm *frame, v1_aud_efrm *encFrame, int millis))
hal_symbol_load("v1_aud", aud_lib->handle, "HI_MPI_AI_GetFrame")))
return EXIT_FAILURE;

return EXIT_SUCCESS;
}

static void v1_aud_unload(v1_aud_impl *aud_lib) {
if (aud_lib->handle) dlclose(aud_lib->handle);
aud_lib->handle = NULL;
memset(aud_lib, 0, sizeof(*aud_lib));
}
Loading

0 comments on commit 4421f90

Please sign in to comment.