Merge branch 'master' of ssh://git.swordlost.top:222/SikongJueluo/FPGA_WebLab
This commit is contained in:
commit
04b136117d
|
@ -145,6 +145,8 @@ try
|
||||||
// 添加 HTTP 视频流服务
|
// 添加 HTTP 视频流服务
|
||||||
builder.Services.AddSingleton<HttpVideoStreamService>();
|
builder.Services.AddSingleton<HttpVideoStreamService>();
|
||||||
builder.Services.AddHostedService(provider => provider.GetRequiredService<HttpVideoStreamService>());
|
builder.Services.AddHostedService(provider => provider.GetRequiredService<HttpVideoStreamService>());
|
||||||
|
builder.Services.AddSingleton<HttpHdmiVideoStreamService>();
|
||||||
|
builder.Services.AddHostedService(provider => provider.GetRequiredService<HttpHdmiVideoStreamService>());
|
||||||
|
|
||||||
// Application Settings
|
// Application Settings
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using server.Services;
|
||||||
|
using Database;
|
||||||
|
|
||||||
|
namespace server.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
public class HdmiVideoStreamController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly HttpHdmiVideoStreamService _videoStreamService;
|
||||||
|
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public HdmiVideoStreamController(HttpHdmiVideoStreamService videoStreamService)
|
||||||
|
{
|
||||||
|
_videoStreamService = videoStreamService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理员获取所有板子的 endpoints
|
||||||
|
[HttpGet("AllEndpoints")]
|
||||||
|
[Authorize("Admin")]
|
||||||
|
public ActionResult<List<HdmiVideoStreamEndpoint>> GetAllEndpoints()
|
||||||
|
{
|
||||||
|
var endpoints = _videoStreamService.GetAllVideoEndpoints();
|
||||||
|
if (endpoints == null)
|
||||||
|
return NotFound("No boards found.");
|
||||||
|
return Ok(endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户获取自己板子的 endpoint
|
||||||
|
[HttpGet("MyEndpoint")]
|
||||||
|
[Authorize]
|
||||||
|
public ActionResult<HdmiVideoStreamEndpoint> GetMyEndpoint()
|
||||||
|
{
|
||||||
|
var userName = User.FindFirstValue(ClaimTypes.Name);
|
||||||
|
if (string.IsNullOrEmpty(userName))
|
||||||
|
return Unauthorized("User name not found in claims.");
|
||||||
|
|
||||||
|
var db = new AppDataConnection();
|
||||||
|
if (db == null)
|
||||||
|
return NotFound("Database connection failed.");
|
||||||
|
|
||||||
|
var userRet = db.GetUserByName(userName);
|
||||||
|
if (!userRet.IsSuccessful || !userRet.Value.HasValue)
|
||||||
|
return NotFound("User not found.");
|
||||||
|
|
||||||
|
var user = userRet.Value.Value;
|
||||||
|
var boardId = user.BoardID;
|
||||||
|
if (boardId == Guid.Empty)
|
||||||
|
return NotFound("No board bound to this user.");
|
||||||
|
|
||||||
|
var boardRet = db.GetBoardByID(boardId);
|
||||||
|
if (!boardRet.IsSuccessful || !boardRet.Value.HasValue)
|
||||||
|
return NotFound("Board not found.");
|
||||||
|
|
||||||
|
var endpoint = _videoStreamService.GetVideoEndpoint(boardId.ToString());
|
||||||
|
return Ok(endpoint);
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,14 +32,16 @@ class HdmiIn
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="address">HDMI输入设备IP地址</param>
|
/// <param name="address">HDMI输入设备IP地址</param>
|
||||||
/// <param name="port">HDMI输入设备端口</param>
|
/// <param name="port">HDMI输入设备端口</param>
|
||||||
|
/// <param name="taskID">任务ID</param>
|
||||||
/// <param name="timeout">超时时间(毫秒)</param>
|
/// <param name="timeout">超时时间(毫秒)</param>
|
||||||
public HdmiIn(string address, int port, int timeout = 500)
|
public HdmiIn(string address, int port, int taskID, int timeout = 500)
|
||||||
{
|
{
|
||||||
if (timeout < 0)
|
if (timeout < 0)
|
||||||
throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
|
throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.ep = new IPEndPoint(IPAddress.Parse(address), port);
|
this.ep = new IPEndPoint(IPAddress.Parse(address), port);
|
||||||
|
this.taskID = taskID;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
using System.Net;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using Peripherals.HdmiInClient;
|
||||||
|
|
||||||
|
namespace server.Services;
|
||||||
|
|
||||||
|
public class HdmiVideoStreamEndpoint
|
||||||
|
{
|
||||||
|
public string BoardId { get; set; } = "";
|
||||||
|
public string MjpegUrl { get; set; } = "";
|
||||||
|
public string VideoUrl { get; set; } = "";
|
||||||
|
public string SnapshotUrl { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HttpHdmiVideoStreamService : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
private HttpListener? _httpListener;
|
||||||
|
private readonly int _serverPort = 4322;
|
||||||
|
private readonly ConcurrentDictionary<string, HdmiIn> _hdmiInDict = new();
|
||||||
|
private bool _isEnabled = true;
|
||||||
|
|
||||||
|
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_httpListener = new HttpListener();
|
||||||
|
_httpListener.Prefixes.Add($"http://*:{_serverPort}/");
|
||||||
|
_httpListener.Start();
|
||||||
|
logger.Info($"HDMI Video Stream Service started on port {_serverPort}");
|
||||||
|
|
||||||
|
await base.StartAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
HttpListenerContext? context = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
context = await _httpListener.GetContextAsync();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// Listener closed, exit loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (HttpListenerException)
|
||||||
|
{
|
||||||
|
// Listener closed, exit loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "Error in GetContextAsync");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (context != null)
|
||||||
|
_ = HandleRequestAsync(context, stoppingToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_httpListener?.Close();
|
||||||
|
logger.Info("HDMI Video Stream Service stopped.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
logger.Info("Stopping HDMI Video Stream Service...");
|
||||||
|
_isEnabled = false;
|
||||||
|
_httpListener?.Close(); // 立即关闭监听器,唤醒阻塞
|
||||||
|
await base.StopAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取/创建 HdmiIn 实例
|
||||||
|
private HdmiIn? GetOrCreateHdmiIn(string boardId)
|
||||||
|
{
|
||||||
|
if (_hdmiInDict.TryGetValue(boardId, out var hdmiIn))
|
||||||
|
return hdmiIn;
|
||||||
|
|
||||||
|
var db = new Database.AppDataConnection();
|
||||||
|
if (db == null)
|
||||||
|
{
|
||||||
|
logger.Error("Failed to create HdmiIn instance");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var boardRet = db.GetBoardByID(Guid.Parse(boardId));
|
||||||
|
if (!boardRet.IsSuccessful || !boardRet.Value.HasValue)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to get board with ID {boardId}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var board = boardRet.Value.Value;
|
||||||
|
|
||||||
|
hdmiIn = new HdmiIn(board.IpAddr, board.Port, 0); // taskID 可根据实际需求调整
|
||||||
|
_hdmiInDict[boardId] = hdmiIn;
|
||||||
|
return hdmiIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleRequestAsync(HttpListenerContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var path = context.Request.Url?.AbsolutePath ?? "/";
|
||||||
|
var boardId = context.Request.QueryString["boardId"];
|
||||||
|
if (string.IsNullOrEmpty(boardId))
|
||||||
|
{
|
||||||
|
await SendErrorAsync(context.Response, "Missing boardId");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hdmiIn = GetOrCreateHdmiIn(boardId);
|
||||||
|
if (hdmiIn == null)
|
||||||
|
{
|
||||||
|
await SendErrorAsync(context.Response, "Invalid boardId or board not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path == "/snapshot")
|
||||||
|
{
|
||||||
|
await HandleSnapshotRequestAsync(context.Response, hdmiIn, cancellationToken);
|
||||||
|
}
|
||||||
|
else if (path == "/mjpeg")
|
||||||
|
{
|
||||||
|
await HandleMjpegStreamAsync(context.Response, hdmiIn, cancellationToken);
|
||||||
|
}
|
||||||
|
else if (path == "/video")
|
||||||
|
{
|
||||||
|
await SendVideoHtmlPageAsync(context.Response, boardId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await SendIndexHtmlPageAsync(context.Response, boardId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleSnapshotRequestAsync(HttpListenerResponse response, HdmiIn hdmiIn, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var frameResult = await hdmiIn.ReadFrame();
|
||||||
|
if (frameResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
response.ContentType = "image/jpeg";
|
||||||
|
await response.OutputStream.WriteAsync(frameResult.Value, 0, frameResult.Value.Length, cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response.StatusCode = 500;
|
||||||
|
await response.OutputStream.WriteAsync(System.Text.Encoding.UTF8.GetBytes("Failed to get snapshot"));
|
||||||
|
}
|
||||||
|
response.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleMjpegStreamAsync(HttpListenerResponse response, HdmiIn hdmiIn, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
response.ContentType = "multipart/x-mixed-replace; boundary=--frame";
|
||||||
|
while (!cancellationToken.IsCancellationRequested && _isEnabled)
|
||||||
|
{
|
||||||
|
var frameResult = await hdmiIn.ReadFrame();
|
||||||
|
if (frameResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
var header = $"--frame\r\nContent-Type: image/jpeg\r\nContent-Length: {frameResult.Value.Length}\r\n\r\n";
|
||||||
|
await response.OutputStream.WriteAsync(System.Text.Encoding.ASCII.GetBytes(header));
|
||||||
|
await response.OutputStream.WriteAsync(frameResult.Value, 0, frameResult.Value.Length, cancellationToken);
|
||||||
|
await response.OutputStream.WriteAsync(System.Text.Encoding.ASCII.GetBytes("\r\n"));
|
||||||
|
}
|
||||||
|
await Task.Delay(33, cancellationToken); // ~30fps
|
||||||
|
}
|
||||||
|
response.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SendVideoHtmlPageAsync(HttpListenerResponse response, string boardId)
|
||||||
|
{
|
||||||
|
string html = $@"<html><body>
|
||||||
|
<h1>HDMI Video Stream for Board {boardId}</h1>
|
||||||
|
<img src='/mjpeg?boardId={boardId}' />
|
||||||
|
</body></html>";
|
||||||
|
response.ContentType = "text/html";
|
||||||
|
await response.OutputStream.WriteAsync(System.Text.Encoding.UTF8.GetBytes(html));
|
||||||
|
response.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SendIndexHtmlPageAsync(HttpListenerResponse response, string boardId)
|
||||||
|
{
|
||||||
|
string html = $@"<html><body>
|
||||||
|
<h1>Welcome to HDMI Video Stream Service</h1>
|
||||||
|
<a href='/video?boardId={boardId}'>View Video Stream for Board {boardId}</a>
|
||||||
|
</body></html>";
|
||||||
|
response.ContentType = "text/html";
|
||||||
|
await response.OutputStream.WriteAsync(System.Text.Encoding.UTF8.GetBytes(html));
|
||||||
|
response.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SendErrorAsync(HttpListenerResponse response, string message)
|
||||||
|
{
|
||||||
|
response.StatusCode = 400;
|
||||||
|
await response.OutputStream.WriteAsync(System.Text.Encoding.UTF8.GetBytes(message));
|
||||||
|
response.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HdmiVideoStreamEndpoint>? GetAllVideoEndpoints()
|
||||||
|
{
|
||||||
|
var db = new Database.AppDataConnection();
|
||||||
|
var boards = db?.GetAllBoard();
|
||||||
|
if (boards == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var endpoints = new List<HdmiVideoStreamEndpoint>();
|
||||||
|
foreach (var board in boards)
|
||||||
|
{
|
||||||
|
endpoints.Add(new HdmiVideoStreamEndpoint
|
||||||
|
{
|
||||||
|
BoardId = board.ID.ToString(),
|
||||||
|
MjpegUrl = $"http://{Global.localhost}:{_serverPort}/mjpeg?boardId={board.ID}",
|
||||||
|
VideoUrl = $"http://{Global.localhost}:{_serverPort}/video?boardId={board.ID}",
|
||||||
|
SnapshotUrl = $"http://{Global.localhost}:{_serverPort}/snapshot?boardId={board.ID}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HdmiVideoStreamEndpoint GetVideoEndpoint(string boardId)
|
||||||
|
{
|
||||||
|
return new HdmiVideoStreamEndpoint
|
||||||
|
{
|
||||||
|
BoardId = boardId,
|
||||||
|
MjpegUrl = $"http://{Global.localhost}:{_serverPort}/mjpeg?boardId={boardId}",
|
||||||
|
VideoUrl = $"http://{Global.localhost}:{_serverPort}/video?boardId={boardId}",
|
||||||
|
SnapshotUrl = $"http://{Global.localhost}:{_serverPort}/snapshot?boardId={boardId}"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
165
src/APIClient.ts
165
src/APIClient.ts
|
@ -2944,6 +2944,123 @@ export class ExamClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class HdmiVideoStreamClient {
|
||||||
|
protected instance: AxiosInstance;
|
||||||
|
protected baseUrl: string;
|
||||||
|
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(baseUrl?: string, instance?: AxiosInstance) {
|
||||||
|
|
||||||
|
this.instance = instance || axios.create();
|
||||||
|
|
||||||
|
this.baseUrl = baseUrl ?? "http://127.0.0.1:5000";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllEndpoints( cancelToken?: CancelToken): Promise<HdmiVideoStreamEndpoint[]> {
|
||||||
|
let url_ = this.baseUrl + "/api/HdmiVideoStream/AllEndpoints";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: AxiosRequestConfig = {
|
||||||
|
method: "GET",
|
||||||
|
url: url_,
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
},
|
||||||
|
cancelToken
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.instance.request(options_).catch((_error: any) => {
|
||||||
|
if (isAxiosError(_error) && _error.response) {
|
||||||
|
return _error.response;
|
||||||
|
} else {
|
||||||
|
throw _error;
|
||||||
|
}
|
||||||
|
}).then((_response: AxiosResponse) => {
|
||||||
|
return this.processGetAllEndpoints(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processGetAllEndpoints(response: AxiosResponse): Promise<HdmiVideoStreamEndpoint[]> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {};
|
||||||
|
if (response.headers && typeof response.headers === "object") {
|
||||||
|
for (const k in response.headers) {
|
||||||
|
if (response.headers.hasOwnProperty(k)) {
|
||||||
|
_headers[k] = response.headers[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status === 200) {
|
||||||
|
const _responseText = response.data;
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText;
|
||||||
|
if (Array.isArray(resultData200)) {
|
||||||
|
result200 = [] as any;
|
||||||
|
for (let item of resultData200)
|
||||||
|
result200!.push(HdmiVideoStreamEndpoint.fromJS(item));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result200 = <any>null;
|
||||||
|
}
|
||||||
|
return Promise.resolve<HdmiVideoStreamEndpoint[]>(result200);
|
||||||
|
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
const _responseText = response.data;
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
}
|
||||||
|
return Promise.resolve<HdmiVideoStreamEndpoint[]>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMyEndpoint( cancelToken?: CancelToken): Promise<HdmiVideoStreamEndpoint> {
|
||||||
|
let url_ = this.baseUrl + "/api/HdmiVideoStream/MyEndpoint";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: AxiosRequestConfig = {
|
||||||
|
method: "GET",
|
||||||
|
url: url_,
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
},
|
||||||
|
cancelToken
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.instance.request(options_).catch((_error: any) => {
|
||||||
|
if (isAxiosError(_error) && _error.response) {
|
||||||
|
return _error.response;
|
||||||
|
} else {
|
||||||
|
throw _error;
|
||||||
|
}
|
||||||
|
}).then((_response: AxiosResponse) => {
|
||||||
|
return this.processGetMyEndpoint(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processGetMyEndpoint(response: AxiosResponse): Promise<HdmiVideoStreamEndpoint> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {};
|
||||||
|
if (response.headers && typeof response.headers === "object") {
|
||||||
|
for (const k in response.headers) {
|
||||||
|
if (response.headers.hasOwnProperty(k)) {
|
||||||
|
_headers[k] = response.headers[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status === 200) {
|
||||||
|
const _responseText = response.data;
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText;
|
||||||
|
result200 = HdmiVideoStreamEndpoint.fromJS(resultData200);
|
||||||
|
return Promise.resolve<HdmiVideoStreamEndpoint>(result200);
|
||||||
|
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
const _responseText = response.data;
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
}
|
||||||
|
return Promise.resolve<HdmiVideoStreamEndpoint>(null as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class JtagClient {
|
export class JtagClient {
|
||||||
protected instance: AxiosInstance;
|
protected instance: AxiosInstance;
|
||||||
protected baseUrl: string;
|
protected baseUrl: string;
|
||||||
|
@ -8019,6 +8136,54 @@ export interface ICreateExamRequest {
|
||||||
isVisibleToUsers: boolean;
|
isVisibleToUsers: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class HdmiVideoStreamEndpoint implements IHdmiVideoStreamEndpoint {
|
||||||
|
boardId!: string;
|
||||||
|
mjpegUrl!: string;
|
||||||
|
videoUrl!: string;
|
||||||
|
snapshotUrl!: string;
|
||||||
|
|
||||||
|
constructor(data?: IHdmiVideoStreamEndpoint) {
|
||||||
|
if (data) {
|
||||||
|
for (var property in data) {
|
||||||
|
if (data.hasOwnProperty(property))
|
||||||
|
(<any>this)[property] = (<any>data)[property];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_data?: any) {
|
||||||
|
if (_data) {
|
||||||
|
this.boardId = _data["boardId"];
|
||||||
|
this.mjpegUrl = _data["mjpegUrl"];
|
||||||
|
this.videoUrl = _data["videoUrl"];
|
||||||
|
this.snapshotUrl = _data["snapshotUrl"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJS(data: any): HdmiVideoStreamEndpoint {
|
||||||
|
data = typeof data === 'object' ? data : {};
|
||||||
|
let result = new HdmiVideoStreamEndpoint();
|
||||||
|
result.init(data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(data?: any) {
|
||||||
|
data = typeof data === 'object' ? data : {};
|
||||||
|
data["boardId"] = this.boardId;
|
||||||
|
data["mjpegUrl"] = this.mjpegUrl;
|
||||||
|
data["videoUrl"] = this.videoUrl;
|
||||||
|
data["snapshotUrl"] = this.snapshotUrl;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHdmiVideoStreamEndpoint {
|
||||||
|
boardId: string;
|
||||||
|
mjpegUrl: string;
|
||||||
|
videoUrl: string;
|
||||||
|
snapshotUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** 逻辑分析仪运行状态枚举 */
|
/** 逻辑分析仪运行状态枚举 */
|
||||||
export enum CaptureStatus {
|
export enum CaptureStatus {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|
Loading…
Reference in New Issue