ffmpeg过滤器filter理论与实战

文章目录

  • 前言
  • 一、DirectShow
    • 1、简介
    • 2、程序基本结构
    • 3、架构
  • 二、过滤器
    • 1、视频过滤器 -vf
    • 2、音频过滤器 -af
    • 3、过滤器链(Filterchain)
    • 4、过滤器图(Filtergraph)
      • ①、基本语法
      • ②、Filtergraph 的分类
    • 5、结构体间的关系图
  • 三、过滤器案例实战
    • 1、示例源码
    • 2、运行结果


前言

ffmpeg 过滤器,当然也有人称为 ffmpeg 滤镜。(用滤镜听起来好像是给 video 用的,所以不太好,因为 audio 也可以用),ffmpeg 目录下,有个文件夹叫 libavfilter,它可以单独编译为一个库。干嘛用的呢?用于音视频过滤。
比如,我有一个 mp4,想把它缩小一半,输出一个新的 mp4,那么,做缩小动作的,就是 libavfilter。

本文进行 ffmpeg 过滤器的理论学习及代码实战。


一、DirectShow

在进行 ffmpeg 过滤器(filter)的学习之前,我们有必要先了解一下 DirectShow,方便后面我们学习 ffmpeg 过滤器时更方便容易理解。

1、简介

DirectShow(简称 DShow)是一个 Windows 平台上的流媒体框架,提供了高质量的多媒体流采集和回放功能。它支持多种多样的媒体文件格式,包括 ASF、MPEG、AVI、MP3 和 WAV 文件,同时支持使用 WDM 驱动或早期的 VFW 驱动来进行多媒体流的采集。

DirectShow 大大简化了媒体回放、格式转换和采集工作。但与此同时,它也为用户自定义的解决方案提供了底层流控制框架,从而使用户可以自行创建支持新的文件格式或其他用户的 DirectShow 组件。

DirectShow 专为 C++ 而设计。 Microsoft 不提供用于 DirectShow 的托管 API。

DirectShow 是基于组件对象模型(COM)的,因此当你编写 DirectShow 应用程序时,你必须具备 COM 客户端程序编写的知识。对于大部分的应用程序,你不需要实现自己的 COM 对象,DirectShow 提供了大部分你需要的 DirectShow 组件,但是假如你需要编写自己的 DirectShow 组件来进行扩充,那么你必须编写实现 COM 对象。

使用 DirectShow 编写的典型应用程序包括:DVD 播放器、视频编辑程序、AVI 到 ASF 转换器、MP3 播放器和数字视频采集应用。

2、程序基本结构

DirectShow 程序基本结构如下图所示:
在这里插入图片描述

3、架构

DirectShow 的架构如下图所示:
在这里插入图片描述

  • DirectShow 位于应用层中。它使用一种叫 Filter Graph 的模型来管理整个数据流的处理过程;参与数据处理的各个功能模块叫 Filter;<font color=>各个 Filter 在 Filter Graph 中按一定的顺序连接成一条 “流水线” 协同工作。(可以看出 FilterGraph 是 Filter 的容器 )
  • 按照功能来分,Filter 大致分为三类:Source FiltersTransform FiltersRendering(sink) Filters
    • Source Filters 主要负责取得数据,数据源可以是文件、因特网、或者计算机里的采集卡、数字摄像机等,然后将数据往下传输;
    • Transform Fitlers 主要负责数据的格式转换、传输;
    • Rendering Filtes 主要负责数据的最终去向,我们可以将数据送给声卡、显卡进行多媒体的演示,也可以输出到文件进行存储。

Filter 一般由一个或多个Pin组成,Filter 之间通过 Pin 相互连接。如下图所示:
在这里插入图片描述

在 DirectShow 系统上,我们看到的,即是我们的应用程序(Application)。应用程序要按照一定的意图建立起相应的 Filter Graph,然后通过 Filter Graph Manager 来控制整个的数据处理过程。DirectShow 能在 Filter Graph 运行的时候接收到各种事件,并通过消息的方式发送到我们的应用程序。这样,就实现了应用程序与 DirectShow 系统之间的交互。

DirectShow 使用一种叫 Filter Graph 的模型来管理整个数据流的处理过程;参与数据处理的各个功能模块叫做 Filter;各个 Filter 在 Filter Graph 中按一定的顺序连接成一条"流水线"协同工作。Filter,它是最基本的软件构件,过滤器通常在多媒体流中执行一个操作。各个 Filter在 Filter Graph 中按一定的顺序连接成一条"流水线"协同工作。如果用图论的术语描述,过滤器图是一个有向、无环、非连通图。有向是因为数据在过滤器之间以预定的方向流动;无环是指没有路径可以从一个过滤器出发又返回到它自身;而非连通是指不是所有的过滤器都可以达到所有其他过滤器。

二、过滤器

在多媒体处理中,filter 的意思是被编码到输出文件之前用来修改输入文件内容的一个软件工具。如:视频翻转,旋转,缩放等。

语法: [input_link_label1]… filter_name=parameters [output_link_label1]…

1、视频过滤器 -vf

如 input.mp4 视频按顺时针方向旋转 90 度

ffplay -i input.mp4 -vf transpose=1

如 input.mp4 视频水平翻转(左右翻转)

ffplay -i input.mp4 -vf hflip

2、音频过滤器 -af

实现慢速播放, 声音速度是原始速度的 50%

ffplay input.mp3 -af atempo=0.5

3、过滤器链(Filterchain)

Filterchain = 逗号分隔的一组 filter

语法: “filter1,filter2,filter3,…filterN-2,filterN-1,filterN”

顺时针旋转 90 度并水平翻转

ffplay -i input.mp4 -vf transpose=1,hflip

4、过滤器图(Filtergraph)

下面我们先做一个镜面对称的视频举例,最终的效果如下:
在这里插入图片描述

第一步:源视频宽度扩大两倍

ffmpeg -i input.mp4 -t 10 -vf pad=2*iw output.mp4

第二步:源视频水平翻转

ffmpeg -i input.mp4 -t 10 -vf hflip output2.mp4

第三步:水平翻转视频覆盖 output.mp4

ffmpeg -i output.mp4 -i output2.mp4 -filter_complex overlay=w compare.mp4

下面我们用过滤器图来实现上面三条命令所实现的效果

①、基本语法

Filtergraph = 分号分隔的一组 filterchain
“filterchain1;filterchain2;…filterchainN-1;filterchainN”

实现上面三步用带有链接标记的过滤器图(Filtergraph)只需一条命令:

ffmpeg -i test.mp4 -t 10 -vf "split[a][b];[a]pad=2*iw[1];[b]hflip[2];[1][2]overlay=w" output.mp4
  • split 过滤器创建两个输入文件的拷贝并标记为 [a],[b]
  • [a] 作为 pad 过滤器的输入,pad 过滤器产生 2 倍宽度并输出到 [1]
  • [b] 作为 hflip 过滤器的输入,vflip 过滤器水平翻转视频并输出到 [2]
  • 用 overlay 过滤器把 [2] 覆盖到 [1] 的旁边

②、Filtergraph 的分类

  • 简单(simple):一对一
  • 复杂(complex):多对一,多对多

简单过滤器图处理流程:
在这里插入图片描述
复杂过滤器图处理流程:
在这里插入图片描述
从图中可以发现复杂过滤器图比简单过滤器图少 2 个步骤,效率比简单高,ffmpeg 建议尽量使用复杂过滤器图。

5、结构体间的关系图

filter 涉及的结构体,主要包括:

  • FilterGraph, AVFilterGraph
  • InputFilter, InputStream, OutputFilter, OutputStream
  • AVFilter,AVFilterContext
  • AVFilterLink
  • AVFilterPad

它们之间的类关系如下图所示:
在这里插入图片描述
从上图可以看到, FFmpeg 的滤镜相关的结构体三层组成:

  • filtergraph 层
    • 由结构体 FilterGraph,AVFilterGraph 组成;
    • 其中,FilterGraph:
      • 包含一个 InputFilter,它指示了整个 Graph 的第一个滤镜,并指示了 InputStream,从而作为整个 Graph 的输入;
      • 包含一个 OutputFilter,它指示了整个 Graph 的最后一个滤镜,并指示了 OutputStream,从而作为整个 Graph 的输出;
      • 包含一个 AVFilterGraph 的实例, 它指示的是组成本 graph 的 filter;
  • filterchain 层
    • 它由 AVFilter,AVFilterContext,AVFilterLink,AVFilterPad 组成;其中,AVFilterContext 是 AVFilter 的实例;
      • 而 filter 之间是用 AVFilterLink 进行连接,意思是,滤镜之间并不是直接相连的,是通过 AVFilterLink 进行连接;
      • AVFilterContext 通过 AVFilterLink 进行连接后,就组成了 Filterchain。
      • 而 AVFilterContext 与 AVFilterLink 之间的 AVFilterPad 是直接相连的,对应的关系是:AVFilterContext 的 output_pad 连接它下游 AVFilterLink 的 srcpad;AVFilterContext 的 input_pad 连接它上游 AVFilterLink 的 dstpad;
  • filter 层
    • AVFilterContext,AVFilterPad 组成;其中 AVFilterContext 是真正进行数据处理的滤镜实体;
    • AVFilterPad 用于 AVFilterContext 之间的 callback(回调):
      • 第一个 AVFilterContext 的 outputs[0] 指针, 指向第一个 AVFilterLink, 这个 AVFilterLink 的 dst
        指针,指向第二个 AVFilterContext。
      • 如果在前一个 AVFilterContext 调用 outputs[0]->dstpad->filter_frame(Frame* input_frame1), 其实就意味着,第一个过滤器,可以把处理好的一个 frame(名字为 input_frame1),通过这个调用传递给第二个过滤器的 input_pads 的 filter_frame 函数。而第二个过滤器,里面就是用户自己实现的 filter_frame(),以对数据进行处理;

三、过滤器案例实战

下面代码通过解码视频帧并将其送入滤镜图进行处理,然后将处理后的帧写入文件。滤镜描述字符串 filter_descr 指定了滤镜操作,本例中使用了 scale 和 hflip 滤镜来对视频进行缩放和水平翻转操作。最终,程序会将处理后的视频帧以 YUV420P 格式写入文件。

1、示例源码


/*** @file* API example for decoding and filtering* @example filtering_video.c*/#define _XOPEN_SOURCE 600 /* for usleep */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>const char *filter_descr = "scale=640:480,hflip";
/* other way:scale=78:24 [scl]; [scl] transpose=cclock // assumes "[in]" and "[out]" to be input output pads respectively*/static AVFormatContext *fmt_ctx;
static AVCodecContext *dec_ctx;
AVFilterContext *buffersink_ctx;
AVFilterContext *buffersrc_ctx;
AVFilterGraph *filter_graph;
static int video_stream_index = -1;
static int64_t last_pts = AV_NOPTS_VALUE;static int open_input_file(const char *filename)
{int ret;AVCodec *dec;if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");return ret;}if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");return ret;}/* select the video stream */ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");return ret;}video_stream_index = ret;/* create decoding context */dec_ctx = avcodec_alloc_context3(dec);if (!dec_ctx)return AVERROR(ENOMEM);avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar);/* init the video decoder */if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");return ret;}return 0;
}static int init_filters(const char *filters_descr)
{char args[512];int ret = 0;const AVFilter *buffersrc  = avfilter_get_by_name("buffer");const AVFilter *buffersink = avfilter_get_by_name("buffersink");AVFilterInOut *outputs = avfilter_inout_alloc();AVFilterInOut *inputs  = avfilter_inout_alloc();AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base;enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };filter_graph = avfilter_graph_alloc();if (!outputs || !inputs || !filter_graph) {ret = AVERROR(ENOMEM);goto end;}/* buffer video source: the decoded frames from the decoder will be inserted here. */snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,time_base.num, time_base.den,dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",args, NULL, filter_graph);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");goto end;}/* buffer video sink: to terminate the filter chain. */ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",NULL, NULL, filter_graph);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");goto end;}/** Set the endpoints for the filter graph. The filter_graph will* be linked to the graph described by filters_descr.*//** The buffer source output must be connected to the input pad of* the first filter described by filters_descr; since the first* filter input label is not specified, it is set to "in" by* default.*/outputs->name       = av_strdup("in");outputs->filter_ctx = buffersrc_ctx;outputs->pad_idx    = 0;outputs->next       = NULL;/** The buffer sink input must be connected to the output pad of* the last filter described by filters_descr; since the last* filter output label is not specified, it is set to "out" by* default.*/inputs->name       = av_strdup("out");inputs->filter_ctx = buffersink_ctx;inputs->pad_idx    = 0;inputs->next       = NULL;if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,&inputs, &outputs, NULL)) < 0)goto end;if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)goto end;end:avfilter_inout_free(&inputs);avfilter_inout_free(&outputs);return ret;
}/// 将yuv帧写入文件:yuv420p格式
FILE * g__file_fd;
static void write_frame(const AVFrame *frame)
{static int printf_flag = 0;if(!printf_flag){printf_flag = 1;printf("frame widht=%d,frame height=%d\n",frame->width,frame->height);if(frame->format==AV_PIX_FMT_YUV420P){printf("format is yuv420p\n");}else{printf("formet is = %d \n",frame->format);}}fwrite(frame->data[0],1,frame->width*frame->height,g__file_fd);fwrite(frame->data[1],1,frame->width/2*frame->height/2,g__file_fd);fwrite(frame->data[2],1,frame->width/2*frame->height/2,g__file_fd);
}int main(int argc, char **argv)
{int ret;AVPacket packet;AVFrame *frame;AVFrame *filt_frame;g__file_fd = fopen("./debug/test.yuv", "w");frame = av_frame_alloc();filt_frame = av_frame_alloc();if (!frame || !filt_frame) {perror("Could not allocate frame");exit(1);}if ((ret = open_input_file("./debug/test.flv")) < 0)goto end;if ((ret = init_filters(filter_descr)) < 0)goto end;/* read all packets */while (1) {if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)break;if (packet.stream_index == video_stream_index) {ret = avcodec_send_packet(dec_ctx, &packet);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Error while sending a packet to the decoder\n");break;}while (ret >= 0) {ret = avcodec_receive_frame(dec_ctx, frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {break;} else if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Error while receiving a frame from the decoder\n");goto end;}frame->pts = frame->best_effort_timestamp;  // 将该时间戳设置为帧的显示时间戳/* push the decoded frame into the filtergraph */if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");break;}/* pull filtered frames from the filtergraph */while (1) {ret = av_buffersink_get_frame(buffersink_ctx, filt_frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)break;if (ret < 0)goto end;write_frame(filt_frame);av_frame_unref(filt_frame);}av_frame_unref(frame);}}av_packet_unref(&packet);}
end:avfilter_graph_free(&filter_graph);avcodec_free_context(&dec_ctx);avformat_close_input(&fmt_ctx);av_frame_free(&frame);av_frame_free(&filt_frame);fclose(g__file_fd);if (ret < 0 && ret != AVERROR_EOF) {fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));exit(1);}exit(0);
}

2、运行结果

打印输出如下:

frame widht=640,frame height=480
format is yuv420p

生成的原始视频数据 test.yuv 文件相比之前已进行压缩的 test.flv 文件大很多
在这里插入图片描述

使用 yuvplayer.exe 播放生成的 test.yuv 文件可以看到下面的结果:
在这里插入图片描述


我的qq:2442391036,欢迎交流!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/214105.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

保研毕业论文查重率多少通过【保姆教程】

大家好&#xff0c;今天来聊聊保研毕业论文查重率多少通过&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; 保研毕业论文查重率多少通过 在保研过程中&#xff0c;毕业论文的查重率是衡量学术诚信和论文…

JAVA8新特性之函数式编程详解

JAVA8新特性之函数式编程详解 前言一、初步了解函数式接口二、 Lambda表达式2.1 概述2.2 lambda省略规则2.3 lambda省略常见实例2.4 lambda表达式与函数式接口 三、 Stream流3.1 stream流的定义3.2 Stream流的特点3.3 Stream流的三个步骤3.4 Stream 和 Collection 集合的区别&a…

【HarmonyOS开发】拖拽动画的实现

动画的原理是在一个时间段内&#xff0c;多次改变UI外观&#xff0c;由于人眼会产生视觉暂留&#xff0c;所以最终看到的就是一个“连续”的动画。UI的一次改变称为一个动画帧&#xff0c;对应一次屏幕刷新&#xff0c;而决定动画流畅度的一个重要指标就是帧率FPS&#xff08;F…

【带头学C++】----- 九、类和对象 ---- 9.12 C++之友元函数(9.12.1---12.4)

❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️创做不易&#xff0c;麻烦点个关注❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️ ❤️❤️❤️❤️❤️❤️❤️❤️❤️文末有惊喜&#xff01;献舞一支&#xff01;❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️ 目录 9.12…

五:爬虫-数据解析之xpath解析

三&#xff1a;数据解析之xpath解析 1.xpath介绍&#xff1a; ​ xpath是XML路径语言&#xff0c;它可以用来确定xml文档中的元素位置&#xff0c;通过元素路径来完成对元素的查找&#xff0c;HTML就是XML的一种实现方式&#xff0c;所以xpath是一种非常强大的定位方式​ XPa…

vue2 element-ui select下拉框 选择传递多个参数

<el-select v-model"select" slot"prepend" placeholder"请选择" change"searchPostFn($event,123)"> <el-option :label"item.ziDianShuJu" :value"{value:item.id, label:item.ziDianShuJu}" v-for&qu…

Ubuntu系统使用快速入门实践(七)——软件安装与使用(5)

Ubuntu系统使用快速入门实践系列文章 下面是Ubuntu系统使用系列文章的总链接&#xff0c;本人发表这个系列的文章链接均收录于此 Ubuntu系统使用快速入门实践系列文章总链接 下面是专栏地址&#xff1a; Ubuntu系统使用快速入门实践系列文章专栏 文章目录 Ubuntu系统使用快速…

【unity】【WebRTC】从0开始创建一个Unity远程媒体流app-构建可同步场景

【背景】 最近在研究远程画面&#xff0c;所以就实践了一下。技术采用我认为比较合适的WebRTC。 这篇文章的基础是我的另一篇博文&#xff0c;如果希望顺利完成本篇操作&#xff0c;请先关注我后查询我的如下博文&#xff1a; 【WebRTC】【Unity】Unity Web RTC1-Unity中简单实…

Docker架构及常用的命令

一、初识Docker 1、 docker是一个快速交付应用、运行应用的技术&#xff0c;具备下列优势&#xff1a; 可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以…

边缘智能网关如何应对环境污染难题

随着我国工业化、城镇化的深入推进&#xff0c;包括大气污染在内的环境污染防治压力继续加大。为应对环境污染防治难题&#xff0c;佰马综合边缘计算、物联网、智能感知等技术&#xff0c;基于边缘智能网关打造环境污染实时监测、预警及智能干预方案&#xff0c;可应用于大气保…

银行数据分析入门篇:信用卡全生命周期分析,到底应该怎么做?

最近有朋友向我咨询银行信贷业务的数据分析&#xff0c;就看了很多案例&#xff0c;刚好看到一个信用卡全生命周期分析的案例&#xff0c;做得很详细又通俗易懂&#xff0c;基本上可以直接复制套用&#xff0c;所以特地分享给大家。 本文主要分享作者整个分析作品的思路&#x…

106.进程控制(结束、孤儿、僵尸进程)以及进程回收

目录 结束进程 孤儿进程 僵尸进程 进程回收 wait() waitpid 进程控制是指在操作系统中对进程进行创建、终止、挂起、唤醒以及进程之间的同步、通信等操作的管理。 结束进程 exit() 和 _exit() 函数都用于终止一个进程&#xff0c;但它们之间有一些重要的区别&#xf…

新工科:数据科学与大数据技术实验中心解决方案,赋能高校新工科数智人才培养

随着数字经济蓬勃发展&#xff0c;数字化产业和产业数字化成为就业增长新动能。据人瑞人才与德勤调研显示&#xff0c;未来3年&#xff0c;数字产业化企业最需要运营人员和开发人员&#xff08;包括大数据开发工程师、数据建模开发工程师等&#xff09;&#xff0c;其次是数据分…

【RTOS学习】FreeRTOS中的链表 | 堆的管理

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f969;FreeRTOS中的链表&#x1f95e;初始化&#x1f95e;尾部插入&#x1f95e;按顺…

OpenWRT搭建本地web站点并结合内网穿透实现公网远程访问

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…

【Windows】MCSM面板搭建Mycraft服务器,实现公网远程联机

文章目录 前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口 5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 前言 MCSManager是一个…

[香橙派]Orange pi zero 3命令行配网方法——建立ssh连接——Ubuntu配置WIFI自动连接

一、前言 前面我们给Orange Pi安装了Ubuntu系统&#xff0c;并通过MobaXterm进行了串口连接&#xff0c;但其实并不方便&#xff0c;在日常开发中&#xff0c;我们希望能够使用更方便的ssh连接来进行操作&#xff0c;因此配置网络是必要的。 本章介绍的方法无需网线、HDMI线等&…

upload-labs

01 随便上传个文件 发现对于上传类型有限制 查看页面代码发现是js的过滤直接关闭js 上传成功 右键图片在新建标签页打开文件 这里直接抓包改名字也行 02 抓包修改后缀名 03 发现后端做了检测抓包修改失败 大小写绕过失败&#xff0c;php特性php1等会被当成php执行 这里图片的…

MS1242,替代ADS1242,24bit 高精度、低功耗模数转换器

产品简述 MS1242/MS1243 是一款高精度、宽动态范围、 ∆-Σ 模数转 换芯片&#xff0c;其工作电压为 2.7V 至 5.25V &#xff0c;可以达到 24bit 无失码转 换&#xff0c;有效精度可达 21bit 。 MS1242/MS1243 可以广泛使用在工 业控制、称重、液体 / 气体化学分析、血液分…

手眼标定 - 最终精度和误差优化心得

手眼标定 - 标定误差优化项 一、TCP标定误差优化1、注意标定针摆放范围2、TCP标定时的点次态与工作姿态尽可能保持相近 二、深度相机对齐矩阵误差1、手动计算对齐矩阵 三、手眼标定拍照姿态1、TCP标定姿态优先2、水平放置棋盘格优先 为减少最终手眼标定的误差&#xff0c;可做或…