FFmpeg第三话:FFmpeg 视频解码详解
FFmpeg 探索之旅
一、FFmpeg 简介与环境搭建
二、FFmpeg 主要结构体剖析
三、FFmpeg 视频解码详解
FFmpeg第三话:FFmpeg 视频解码详解
- FFmpeg 探索之旅
- 前言
- 一、视频解码基础
- 二、FFmpeg 关键 API 深度剖析
- (一)avformat_open_input()
- (二)avformat_find_stream_info()
- (三)avcodec_find_decoder()
- (四)avcodec_alloc_context3() 与 avcodec_parameters_to_context()
- (五)avcodec_open2()
- (六)av_read_frame() 与解码循环(含 avcodec_send_packet()、avcodec_receive_frame())
- 四、实战案例全流程解析
- 总结
前言
在多媒体技术蓬勃发展的当下,视频处理已然成为众多领域不可或缺的关键环节。而 FFmpeg,这款开源、跨平台且功能强大到近乎“神器”级别的音视频处理库,始终站在行业的前沿,为视频解码、编码、转码、滤镜处理等一系列复杂操作提供坚实的技术支撑。今天,就让我们一同深入探寻 FFmpeg 视频解码的核心世界,从基础概念到实际代码,彻底揭开它神秘的面纱。
一、视频解码基础
视频解码本质:
视频在存储与传输过程中,为削减数据量、节省带宽以及提升存储效率,会借助如 H.264、H.265、AV1 等先进编码标准进行高强度压缩。视频解码,恰似一场逆向的精密工程,旨在将这些压缩后的数据依照特定算法与规则,逐步还原为可供显示设备直接呈现或后续深度处理的原始视频帧序列,这些帧通常采用 YUV 或 RGB 色彩空间格式,每帧都蕴含着丰富的像素信息,精准勾勒出画面的每一处细节。
例如,H.264 编码巧妙运用帧间预测、帧内预测、变换编码及熵编码等复杂技术,去除画面中的冗余信息,仅保留关键数据;解码时,则需依据编码规则,反向推算出每个像素的原始取值,涉及运动补偿以还原帧间动态变化、熵解码恢复原始数据分布等关键步骤,确保画面流畅、清晰地重现。
二、FFmpeg 关键 API 深度剖析
(一)avformat_open_input()
此 API 作为开启视频解码之旅的首道大门,肩负着至关重要的使命。它接受一个 AVFormatContext
结构体指针的地址作为参数,旨在精准打开指定路径的视频文件,并深度剖析文件头信息,从而精准判定视频流的封装格式,诸如常见的 MP4、AVI、MKV 等,抑或是新兴的网络流封装格式。成功调用后,AVFormatContext
结构体将宛如一位信息渊博的向导,装满视频文件的基础元数据,涵盖文件时长、码率、各路音视频流数量及基本特性等关键情报,为后续解码流程铺就坚实基石。
示例代码:
#include <libavformat\avformat.h>
#include <stdio.h>int main()
{AVFormatContext* fmt_ctx = NULL;// 指定输入文件的路径const char* input_file_name = "input_video.mp4";// 打开输入文件int ret = avformat_open_input(&fmt_ctx, input_file_name, NULL, NULL);if (ret < 0) {// 如果打开失败,打印错误信息char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);fprintf(stderr, "Unable to open input video file.");return -1;}// ...// 释放资源avformat_close_input(&fmt_ctx);return 0;
}
这段代码尝试打开名为 "input_video.mp4"
的文件,若遭遇阻碍,借助 av_strerror
获取详细错误信息并输出,随即终止程序,凸显严谨的错误处理逻辑。
(二)avformat_find_stream_info()
avformat_find_stream_info()
对已打开的视频文件展开深度扫描与剖析。它遍历视频文件的每一处角落,不仅进一步完善 AVFormatContext
结构体中既有信息的细节,更精准定位各路音视频流,详细解析出视频流的分辨率、帧率、编码参数,音频流的采样率、声道布局等核心要素,为后续精准分离与处理不同类型媒体流提供精准导航。
示例代码:
ret = avformat_find_stream_info(fmt_ctx, NULL);
if (ret < 0) {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);fprintf(stderr, "无法获取视频流信息: %s\n", errbuf);avformat_close_input(&fmt_ctx);return -1;
}
在此,若信息获取环节出现差池,及时关闭已打开文件资源,避免内存泄漏等隐患,同时输出错误详情,确保程序稳定性与可维护性。
(三)avcodec_find_decoder()
avcodec_find_decoder()
依据视频流特定编码 ID(如 AV_CODEC_ID_H264
、AV_CODEC_ID_HEVC
等),在 FFmpeg 庞大的解码器库中迅速定位匹配解码器。一旦觅得,即刻返回 AVCodec
结构体指针,此指针恰似解码器的操控手册,掌控着解码流程的核心算法与关键参数设置,是后续构建解码环境的核心依托。
示例代码:
AVCodec *codec = NULL;
int video_stream_index = -1;
for (int i = 0; i < fmt_ctx->nb_streams; i++) {if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_stream_index = i;codec = avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id);if (!codec) {fprintf(stderr, "未找到视频解码器\n");avformat_close_input(&fmt_ctx);return -1;}break;}
}
这段代码遍历视频文件所有流,锁定视频流后竭力寻找适配解码器,若搜寻无果,果断关闭文件资源,终止程序,以防陷入无意义的后续操作。
(四)avcodec_alloc_context3() 与 avcodec_parameters_to_context()
avcodec_alloc_context3()
为选定解码器精心分配AVCodecContext
结构体内存空间,并初始化一系列默认参数,搭建起解码操作的基础场地框架,准备迎接后续精细配置。
示例代码:
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {fprintf(stderr, "无法分配解码器上下文\n");avformat_close_input(&fmt_ctx);return -1;
}
若内存分配环节遇阻,迅速清理现场,关闭文件,保障程序稳健运行。
avcodec_parameters_to_context()
负责将视频流AVStream
结构体中AVCodecParameters
所蕴含的编码参数,毫厘不差地复制到AVCodecContext
结构体中,确保解码器精准遵循视频流原始编码规则行事,从像素格式到分辨率,从帧率到码率控制参数,全方位保障解码一致性。
示例代码:
ret = avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream_index]->codecpar);
if (ret < 0) {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);fprintf(stderr, "无法复制编解码器参数: %s\n", errbuf);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;
}
复制过程若现异常,立即释放已分配解码器上下文内存,关闭文件,避免资源浪费与错误蔓延。
(五)avcodec_open2()
avcodec_open2()
依据 AVCodecContext
结构体中精心配置的参数,深度初始化解码器内部复杂算法机制,调配所需系统资源,完成解码器初始化的最后冲刺。此刻,解码器宛如一台蓄势待发的引擎,静候视频数据输入,准备释放强大解码效能。
示例代码:
ret = avcodec_open2(codec_ctx, codec, NULL);
if (ret < 0) {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);fprintf(stderr, "无法打开解码器: %s\n", errbuf);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;
}
一旦解码器启动失败,迅速拆解已构建的解码环境,关闭文件,严守程序稳定防线。
(六)av_read_frame() 与解码循环(含 avcodec_send_packet()、avcodec_receive_frame())
av_read_frame()
用于严格依循视频文件封装格式规则,逐帧从文件中读取数据包,将其妥善封装于AVPacket
结构体中,该结构体满载未解码的原始视频数据、所属流索引以及关键时间戳信息,成为解码流程数据源头的稳定供给站。
示例代码:
AVPacket pkt;
while (av_read_frame(fmt_ctx, &pkt) >= 0) {if (pkt.stream_index == video_stream_index) {// 此数据包属视频流,送解码器处理// 后续解码代码......}av_packet_unref(&pkt);
}
循环读取数据包,一旦识别出视频流数据包,即刻送入后续解码流程,每轮循环末尾,借助 av_packet_unref()
释放数据包资源,避免内存泄漏,确保数据流转顺畅。
avcodec_send_packet()
恰似解码流水线的前端“调度员”,将AVPacket
数据包精准推送至解码器输入缓冲区,若缓冲区满溢或遭遇特殊状况,及时反馈错误码,巧妙调控解码节奏,开启帧数据解码之旅。
示例代码:
ret = avcodec_send_packet(codec_ctx, &pkt);
if (ret < 0) {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);fprintf(stderr, "发送数据包至解码器出错: %s\n", errbuf);av_packet_unref(&pkt);continue;
}
遇发送异常,迅速处理错误,释放数据包引用,无缝衔接下一轮数据读取,保障流程连贯性。
avcodec_receive_frame()
则扮演解码流水线末端的“收获者”角色,全神贯注地尝试从解码器获取解码完毕的完整视频帧(封装于AVFrame
结构体),该结构体满载珍贵原始像素数据,静候进一步处理或存储。成功收获帧数据则返回 0,若暂无帧就绪或已达视频尾声,则相应返回特定错误码,循环调用此函数直至完整视频帧序列尽收囊中。
示例代码:
AVFrame *frame = av_frame_alloc();
while (ret >= 0) {ret = avcodec_receive_frame(codec_ctx, frame);if (ret == 0) {// 成功获取解码帧,可处理或保存// 后续帧处理代码......} else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {// 无帧或已到视频尾,跳出或继续读取数据包break;} else {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);fprintf(stderr, "接收解码帧出错: %s\n", errbuf);break;}
}
av_frame_free(&frame);
每轮循环谨慎判断返回值,依据不同情形灵活抉择继续读取、跳出循环或处理错误,最终释放 AVFrame
资源,完美收官解码流程。
四、实战案例全流程解析
以下奉上一段基于 FFmpeg 完整解码本地视频文件并将解码后 YUV420P 格式帧数据存储至 output.yuv
文件的示例代码,全程穿插严谨错误处理机制,确保程序稳健运行:
#include <iostream>
#include <string>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
}void handle_ffmpeg_error(int ret, const char* msg) {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);fprintf(stderr, "%s: %s\n", msg, errbuf);
}int main() {AVFormatContext* fmt_ctx = avformat_alloc_context();std::string file_path = "F:/QT/mp4_flv/x.mp4";// 打开输入视频文件,建立 AVFormatContextint ret = avformat_open_input(&fmt_ctx, file_path.c_str(), NULL, NULL);if (ret < 0) {handle_ffmpeg_error(ret, "Failed to open video file");return -1;}// 解析视频流信息,填充 AVFormatContext 细节ret = avformat_find_stream_info(fmt_ctx, NULL);if (ret < 0) {handle_ffmpeg_error(ret, "Error in obtaining video stream information");return -1;}// 定位视频流找到适合的解码器const AVCodec* codec = NULL;int video_stream_idx = -1;for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_stream_idx = i;codec = avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id);if (!codec) {fprintf(stderr, "Video decoder not found\n");avformat_close_input(&fmt_ctx);return -1;}break;}}// 分配解码器上下文,关联解码器与参数AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx) {fprintf(stderr, "Decoder context allocation failed\n");avformat_close_input(&fmt_ctx);return -1;}ret = avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream_idx]->codecpar);if (ret < 0) {handle_ffmpeg_error(ret, "Copying codec parameters failed");avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;}// 打开解码器ret = avcodec_open2(codec_ctx, codec, NULL);if (ret < 0) {handle_ffmpeg_error(ret, "Decoder open failed!");avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;}// 分配 AVFrame 存储解码帧,准备输出 YUV 文件AVFrame* frame = av_frame_alloc();FILE* out_file = nullptr;if (fopen_s(&out_file, "output.yuv", "wb") != 0) {perror("无法创建输出 YUV 文件");av_frame_free(&frame);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;}// 读取视频帧数据包,解码循环AVPacket pkt;while (av_read_frame(fmt_ctx, &pkt) >= 0) {if (pkt.stream_index == video_stream_idx) {ret = avcodec_send_packet(codec_ctx, &pkt);if (ret < 0) {handle_ffmpeg_error(ret, "Error sending data packet to decoder.");av_packet_unref(&pkt);continue;}while (ret >= 0) {ret = avcodec_receive_frame(codec_ctx, frame);if (ret == 0) {// 将解码后的 YUV 数据写入文件for (int i = 0; i < frame->height; i++) {fwrite(frame->data[0] + i * frame->linesize[0], 1, frame->width, out_file);}for (int i = 0; i < frame->height / 2; i++) {fwrite(frame->data[1] + i * frame->linesize[1], 1, frame->width / 2, out_file);}for (int i = 0; i < frame->height / 2; i++) {fwrite(frame->data[2] + i * frame->linesize[2], 1, frame->width / 2, out_file);}}else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {break;}else {handle_ffmpeg_error(ret, "Error receiving decoded frame.");break;}}}av_packet_unref(&pkt);}// 释放资源,关闭文件与上下文fclose(out_file);av_frame_free(&frame);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return 0;
}
总结
本文围绕 FFmpeg 视频解码进行了全面讲解,核心内容包括:
- 视频解码基础概念:介绍视频存储与传输时会压缩,解码则是逆向还原为原始视频帧序列的过程,以常见编码标准举例说明了编码和解码的关键技术要点。
- FFmpeg 关键 API 剖析:详细解读了多个关键 API,如avformat_open_input()用于打开文件获取基础元数据;avformat_find_stream_info()完善流信息解析;avcodec_find_decoder()定位解码器;avcodec_alloc_context3()和avcodec_parameters_to_context()搭建与配置解码环境;avcodec_open2()初始化解码器;以及av_read_frame()、avcodec_send_packet()、avcodec_receive_frame()协同完成数据读取、发送与帧接收等操作,各 API 都附带有示例代码与错误处理逻辑展示。
- 实战案例解析:呈现了完整解码本地视频并存储解码帧数据的示例代码,其中融入了严谨的错误处理机制,体现从视频文件打开到最终资源释放、文件关闭的全流程操作,确保程序稳定运行。
相关文章:
FFmpeg第三话:FFmpeg 视频解码详解
FFmpeg 探索之旅 一、FFmpeg 简介与环境搭建 二、FFmpeg 主要结构体剖析 三、FFmpeg 视频解码详解 FFmpeg第三话:FFmpeg 视频解码详解 FFmpeg 探索之旅前言一、视频解码基础二、FFmpeg 关键 API 深度剖析(一)avformat_open_input()ÿ…...

解决 vue3 中 echarts图表在el-dialog中显示问题
原因: 第一次点开不显示图表,第二次点开虽然显示图表,但是图表挤在一起,页面检查发现宽高只有100px,但是明明已经设置样式宽高100% 这可能是由于 el-dialog 还没有完全渲染完成,而你的 echarts 组件已经开始尝试渲染图…...

C++ OpenGL学习笔记(4、绘制贴图纹理)
相关链接: C OpenGL学习笔记(1、Hello World空窗口程序) C OpenGL学习笔记(2、绘制橙色三角形绘制、绿色随时间变化的三角形绘制) C OpenGL学习笔记(3、绘制彩色三角形、绘制彩色矩形) 通过前面…...

关于我的Java考试被老师挂掉的这件事......
目录 1.事情起源 2.问题出现 3.最后的考试结果 4.问题如何解决的 5.此件事情引发我的思考 1.事情起源 现在是2024-12-25中午的13:08分,我于今天上虞结束了这个学期的Java课程的学习,上午的课程内容就是开始,使用MVC实现对于题目要求的这…...

Websocket客户端从Openai Realtime api Sever只收到部分数据问题分析
目录 背景 分析 解决方案 背景 正常情况下,会从Openai Realtime api Sever收到正常的json数据,但是当返回音频数据时,总会返回非json数据。这是什么问题呢? 分析 期望的完整响应数据如下: {"session": {"inp…...
Unity 6 中的新增功能
Unity 6 是 Unity 的最新版本。 一、编辑器和工作流程 Unity 6 中引入的更改 在 Linux 上实现了将文件和资源从 Unity 拖放到外部应用程序的功能。将 Asset Manager for Unity 包添加到 Package Manager > Services > Content Management 部分中。此包允许用户轻松浏览…...

[ComfyUI]颜色提取插件,Flux专属,让出图更加可控
一、介绍 今天介绍这个好玩的插件 ComfyUI APQNodes,默认的Flux模型是无法理解准确的颜色代码。 而这个插件可以帮我忙将输入的十六进制颜色代码转换为 FLUX.1 Dev 已知的最相似的颜色名称(来自预先测试的 155 个颜色名称)。 所以就…...

【magic-dash】01:magic-dash创建单页面应用及二次开发
文章目录 一、magic-dash是什么1.1 安装1.2 使用1.2.1 查看内置项目模板1.2.2 生成指定项目模板1.2.3 查看当前magic-dash版本1.2.4 查看命令说明1.2.5 内置模板列表二、创建虚拟环境并安装magic-dash三、magic-dash单页工具应用开发3.1 创建单页面项目3.1.1 使用命令行创建单页…...
ChatGPT等大语言模型与水文水资源、水环境领域的深度融合
聚焦GPT等大语言模型与水文水资源领域的深度融合,通过系统化内容与实践案例,讲解如何高效完成时间序列分析、空间数据处理、水文模型优化以及智能科学写作等任务。同时,展示AI在高级机器学习模型开发、资源优化算法编程与模型微调中的最新应用…...
机器学习连载
1 机器学习基础知识 机器学习(Machine learning)是人工智能的子集,是实现人工智能的一种途径,但并不是唯一的途径。它是一门专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已…...

linux查看天气预报
wttr.in 是一个简单且功能强大的命令行天气查询工具,实现了命令行下查看天气的炫酷效果。 开源地址:GitHub - chubin/wttr.in: :partly_sunny: The right way to check the weather 一. 什么是 wttr.in? wttr.in 是一个基于 Web 的命令行天…...
minikube start --driver=docker --force
minikube start --driver=docker --force 😄 minikube v1.34.0 on Debian 11.7 (amd64) ❗ minikube skips various validations when --force is supplied; this may lead to unexpected behavior ✨ Using the docker driver based on user configuration 🛑 The…...

游戏引擎学习第58天
发现一个vscode Log 断点的用法 回顾 我们正在继续推进工作,之前做了一些测试和清理工作,但还有一件事没有完成,因此我们还没有完全回到功能平衡的状态。昨天我们已经为实体做了空间划分,所以接下来的目标是继续完成这部分工作&a…...

我用火语言RPA生成EXE可执行文件,并使用激活码对EXE进行管理
火语言RPA,不仅可以生成EXE独立可执行文件,还可以使用激活码的功能对EXE进行管理,限制激活类型:在线、离线,EXE有效天数等进行管理,有限制的自由才是真正的自由! 生成EXE的时候选择App注册码验证类型 当分享…...

【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)11
文章目录 一、算法概念11二、算法原理(一)感知机(二)多层感知机1、隐藏层2、激活函数sigma函数tanh函数ReLU函数 3、反向传播算法 三、算法优缺点(一)优点(二)缺点 四、MLP分类任务实…...
32位MCU主控智能电表方案
智能电表作为电网数据采集的核心设备,承担着至关重要的角色。它主要用于采集、计量和传输原始的电能数据,确保电力系统的高效运行。该设备配备了多种通讯接口,如RS485和以太网,使得用户能够轻松进行用电检测、集中抄表以及电力管理…...
ConstraintLayout是完美的布局吗?
非也! <TextViewandroid:id"id/tv_tittle_msg"android:layout_width"wrap_content"android:layout_height"wrap_content"android:layout_marginLeft"16dp"android:layout_marginRight"16dp"android:layout_ma…...
39.在 Vue3 中使用 OpenLayers 导出 GeoJSON 文件及详解 GEOJSON 格式
一、引言 在 Web 地图开发领域,Vue3 作为一款流行的前端框架,结合强大的 OpenLayers 地图库,能够实现丰富多样的地图功能。其中,将地图数据以 GeoJSON 格式导出是一项常见且实用的需求,本文将深入探讨如何在 Vue3 环境…...

Feign的调用demo 和 EnableFeignClients的包名
在你的场景下,如果刷题微服务通过 Maven 引入了 auth-api 模块,并且 auth-api 中定义了 Feign 接口(例如获取用户名的方法),你需要在 刷题微服务 中的启动类上配置 EnableFeignClients 注解。配置中 basePackages 参数…...
简化开发流程:如何通过 JDBC 自动生成符合 Java 命名规范的实体类
在这篇博客中,我分享了如何通过 Java 和 JDBC 自动生成数据库实体类的过程。通常,手动编写实体类代码既繁琐又容易出错,尤其是在数据库表结构发生变化时,手动更新代码的工作量非常大。为了提高开发效率,我利用 JDBC 连…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解
进来是需要留言的,先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码,输入的<>当成字符串处理回显到页面中,看来只是把用户输…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...