HLS-指令使用指南(二)

简介: HLS-指令使用指南

pragma HLS top


说明

将名称附加到函数,然后可以与 set_top 命令一起使用该名称来合成该函数以及从指定顶级调用的任何函数。 这通常用于在 C/C++ 中合成类的成员函数。在活动解决方案中指定编译指示,然后使用具有新名称的 set_top 命令。

语法

将编译指示放在 C 源代码中所需位置的边界内。

#pragma HLS top name=<string>

其中, name=,指定 set_top 命令使用的名称。

示例

函数 foo_long_name 被指定为顶级函数,并重命名为 DESIGN_TOP。在代码中放置 pragma 之后,set_top 命令仍然必须从 Tcl 命令行发出,或者从 GUI 项目设置中指定的顶层发出。

void foo_long_name () {
#pragma HLS top name=DESIGN_TOP
...
}
set_top DESIGN_TOP

函数内联


pragma HLS inline


说明

删除作为层次结构中单独实体的函数。 内联后,函数被分解到调用函数中,不再作为 RTL 中单独的层次结构出现。 在某些情况下,内联函数允许函数内的操作与周围的操作更有效地共享和优化。 内联函数不能共享。 这会增加实现 RTL 所需的面积。

INLINE 编译指示适用于它定义的范围,具体取决于它的指定方式:

  • INLINE:没有参数,pragma 意味着指定它的函数应该向上内联到任何调用函数或区域。
  • INLINE OFF:指定在其中指定的函数不应向上内联到任何调用函数或区域中。 这将禁用可能自动内联或作为区域或递归的一部分内联的特定函数的内联。
  • INLINE REGION:这将编译指示应用于区域或分配它的函数体。它向下应用,内联区域或函数的内容,但不通过层次结构递归内联。
  • INLINE RECURSIVE:这将编译指示应用于区域或分配它的函数体。它向下应用,递归地内联区域或函数的内容。

默认情况下,内联仅在函数层次结构的下一级执行,而不是在子函数上执行。但是,递归选项允许您通过层次结构的级别指定内联。

语法

将编译指示放在函数体或代码区域内的 C 源代码中。

#pragma HLS inline <region | recursive | off>

其中,

  • region:可选地指定指定区域(或包含在函数体中)的所有函数都将被内联,适用于该区域的范围。
  • recursive:默认情况下,只执行一级函数内联,指定函数内的函数不内联。 recursive 选项以递归方式内联指定函数或区域内的所有函数。
  • off:禁用函数内联以防止内联指定的函数。 例如,如果在函数中指定了递归,则此选项可以防止特定调用的函数在所有其他函数都被内联时被内联。Vivado HLS 自动内联小函数,使用带有 off 选项的 INLINE pragma 可用于防止这种自动内联。

示例

示例1

本示例内联指定区域内的所有函数,在本例中为 foo_top 的主体,但不内联这些函数内的任何低级函数。

void foo_top { a, b, c, d} { 
#pragma HLS inline region 
...

示例2

以下示例将 foo_top 主体内的所有函数内联,通过函数层次结构向下递归内联,但函数 foo_sub 未内联。 递归编译指示放在函数 foo_top 中。 禁用内联的编译指示放在函数 foo_sub中:

foo_sub (p, q) { 
#pragma HLS inline off 
int q1 = q + 10; 
foo(p1,q);// foo_3 
...
}
void foo_top { a, b, c, d} {
    #pragma HLS inline region recursive
    ...
    foo(a,b);//foo_1
    foo(a,c);//foo_2
    foo_sub(a,d);
    ...
}

INLINE 向下应用于函数 foo_top 的内容,但向上应用于调用 foo_sub 的代码。

示例3

本示例将 copy_output 函数内联到任何调用 copy_output 的函数或区域中。

void copy_output(int *out, int out_lcl[OSize * OSize], int output) {
#pragma HLS INLINE
    // Calculate each work_item's result update location
    int stride = output * OSize * OSize;
    // Work_item updates output filter/image in DDR
    writeOut: for(int itr = 0; itr < OSize * OSize; itr++) {
        #pragma HLS PIPELINE
        out[stride + itr] = out_lcl[itr];
}

pragma HLS function_instantiate


说明

FUNCTION_INSTANTIATE指令是一种优化技术,它具有维护函数层次结构的区域优势,但提供了一个额外的强大选项:对函数的特定实例执行有针对性的局部优化。 这可以简化围绕函数调用的控制逻辑,并有可能提高延迟和吞吐量。

默认情况下:

  • 函数在 RTL 中保留为单独的层次结构块。
  • 同一层次结构中的所有函数实例都使用单个 RTL 实现(块)。

FUNCTION_INSTANTIATE 编译指示用于为函数的每个实例创建唯一的 RTL 实现,允许根据函数调用对每个实例进行本地优化。 该编译指示利用了当函数被调用时函数的某些输入可能是常量值的事实,并使用它来简化周围的控制结构并生成更小更优化的功能块。

char foo_sub(char inval, char incr) { 
#pragma HLS function_instantiate variable=incr 
return inval + incr; 
} 
void foo(char inval1, char inval2, char inval3, 
char *outval1, char *outval2, char * outval3) { 
*outval1 = foo_sub(inval1, 1); 
*outval2 = foo_sub(inval2, 2); 
*outval3 = foo_sub(inval3, 3); 
}

如果没有 FUNCTION_INSTANTIATE pragma,代码将导致 foo 中函数的所有三个实例的函数 foo_sub 的单个 RTL 实现。 函数 foo_sub 的每个实例都以相同的方式实现。 这对于函数重用和减少函数的每个实例调用所需的区域来说很好,但意味着函数内部的控制逻辑必须更加复杂,以解决每次调用 foo_sub 的变化。

在上面的代码示例中,FUNCTION_INSTANTIATE 编译指示导致函数 foo_sub 的三种不同实现,每种实现都针对 incr 参数独立优化,减少了面积并提高了函数的性能。 在 FUNCTION_INSTANTIATE 优化之后,foo_sub 被有效地转换为三个独立的函数,每个函数都针对 incr 的指定值进行了优化。

语法

将编译指示放在 C 源代码中所需位置的边界内。

#pragma HLS function_instantiate variable=<variable>

其中,variable=定义了用作常量的函数参数的必需参数。

示例

示例1

在以下示例中,放置在函数 swInt) 中的 FUNCTION_INSTANTIATE 编译指示允许函数 swInt 的每个实例相对于 maxv 函数参数进行独立优化:

void swInt(unsigned int *readRefPacked, short *maxr, short *maxc, short
*maxv){
#pragma HLS function_instantiate variable=maxv
  uint2_t d2bit[MAXCOL];
  uint2_t q2bit[MAXROW];
#pragma HLS array partition variable=d2bit,q2bit cyclic factor=FACTOR
    intTo2bit<MAXCOL/16>((readRefPacked + MAXROW/16), d2bit);
    intTo2bit<MAXROW/16>(readRefPacked, q2bit);
    sw(d2bit, q2bit, maxr, maxc, maxv);
}

接口综合


pragma HLS interface


描述

在基于C 的设计中,所有输入和输出操作都是通过形式函数参数在零时间内执行的。 在 RTL 设计中,这些相同的输入和输出操作必须通过设计接口中的端口执行,并且通常使用特定的 I/O(输入输出)协议进行操作。

INTERFACE pragma 指定如何在接口综合期间从函数定义创建 RTL 端口。

RTL 实现中的端口源自:

  • 任何指定的功能级协议。
  • 函数参数。
  • 由顶级函数访问并在其作用域外定义的全局变量。

函数级协议,也称为块级 I/O 协议,提供信号来控制函数何时开始操作,并指示函数操作何时结束、空闲和准备好接受新输入。 函数级协议的实现:

由  值 ap_ctrl_none、ap_ctrl_hs 或 ap_ctrl_chain 指定。 ap_ctrl_hs 块级 I/O 协议是默认的。

与函数名称相关联。

每个函数参数都可以指定为具有自己的端口级 (I/O) 接口协议,例如有效握手 (ap_vld) 或确认握手 (ap_ack)。 为顶级函数中的每个参数创建端口级接口协议,如果函数返回一个值,则函数返回。 创建的默认 I/O 协议取决于 C 参数的类型。 在使用块级协议启动块操作后,端口级 IO 协议用于对进出块的数据进行排序。

如果访问了全局变量,但所有读写操作都是设计本地的,则在设计中创建资源。RTL 中不需要 I/O 端口。 如果预期全局变量是外部源或目标,请以与标准函数参数类似的方式指定其接口。

当 INTERFACE pragma 用于子函数时,只能使用 register 选项。子函数不支持  选项。Vivado HLS 会自动确定任何子函数使用的 I/O 协议。 您无法控制这些端口,除非指定端口是否已注册。

语法

将编译指示放在函数的边界内。

#pragma HLS interface <mode> port=<name> bundle=<string> \
register register_mode=<mode> depth=<int> offset=<string> \
clock=<string> name=<string> \
num_read_outstanding=<int> num_write_outstanding=<int> \
max_read_burst_length=<int> max_write_burst_length=<int>

其中,

  • :指定函数参数、函数使用的全局变量或块级控制协议的接口协议模式。 模式可以指定为以下之一:

image.png

  • port=:指定 INTERFACE pragma 应用的函数参数、函数返回或全局变量的名称。块级 I/O 协议(ap_ctrl_none、ap_ctrl_hs 或 ap_ctrl_chain)可以分配给函数返回值的端口。
  • bundle=:将函数参数分组到 AXI 接口端口中。 默认情况下,Vivado HLS 将所有指定为 AXI4-Lite (s_axilite) 接口的函数参数分组到单个 AXI4-Lite 端口中。 类似地,指定为 AXI4 (m_axi) 接口的所有函数参数都分组到单个 AXI4 端口中。 此选项将具有相同 bundle= 的所有接口端口显式分组到相同的 AXI 接口端口中,并将 RTL 端口命名为 指定的值。
  • register:注册信号和任何相关协议信号的可选关键字,并使信号至少持续到函数执行的最后一个周期。 此选项适用于以下接口模式:

○ ap_none ○ ap_ack ○ ap_vld ○ ap_ovld

○ ap_hs ○ ap_stable ○ axis ○ s_axilite

  • register_mode= :与 register 关键字一起使用,此选项指定寄存器是否放置在正向路径(TDATA 和 TVALID)、反向路径 (TREADY)、两条路径(TDATA、TVALID、 和 TREADY),或者如果没有任何端口信号要寄存(关闭)。 默认 register_mode 是 both。 AXI-Stream(axis)侧通道信号被认为是数据信号,只要寄存TDATA 就会寄存。
  • depth=:指定测试台要处理的最大样本数。 此设置指示 Vivado HLS 为 RTL 协同仿真创建的验证适配器中所需的 FIFO 的最大大小。虽然深度通常是一个选项,但只有m_axi 接口需要配置。
  • offset=:控制 AXI4-Lite (s_axilite) 和 AXI4 (m_axi) 接口中的地址偏移。
  • ○ 对于 s_axilite 接口, 指定寄存器映射中的地址。
    ○ 对于 m_axi 接口, 指定以下值之一:
  • direct:生成标量输入偏移端口。
  • slave:生成偏移端口并自动将其映射到 AXI4-Lite 从接口。
  • off:不生成偏移端口。
  • config_interface 命令的 -m_axi_offset 选项全局控制设计中所有 M_AXI 接口的偏移端口。
  • clock=:可选择仅为接口模式 s_axilite 指定。 这定义了用于接口的时钟信号。 默认情况下,AXI-Lite 接口时钟与系统时钟相同。 此选项用于为 AXI-Lite (s_axilite) 接口指定单独的时钟。如果捆绑选项用于将多个顶级函数参数分组到单个 AXI-Lite 接口中,则只需在捆绑成员之一上指定时钟选项。
  • num_read_outstanding=:对于 AXI4 (m_axi) 接口,此选项指定在设计停止之前可以向 AXI4 总线发出多少个读取请求,而没有响应。这意味着设计中的内部存储,大小为 FIFO:
num_read_outstanding*max_read_burst_length*word_size。

num_write_outstanding=:对于 AXI4 (m_axi) 接口,此选项指定在设计停止之前可以向 AXI4 总线发出多少次写入请求而没有响应。 这意味着设计中的内部存储,大小为 FIFO:

num_write_outstanding*max_write_burst_length*word_size

max_read_burst_length=:对于 AXI4 (m_axi) 接口,此选项指定在突发传输期间读取的最大数据值数。

max_write_burst_length=:对于 AXI4 (m_axi) 接口,此选项指定在突发传输期间写入的最大数据值数。

name=:此选项用于根据您自己的规范重命名端口。生成的 RTL 端口将使用此名称。

示例

示例1

在此示例中,两个函数参数均使用 AXI4-Stream 接口实现:

void example(int A[50], int B[50]) { 
    //Set the HLS native interface types 
    #pragma HLS INTERFACE axis port=A 
    #pragma HLS INTERFACE axis port=B 
    int i; 
    for(i = 0; i < 50; i++){ 
        B[i] = A[i] + 5; 
    } 
}

示例2

下面关闭块级 I/O 协议,并赋给函数返回值:

#pragma HLS interface ap_ctrl_none port=return

函数参数 InData 被指定为使用 ap_vld 接口,并且还指示应该寄存器输入:

#pragma HLS interface ap_vld register port=InData

这将全局变量 lookup_table 设置为 RTL 设计上的端口,具有 ap_memory 接口:

pragma HLS interface ap_memory port=lookup_table

示例3

本示例定义了顶级转置功能端口的 INTERFACE 标准。 请注意使用 bundle= 选项对信号进行分组。

// TOP LEVEL - TRANSPOSE
void transpose(int* input, int* output) {
#pragma HLS INTERFACE m_axi port=input offset=slave bundle=gmem0
#pragma HLS INTERFACE m_axi port=output offset=slave bundle=gmem1
#pragma HLS INTERFACE s_axilite port=input bundle=control
#pragma HLS INTERFACE s_axilite port=output bundle=control
#pragma HLS INTERFACE s_axilite port=return bundle=control
#pragma HLS dataflow

pragma HLS protocol


说明

protocol pragma将代码的一个区域指定为协议区域,除非代码中明确指定,否则Vivado HLS不会在其中插入时钟操作。协议区域可用于手动指定接口协议,以确保最终设计可连接到具有相同I/O协议的其他硬件块。

Vivado HLS不会在操作之间插入任何时钟,包括从函数参数读取或写入的操作,除非在代码中明确指定。因此,RTL遵循读写顺序。

可以指定时钟操作:

  • 在C语言中,使用ap_wait()语句(包括ap_utils.h)。
  • 在C++和SystemC中使用WaIT()语句(包括System.h)进行设计。

ap_wait和wait语句对C和C++设计的仿真没有影响。它们仅由Vivado HLS进行解释。

要创建C代码的区域,请执行以下操作:

  1. 将区域用大括号括起来,{},
  2. 可以选择将其命名以提供标识符。

例如,下面定义了一个名为io_section的区域:

io_section:{ 
...
}

语法

将pragma放置在区域边界内,以定义该区域的协议。

#pragma HLS protocol <floating | fixed>

其中:

  • floating:协议模式,允许协议区域外的语句与最终RTL中协议区域内的语句重叠。协议区域内的代码保持周期精确,但其他操作可能同时发生。这是默认的协议模式。
  • fixed:协议模式,确保协议区域内外的语句没有重叠。

示例

本示例将区域 io_section 定义为固定协议区域。 将编译指示放在里面的区域:

io_section:{
#pragma HLS protocol fixed
...
}

任务级流水


pragma HLS dataflow


说明

DATAFLOW pragma 支持任务级流水线,允许函数和循环在其操作中重叠,增加 RTL实现的并发性,并增加设计的整体吞吐量。

所有操作都在 C 描述中按顺序执行。 在没有任何限制资源的指令(例如 pragma HLS 分配)的情况下,Vivado HLS 寻求最小化延迟并提高并发性。 但是,数据依赖性可以限制这一点。 例如,访问数组的函数或循环必须在完成之前完成对数组的所有读/写访问。 这可以防止下一个消耗数据的函数或循环开始操作。 DATAFLOW 优化使函数或循环中的操作能够在前一个函数或循环完成其所有操作之前开始操作。

image.png

当指定 DATAFLOW pragma 时,Vivado HLS 分析顺序函数或循环之间的数据流并创建通道(基于乒乓 RAM 或 FIFO),允许消费者函数或循环在生产者函数或循环完成之前开始操作。

这允许函数或循环并行运行,从而减少延迟并提高 RTL 的吞吐量。如果未指定启动间隔(一个函数或循环开始与下一个循环之间的循环数),Vivado HLS 会尝试最小化启动间隔并在数据可用时立即开始操作。

config_dataflow 命令指定用于数据流优化的默认内存通道和 FIFO 深度。为了使 DATAFLOW 优化起作用,数据必须从一个任务流向下一个任务。 以下编码风格会阻止 Vivado HLS 执行 DATAFLOW 优化:

  • 单一生产者-消费者违规。
  • 绕过任务。
  • 任务之间的反馈。
  • 有条件地执行任务。
  • 具有多个退出条件的循环。

如果存在这些编码风格中的任何一种,Vivado HLS 会发出一条消息并且不执行 DATAFLOW 优化。最后,DATAFLOW 优化没有分层实现。 如果子函数或循环包含可能受益于 DATAFLOW 优化的其他任务,则必须将优化应用于循环、子函数或内联子函数。

语法

将编译指示放在区域、函数或循环的边界内的 C 源代码中。

#pragma HLS dataflow

示例

在循环 wr_loop_j 中指定 DATAFLOW 优化。

wr_loop_j: for (int j = 0; j < TILE_PER_ROW; ++j) {
  #pragma HLS DATAFLOW
  wr_buf_loop_m: for (int m = 0; m < TILE_HEIGHT; ++m) {
    wr_buf_loop_n: for (int n = 0; n < TILE_WIDTH; ++n) {
      #pragma HLS PIPELINE
      // should burst TILE_WIDTH in WORD beat
      outFifo >> tile[m][n];
    }
  }
  wr_loop_m: for (int m = 0; m < TILE_HEIGHT; ++m) {
    wr_loop_n: for (int n = 0; n < TILE_WIDTH; ++n) {
      #pragma HLS PIPELINE
      outx[TILE_HEIGHT*TILE_PER_ROW*TILE_WIDTH*i
      +TILE_PER_ROW*TILE_WIDTH*m+TILE_WIDTH*j+n] = tile[m][n];
    }
  }
}

pragma HLS stream


说明

  • 默认情况下,数组变量实现为RAM。
  • 顶层函数数组参数实现为RAM接口端口。
  • 通用阵列作为RAM实现读写访问。
  • 在涉及 DATAFLOW 优化的子函数中,实现了数组参数使用 RAM 乒乓缓冲通道。
  • 基于循环的 DATAFLOW 优化中,涉及的数组作为 RAM 实现乒乓缓冲通道。

如果存储在阵列中的数据以顺序方式使用或生成,则更有效的通信机制是使用 STREAM pragma 指定的流数据,其中使用 FIFO 而不是 RAM。当顶层函数的参数指定为 INTERFACE 类型 ap_fifo 时,该数组将自动实现为流。

语法

将编译指示放在 C 源代码中所需位置的边界内。

#pragma HLS stream variable=<variable> depth=<int> dim=<int> off

其中:

  • variable=:指定要实现为流接口的数组的名称。
  • depth=:仅与DATAFLOW 通道中的数据流相关。 默认情况下,RTL 中实现的 FIFO 深度与 C 代码中指定的数组大小相同。 此选项可让您修改 FIFO 的大小并指定不同的深度。当数组在 DATAFLOW 区域中实现时,通常使用 depth= 选项来减小 FIFO 的大小。 例如,在 DATAFLOW 区域中,当所有循环和函数都以 II=1 的速率处理数据时,不需要大的 FIFO,因为每个时钟周期都会产生和消耗数据。 在这种情况下,可以使用 depth= 选项将 FIFO 大小减少到 1,以显着减少 RTL 设计的面积。config_dataflow -depth 命令提供了流式传输 DATAFLOW 区域中的所有数组的能力。 此处指定的 depth= 选项会覆盖已分配变量的 config_dataflow 命令。
  • dim=:指定要流式传输的数组的维度。 默认值为维度 1。对于具有 N 维的数组,指定为从 0 到 N 的整数。
  • off:禁用流数据。 仅与数据流通道中的数组流相关。
  • config_dataflow -default_channel fifo 命令全局表示设计中所有阵列上的 STREAM 编译指示。 此处指定的 off 选项会覆盖分配变量的 config_dataflow 命令,并恢复使用基于 RAM 乒乓缓冲区的通道的默认值。

示例

示例1

以下示例指定要流式传输的数组 A[10],并作为 FIFO 实现:

#pragma HLS STREAM variable=A

示例2

在此示例中,数组 B 设置为 FIFO 深度为 12 的流数据:

#pragma HLS STREAM variable=B depth=12

示例3

阵列 C 已禁用流式传输。

在本例中假定由 config_dataflow 启用:

#pragma HLS STREAM variable=C off



目录
相关文章
|
存储 Cloud Native Linux
音视频 FFmpeg如何查询命令帮助文档
音视频 FFmpeg如何查询命令帮助文档
|
3月前
|
缓存 视频直播 Linux
FFmpeg开发笔记(四十三)使用SRS开启SRT协议的视频直播服务
《FFmpeg开发实战》书中介绍了轻量级流媒体服务器MediaMTX,适合测试但不适用于生产环境。SRS是一款国产开源服务器,支持RTMP、SRT等协议,适合生产使用。要启用SRS的SRT推流,需配置`srt.conf`,开启SRT服务并配置端口。在确保FFmpeg集成libsrt后,拉流则使用类似但带有`m=request`的地址。在Windows上,同样需要集成libsrt的FFmpeg来使用ffplay拉流。SRS的日志确认了推拉流的成功。书中提供更深入的FFmpeg开发知识。
143 2
FFmpeg开发笔记(四十三)使用SRS开启SRT协议的视频直播服务
|
3月前
|
视频直播 Linux Windows
FFmpeg开发笔记(四十二)使用ZLMediaKit开启SRT视频直播服务
《FFmpeg开发实战》书中介绍了使用MediaMTX测试RTSP/RTMP,但该工具简单,不适合生产环境。ZLMediaKit,一个支持RTSP/RTMP/SRT的国产流媒体服务器,是更好的选择。要通过ZLMediaKit和FFmpeg实现SRT推流,需确保FFmpeg已集成libsrt。ZLMediaKit默认配置文件中,SRT监听9000端口。日志显示推流和拉流成功。ZLMediaKit支持多种音视频编码,如H264、AAC等。要了解更多FFmpeg开发信息,可参考该书。
111 0
FFmpeg开发笔记(四十二)使用ZLMediaKit开启SRT视频直播服务
|
5月前
|
数据安全/隐私保护 索引 Python
详尽分享视频相关的hls协议、VLC播放器、m3u文件的播放
详尽分享视频相关的hls协议、VLC播放器、m3u文件的播放
103 0
|
6月前
|
C# 数据安全/隐私保护 开发者
Windows平台RTMP推送|轻量级RTSP服务录像模块如何支持中文路径?
Windows平台RTMP推送|轻量级RTSP服务录像模块如何支持中文路径?
|
Web App开发 编解码 前端开发
2023年WEB内嵌VLC直接播放RTSP视频流,无需服务器转码,支持硬件解码及高版本Chrome
2015年之前还可以用VLC原生播放器在Chrome、Firefox等浏览器中直接播放,延迟比较低,效果也还不错。可惜好景不长,从 2015年Chrome、Firefox等浏览器取消了对 NPAPI插件的支持,海康威视官方提供的 web3.0开发包也只能在低版本浏览器播放。
460 0
|
容器
flv拉流在项目中如何使用(二)
这里主要是我们不能使用video容器自带的暂停和播放按钮了,我们要隐藏原来的自己实现暂停和播放。暂停和播放说白了就是断流和重新拉流
149 1
|
编解码 开发工具 C#
Windows平台RTMP/RTSP直播推送模块设计和使用说明
好多开发者一直反馈,Windows平台,做个推屏或者推摄像头,推RTMP或者RTSP出去,不知道哪些功能是必须的,哪些设计是可有可无的,还有就是,不知道如何选技术方案,以下是基于我们设计的Windows平台RTSP、RTMP直播推送模块,设计和使用说明,供大家参考。
467 0
|
数据处理 Android开发 开发者
Android平台实现mp4文件实时推送RTMP|轻量级RTSP服务|GB28181平台
好多开发者有这样的诉求,想把本地录制的MP4文件,以实时流数据的形式,推送到RTMP服务器,注入轻量级RTSP服务,或者对接到GB28181平台,这块前几年我们就有对接。
116 0
|
移动开发 前端开发 网络协议
flv拉流在项目中如何使用(一)
最近做的项目里面用到通过前端flv.js拉流播放直播视频(实时视频);这里给大家介绍一下流程,首先是前端发送请求后端给返回一个直播流指定地址,然后前端把这个地址通过flv处理放到video容器中进行播放;
403 0