【FFmpeg】调用ffmpeg库进行RTMP推流和拉流
【FFmpeg】调用ffmpeg库实现RTMP推流
- 1.FFmpeg编译
- 2.RTMP服务器搭建
- 3.调用FFmpeg库实现RTMP推流和拉流
- 3.1 基本框架
- 3.2 实现代码
- 3.3 测试
- 3.3.1 推流
- 3.3.2 拉流
参考:雷霄骅博士, 调用ffmpeg库进行RTMP推流
====== 示例工程 ======
【FFmpeg】调用FFmpeg库实现264软编
【FFmpeg】调用FFmpeg库实现264软解
1.FFmpeg编译
参考: FFmpeg在Windows下的编译
本文使用FFmpeg-7.0版本
2.RTMP服务器搭建
将本机配置成为服务器,实现本地的推流和拉流操作。RTMP服务器的搭建参考:RTMP服务器的搭建
RTMP是Adobe提出的一种应用层的协议,用于解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题传输,传输媒体的格式为FLV,因此本文推流的格式是flv格式。flv文件可以使用ffmpeg命令行,从yuv文件转换而来。
3.调用FFmpeg库实现RTMP推流和拉流
3.1 基本框架
在实现时,对参考博客中的部分函数进行了修改
- 不再使用av_register_all()函数对编解码器进行初始化
- 增加av_log_set_level(AV_LOG_TRACE)增加日志输出信息
- 使用本机IP127.0.0.1
- 修改部分参数的调用,因为部分变量存储的位置发生了变化
- 修改部分函数的调用,因为使用的FFmpeg版本不同
- 将推流和拉流的部分合并,用一套代码实现
在编码过程当中,主要使用了如下的函数
函数名 | 作用 |
---|---|
av_log_set_level | 配置输出日志级别 (AV_LOG_TRACE最详细) |
avformat_network_init | 初始化网络模块 |
avformat_open_input | 打开输入文件,并且将文件信息赋值给AVFormatContext保存 |
avformat_find_stream_info | 根据AVFormatContext查找流信息 |
av_dump_format | 将AVFormatContext中的媒体文件的信息进行格式化输出 |
avformat_alloc_output_context2 | 根据format_name(或filename或oformat)创建输出文件的AVFormatContext信息 |
avformat_new_stream | 根据AVFormatContext和AVCodecContext创建新的流 |
avcodec_parameters_copy | 拷贝AVCodecParameters |
avio_open | 根据url进行AVIOContext的创建与初始化(这个url在推流时就是服务器地址) |
avformat_write_header | 为流分配priv_data并且将流的头信息写入到输出媒体文件 |
av_read_frame | 根据AVFormatContext所提供的的信息读取一帧,存入AVPacket |
av_interleaved_write_frame | 以交错的方式将帧送入到媒体文件中 |
av_packet_unref | 释放AVPacket |
av_write_trailer | 将流的尾部写入到输出的媒体文件中,并且释放文件中的priv_data |
avformat_close_input | 释放AVFormatContext |
从使用的函数来看,主要的操作流程和数据流走向大约为:
- 初始化网络模块,为RTMP传输进行准备(avformat_network_init)
- 打开输入文件,创建输入文件结构体并且读取输入文件信息(avformat_open_input),此时也会创建输入的流信息结构体
- 根据输入文件查找流信息,赋值给流信息结构体(avformat_find_stream_info)
- 打印输入文件信息(av_dump_format)
- 根据输出文件信息来创建输出文件结构体(avformat_alloc_output_context2)
- 创建输出流(avformat_new_stream)
- 将输入流的参数拷贝给输出给输出流(avcodec_parameters_copy)
- 打印输出文件信息(av_dump_format)
- 打开输出口,准备推流(avio_open)
- 写入流的头部信息(avformat_write_header)
- 读取一帧信息,存储到AVPacket中(av_read_frame)
- 处理时间戳;PTS是播放时间戳,告诉播放器播放这一帧的时间;DTS是解码时间戳,告诉播放器解码这一帧的时间;PTS通常是按照递增顺序排列的。这里雷博士认为延时很重要,如果不对前后帧推流的时间进行控制,帧会瞬时推送到服务器端,会出现服务器无法正常接收帧的情况
- 将帧推流(av_interleaved_write_frame)
- 写入流的尾部信息(av_write_trailer)
- 释放结构体信息(av_packet_unref、av_write_trailer和avformat_close_input)
3.2 实现代码
在调试时,发现如果AVPacket这里定义如果是指针的话,会出现av_read_frame第二帧读取失败的情况,这里有待进一步学习。
在代码中,利用bool is_sender来控制是发送还是接收,发送和接收都使用同一套代码,只是在时间戳部分有所区别,即发送端需要计算而接收端不需要使用。不过这里的in_url和out_url还是固定的,实际使用时得重新配置。
#pragma warning(disable : 4996)#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "streamer.h"#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
#include "libavutil/time.h"
#include "libavutil/timestamp.h"
#include "libavutil/mathematics.h"
#include "libavutil/log.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
#ifdef __cplusplus
};
#endif
#endifint streamer_internal(const char* in_url, const char* out_url, bool is_sender)
{// set log level// av_log_set_level(AV_LOG_TRACE);AVOutputFormat* av_out_fmt = NULL;AVFormatContext* av_in_fmt_ctx = NULL;AVFormatContext* av_out_fmt_ctx = NULL;AVPacket av_pkt;const char* in_filename = in_url;const char* out_filename = out_url;int ret = 0;int i = 0;int video_idx = -1;int frame_idx = 0;int64_t start_time = 0;// bool b_sender = 0;//in_filename = "enc_in_all.flv"; // input flv file//out_filename = "rtmp://127.0.0.1:1935/live/stream"; // output url//in_filename = "rtmp://127.0.0.1:1935/live/stream"; // input flv file//out_filename = "receive.flv"; // output url// av_register_all(); // 新版本ffmpeg不再使用// init networkavformat_network_init();if ((ret = avformat_open_input(&av_in_fmt_ctx, in_filename, 0, 0)) < 0) {fprintf(stderr, "Could not open input file.");goto end;}if ((ret = avformat_find_stream_info(av_in_fmt_ctx, 0)) < 0) {fprintf(stderr, "Failed to retrive input stream information");goto end;}for (i = 0; i < av_in_fmt_ctx->nb_streams; i++) {if (av_in_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_idx = i;break;}}// 将AVFormatContext结构体中媒体文件的信息进行格式化输出av_dump_format(av_in_fmt_ctx, 0, in_filename, 0);// Output// av_out_fmt_ctx是函数执行成功之后的上下文信息结构体// "flv"是输出格式// out_filename是输出文件ret = avformat_alloc_output_context2(&av_out_fmt_ctx, NULL, NULL, out_filename); // RTMP// ret = avformat_alloc_output_context2(&av_out_fmt_ctx, NULL, "flv", out_filename); // RTMP// avformat_alloc_output_context2(&av_out_fmt_ctx, NULL, "mpegts", out_filename); // UDPif (ret < 0) {fprintf(stderr, "Could not create output context, error code:%d\n", ret);//ret = AVERROR_UNKNOWN;goto end;}// av_out_fmt_ctx->oformat;for (i = 0; i < av_in_fmt_ctx->nb_streams; i++) {AVStream* in_stream = av_in_fmt_ctx->streams[i];// 为av_out_fmt_ctx创建一个新的流,第二个参数video_codec没有被使用AVStream* out_stream = avformat_new_stream(av_out_fmt_ctx, av_in_fmt_ctx->video_codec);//AVStream* out_stream = avformat_new_stream(av_out_fmt_ctx, in_stream->codec->codec);if (!out_stream) {fprintf(stderr, "Failed to allocating output stream\n");ret = AVERROR_UNKNOWN;goto end;}// Copy the setting of AVCodecContext// ret = avcodec_copy_context(out_stream->codecpar, in_stream->codecpar);ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);if (ret < 0) {fprintf(stderr, "Failed to copy context from input to output stream codec context\n");goto end;}out_stream->codecpar->codec_tag = 0;if (av_out_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {// out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;// out_stream->event_flags |= AV_CODEC_FLAG_GLOBAL_HEADER;}}// Dump format// 将AVFormatContext结构体中媒体文件的信息进行格式化输出av_dump_format(av_out_fmt_ctx, 0, out_filename, 1);// Open output URL if (!(av_out_fmt_ctx->oformat->flags & AVFMT_NOFILE)) {// 打开文件ret = avio_open(&av_out_fmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);if (ret < 0) {fprintf(stderr, "Could not open output URL '%s'", out_filename);goto end;}}// Write file headerret = avformat_write_header(av_out_fmt_ctx, NULL);if (ret < 0) {fprintf(stderr, "Error occured when opening output URL\n");goto end;}if (is_sender) {start_time = av_gettime();}while(1) {AVStream* in_stream;AVStream* out_stream;// get an AVPacket// 这里如果使用av_pkt指针的话,第二帧时就会出错ret = av_read_frame(av_in_fmt_ctx, &av_pkt);if (ret < 0) {break;}// write ptsif (av_pkt.pts == AV_NOPTS_VALUE && is_sender) {// write ptsAVRational time_base1 = av_in_fmt_ctx->streams[video_idx]->time_base;// Duration between 2 frames (us)int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(av_in_fmt_ctx->streams[video_idx]->r_frame_rate);// parameters// pts是播放时间戳,告诉播放器什么时候播放这一帧视频,PTS通常是按照递增顺序排列的,以保证正确的时间顺序和播放同步// dts是解码时间戳,告诉播放器什么时候解码这一帧视频av_pkt.pts = (double)(frame_idx * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);av_pkt.dts = av_pkt.pts;av_pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);}// important: delayif (av_pkt.stream_index == video_idx && is_sender) {AVRational time_base = av_in_fmt_ctx->streams[video_idx]->time_base;AVRational time_base_q = { 1, AV_TIME_BASE };int64_t pts_time = av_rescale_q(av_pkt.dts, time_base, time_base_q);int64_t now_time = av_gettime() - start_time;if (pts_time > now_time) {av_usleep(pts_time - now_time);}// av_usleep(50);}in_stream = av_in_fmt_ctx->streams[av_pkt.stream_index];out_stream = av_out_fmt_ctx->streams[av_pkt.stream_index];// copy packet// convert PTS/DTSav_pkt.pts = av_rescale_q_rnd(av_pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));av_pkt.dts = av_rescale_q_rnd(av_pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));av_pkt.duration = av_rescale_q(av_pkt.duration, in_stream->time_base, out_stream->time_base);av_pkt.pos = -1;// print to screenif (av_pkt.stream_index == video_idx) {if (is_sender) {fprintf(stdout, "Send %8d video frames to output URL\n", frame_idx);}else {fprintf(stdout, "Receive %8d video frames from input URL\n", frame_idx);}frame_idx++;}ret = av_interleaved_write_frame(av_out_fmt_ctx, &av_pkt);// ret = av_write_frame(av_out_fmt_ctx, av_pkt);if (ret < 0) {fprintf(stderr, "Error muxing packet, error code:%d\n", ret);break;}// av_packet_free(&av_pkt);av_packet_unref(&av_pkt);} // write file trailerav_write_trailer(av_out_fmt_ctx);end:avformat_close_input(&av_in_fmt_ctx);// close output/*if (av_out_fmt_ctx && !(av_out_fmt->flags & AVFMT_NOFILE)) {avio_close(av_out_fmt_ctx->pb);}*//*avformat_free_context(av_out_fmt_ctx);if (ret < 0 && ret != AVERROR_EOF) {fprintf(stderr, "Error occured\n");return -1;}*/return 0;
}int streamer()
{const char* in_url = "rtmp://127.0.0.1:1935/live/stream"; // input flv fileconst char* out_url = "receive.flv"; // output urlbool is_sender = 0;streamer_internal(in_url, out_url, is_sender);return 0;
}
3.3 测试
3.3.1 推流
使用代码进行推流,可以访问http://localhost/stat地址查看推流的状态。
...
...Metadata:encoder : Lavf61.3.100Duration: 00:00:40.00, start: 0.000000, bitrate: 18849 kb/sStream #0:0: Video: h264 (High), yuv420p(progressive), 1920x1200, 25 fps, 25 tbr, 1k tbn
Output #0, flv, to 'rtmp://127.0.0.1:1935/live/stream':Stream #0:0: Video: h264 (High), yuv420p(progressive), 1920x1200, q=2-31
Send 0 video frames to output URL
Send 1 video frames to output URL
Send 2 video frames to output URL
Send 3 video frames to output URL
Send 4 video frames to output URL
Send 5 video frames to output URL
Send 6 video frames to output URL
Send 7 video frames to output URL
Send 8 video frames to output URL
Send 9 video frames to output URL
Send 10 video frames to output URL
Send 11 video frames to output URL
Send 12 video frames to output URL
Send 13 video frames to output URL
Send 14 video frames to output URL
Send 15 video frames to output URL
Send 16 video frames to output URL
Send 17 video frames to output URL
Send 18 video frames to output URL
...
...
3.3.2 拉流
拉流时,需要对齐推流和拉流时的RTMP地址。如果不对齐,拉流将会一直处于idel状态。
Input #0, flv, from 'rtmp://127.0.0.1:1935/live/stream':Metadata:|RtmpSampleAccess: trueServer : NGINX RTMP (github.com/arut/nginx-rtmp-module)displayWidth : 1920displayHeight : 1200fps : 25profile :level :Duration: 00:00:00.00, start: 59.120000, bitrate: N/AStream #0:0: Video: h264 (High), yuv420p(progressive), 1920x1200, 25 fps, 25 tbr, 1k tbn
Output #0, flv, to 'receive.flv':Stream #0:0: Video: h264 (High), yuv420p(progressive), 1920x1200, q=2-31
Receive 0 video frames from input URL
Receive 1 video frames from input URL
Receive 2 video frames from input URL
Receive 3 video frames from input URL
Receive 4 video frames from input URL
Receive 5 video frames from input URL
Receive 6 video frames from input URL
Receive 7 video frames from input URL
Receive 8 video frames from input URL
Receive 9 video frames from input URL
Receive 10 video frames from input URL
Receive 11 video frames from input URL
Receive 12 video frames from input URL
另外,推流和拉流也可以使用其他已有工具,例如推流直接使用ffmpeg.exe,拉流使用ffplay.exe(或VLC Media Player)
CSDN: https://blog.csdn.net/weixin_42877471
Github: https://github.com/DoFulangChen/
相关文章:

【FFmpeg】调用ffmpeg库进行RTMP推流和拉流
【FFmpeg】调用ffmpeg库实现RTMP推流 1.FFmpeg编译2.RTMP服务器搭建3.调用FFmpeg库实现RTMP推流和拉流3.1 基本框架3.2 实现代码3.3 测试3.3.1 推流3.3.2 拉流 参考:雷霄骅博士, 调用ffmpeg库进行RTMP推流 示例工程 【FFmpeg】调用FFmpeg库实现264软编 【FFmpeg】…...

Multisim 14 常见电子仪器的使用和Multisim的使用
multisim multisim,即电子电路仿真设计软件。Multisim是美国国家仪器(NI)有限公司推出的以Windows为基础的仿真工具,适用于板级的模拟/数字电路板的设计工作。它包含了电路原理图的图形输入、电路硬件描述语言输入方式࿰…...

【2024高校网络安全管理运维赛】巨细记录!
2024高校网络安全管理运维赛 文章目录 2024高校网络安全管理运维赛MISC签到考点:动态图片分帧提取 easyshell考点:流量分析 冰蝎3.0 Webphpsql考点:sql万能钥匙 fileit考点:xml注入 外带 Cryptosecretbit考点:代码阅读…...

Nuxt.js实战:Vue.js的服务器端渲染框架
创建Nuxt.js项目 首先,确保你已经安装了Node.js和yarn或npm。然后,通过命令行创建一个新的Nuxt.js项目: yarn create nuxt-app my-nuxt-project cd my-nuxt-project在创建过程中,你可以选择是否需要UI框架、预处理器等选项&…...

提高Rust安装与更新的速度
一、背景 因为rust安装过程中,默认的下载服务器为crates.io,这是一个国外的服务器,国内用户使用时,下载与更新的速度非常慢,因此,我们需要使用一个国内的服务器来提高下载与更新的速度。 本文推荐使用字节…...

【linux软件基础知识】内核代码中的就绪队列简化示例
在内核代码中,就绪队列通常使用允许高效插入和删除进程的数据结构来表示。 用于表示就绪队列的一种常见数据结构是链表。 以下是如何使用链表在内核代码中表示就绪队列的简化示例: struct task_struct {// Process control block (PCB) fields// ...struct task_struct *nex…...

《C++学习笔记---初阶篇6》---string类 上
目录 1. 为什么要学习string类 1.1 C语言中的字符串 2. 标准库中的string类 2.1 string类(了解) 2.2 string类的常用接口说明 2.2.1. string类对象的常见构造 2.2.2. string类对象的容量操作 2.2.3.再次探讨reserve与resize 2.2.4.string类对象的访问及遍历操作 2.2.5…...

mysql中的页和行
页 行即表中的真实行,‘行式数据库’的由来 虽然MySQL的数据文件(例如.ibd文件)中的数据页在物理上是通过链表连接的,但是在逻辑上,MySQL使用B树来组织和访问数据。 行:主要是dynamic类型...

Vim常用快捷键
这个是我的草稿本记录一下防止丢失,以后有时间进行整理 0 或功能键[Home]这是数字『 0 』:移动到这一行的最前面字符处 (常用)$ 或功能键[End]移动到这一行的最后面字符处(常用)G移动到这个档案的最后一行(常用)nGn 为数字。移动到这个档案的第 n 行。例…...

力扣题目汇总分析 利用树形DP解决问题
树里 任意两个节点之间的问题。而不是根节点到叶子节点的问题或者是父节点到子节点的问题。通通一个套路,即利用543的解题思路。 543.二叉树的直径 分析 明确:二叉树的 直径 是指树中任意两个节点之间最长路径的 长度。两个节点之间的最长路径是他们之…...

GO语言核心30讲 实战与应用 (第二部分)
原站地址:Go语言核心36讲_Golang_Go语言-极客时间 一、sync.WaitGroup和sync.Once 1. sync.WaitGroup 比通道更加适合实现一对多的 goroutine 协作流程。 2. WaitGroup类型有三个指针方法:Wait、Add和Done,以及内部有一个计数器。 (1) Wa…...

linux设置挂载指定的usb,自动挂载
一、设置指定的USB 在Linux系统中,如果您只想让系统挂载特定的USB设备,而忽略其他的USB设备,可以通过创建自定义的udev规则来实现。以下是设置系统只能挂载指定USB设备的基本步骤: 确定USB设备的属性: 首先࿰…...

简站WordPress主题
简站WordPress主题是一种专为建立网站而设计的WordPress模板,它旨在简化网站建设过程,使得用户能够更容易地创建和管理自己的网站。简站WordPress主题具有以下特点: 易用性:简站WordPress主题被设计为简单易用,适合各…...

is和==的关系
Python中is和的关系 is判断两个变量是不是指的是同一个内存地址,也就是通过id()函数判断 判断两个变量的值是不是相同 a [1, 2, 3, 4] b [1, 2, 3, 4] print(id(a)) # 2298268712768 print(id(b)) # 2298269716992 print(a is b) # False print(a b) # Tr…...

璩静是为了薅百度羊毛
关注卢松松,会经常给你分享一些我的经验和观点。 百度副总裁璩静离职了,网传她的年薪是1500万,而璩静在4月24日注册了一个文化传媒公司,大家都认为璩静是在为离职做准备。但松松我认为不是。 我认为:璩静成立新公司是…...

Element ui input 限制只能输入数字,且只能有两位小数
<el-form-item label"整体进度:" prop"number"> <el-input v-model"formInline.number" input"handleInput" placeholder"百分比" clearable></el-input>% </el-form-item&g…...

吃掉 N 个橘子的最少天数
代码实现: 方法一:递归——超时 #define min(a, b) ((a) > (b) ? (b) : (a))int minDays(int n) {if (n 1 || n 2) {return n;}if (n % 3 0) {if (n % 2 0) {return min(min(minDays(n - 1), minDays(n / 2)), minDays(n - 2 * (n / 3))) 1;} e…...

JavaScript 之 toString()方法详解
一、前言: 在 JavaScript 中,toString() 方法是很多数据类型内置的方法,它被用于将特定的数据类型转换为字符串。但是在不同的数据类型中的作用并非完全相同,下面就来详细讲解一下 toString() 方法在各种数据类型中的使用和作用…...

PPMP_char3
PMPP char3 – Multidimensional grids and data 五一过后,有些工作要赶,抽出时间更新一下。这一章基本都熟练掌握,在做习题过程中有一些思考。这里涉及到了一点点GEMM(矩阵乘),GEMM有太多可深挖的了&a…...

VulkanSDK Demos vkcube 编译失败
操作系统: Windows 11 23H2 Vulkan 版本: 1.3.2.280.0 Visual Studio 版本: 2022 在VulkanSDK/Demos目录下存在一个demo solution,其中包含两个project, vkcube和vkcubepp,两个分别为C语言和C写的示例程序, 但是直接编译这两个project时会编译失败,报了以下错误: fatal err…...

(二)Jetpack Compose 布局模型
前文回顾 (一)Jetpack Compose 从入门到会写-CSDN博客 首先让我们回顾一下上一篇文章中里提到过几个问题: ComposeView的层级关系,互相嵌套存在的问题? 为什么Compose可以实现只测量一次? ComposeView和…...

【Oracle impdp导入dmp文件(windows)】
Oracle impdp导入dmp文件(windows) 1、连接数据库2、创建与导出的模式相同名称的用户WIRELESS2,并赋予权限3、创建directory 的物理目录f:\radio\dmp,并把.dmp文件放进去4、连接新用户WIRELESS25、创建表空间的物理目录F:\radio\t…...

代数结构:5、格与布尔代数
16.1 偏序与格 偏序集:设P是集合,P上的二元关系“≤”满足以下三个条件,则称“≤”是P上的偏序关系(或部分序关系) (1)自反性:a≤a,∀a∈P; (2…...

如何使用DEEPL免费翻译PDF
如何使用DEEPL免费翻译PDF 安装DEEPL取消PDF限制 安装DEEPL 安装教程比较多,这里不重复。 把英文pdf拖进去,点翻译,在下面的框中有已经翻译完毕的文档。 但是存在两个问题 问题1:这些文档是加密的。 问题2:带有DeepL标…...

Spring-全面详解
Spring,就像是软件开发界的一个超级英雄,它让编写Java程序变得更简单、更灵活。想象一下,如果你要盖一栋大楼,Spring就是那个提供各种工具、框架和最佳实践的建筑大师,帮助你高效、优雅地搭建起整个项目。 Spring是啥&…...

QT自适应界面 处理高DPI 缩放比界面乱问题
1.pro文件添加 必须添加要不找不到 QT版本需要 5。4 以上才支持 QT widgets 2.main界面提前处理 // 1. 全局缩放使能QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);// 2. 适配非整数倍缩放QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::High…...

序列到序列模型在语言识别Speech Applications中的应用 Transformer应用于TTS Transformer应用于ASR 端到端RNN
序列到序列模型在语言识别Speech Applications中的应用 A Comparative Study on Transformer vs RNN in Speech Applications 序列到序列(Seq2Seq)模型在语音识别(Speech Applications)中有重要的应用。虽然Seq2Seq模型最初是为了解决自然语言处理中的序列生成问题而设计的…...

【Linux】- Linux环境变量[8]
目录 环境变量 $符号 自行设置环境变量 环境变量 环境变量是操作系统(Windows、Linux、Mac)在运行的时候,记录的一些关键性信息,用以辅助系统运行。在Linux系统中执行:env命令即可查看当前系统中记录的环境变量。 …...

前端笔记-day04
文章目录 01-后代选择器02-子代选择器03-并集选择器04-交集选择器05-伪类选择器06-拓展-超链接伪类07-CSS特性-继承性08-CSS特性-层叠性09-CSS特性-优先级11-Emmet写法12-背景图13-背景图平铺方式14-背景图位置15-背景图缩放16-背景图固定17-background属性18-显示模式19-显示模…...

计算机字符集产生的历史与乱码
你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 一…...