当前位置: 首页 > news >正文

FFmpeg常用API与示例(四)——过滤器实战

1.filter

在多媒体处理中,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%

offplay input.mp3 -af atempo=0.5

过滤器链(Filterchain)

Filterchain = 逗号分隔的一组 filter

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

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

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

过滤器图(Filtergraph)

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

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

第二步:源视频水平翻转

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

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

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

是不是很复杂?

用带有链接标记的过滤器图(Filtergraph)只需一条命令

基本语法

Filtergraph = 分号分隔的一组 filterchain

“filterchain1;filterchain2;…filterchainN-1;filterchainN”

Filtergraph 的分类

1、简单(simple) 一对一

2、复杂(complex)多对一, 多对多

过滤器图处理流程:

在这里插入图片描述

对于刚才用三步处理的方式,用过滤器图可以这样做:

ffplay -f lavfi -i testsrc -vf split[a][b];[a]pad=2*iw[1];[b]hflip[2];[1][2]overlay=w

F1: split 过滤器创建两个输入文件的拷贝并标记为[a],[b]

F2: [a]作为 pad 过滤器的输入,pad 过滤器产生 2 倍宽度并输出到[1].

F3: [b]作为 hflip 过滤器的输入,vflip 过滤器水平翻转视频并输出到[2].

F4: 用 overlay 过滤器把 [2]覆盖到[1]的旁边.

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

  • FilterGraph, AVFilterGraph

  • InputFilter, InputStream, OutputFilter, OutputStream

  • AVFilter, AVFilterContext

  • AVFilterLink

  • AVFilterPad;

2.DirectShow

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

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

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

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

在这里插入图片描述

DirectShow 的架构如下图所示:

在这里插入图片描述

/*** @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;if (argc != 2) {fprintf(stderr, "Usage: %s file\n", argv[0]);exit(1);}g__file_fd = fopen("yuv888.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(argv[1])) < 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);
}

相关文章:

FFmpeg常用API与示例(四)——过滤器实战

1.filter 在多媒体处理中&#xff0c;filter 的意思是被编码到输出文件之前用来修改输入文件内容的一个软件工具。如&#xff1a;视频翻转&#xff0c;旋转&#xff0c;缩放等。 语法&#xff1a;[input_link_label1]… filter_nameparameters [output_link_label1]… 1、视…...

解决springboot项目的网站静态页面显示不全问题

在通过springboot搭建项目时&#xff0c;为了能够访问静态的前端页面&#xff0c;我们考虑到访问的优先级问题&#xff0c;通常选择将资源放在recourses/static的目录下&#xff0c;如下&#xff1a; 这时可能会出现类似于下面这种图片无法加载、没有按照指定位置显示的情况&am…...

表面的相似,本质的不同

韩信与韩王信&#xff0c;两个韩信的结局都是被刘邦所杀&#xff0c;似乎结局类似。但是&#xff0c;略加分析&#xff0c;就会发现其中存在本质的区别。 韩信属于必杀。他的王位是要来的&#xff0c;有居功自傲的本意&#xff0c;功高震主而且毫不避讳。而且年轻&#xff0c;…...

问题:幂等性 分布式session

web项目中请求线程到service层的时候远程调用服务之前是串行化执行每个任务都要get阻塞等待任务完成&#xff0c;举例当用户在购物车页面点击去结算就会请求后台toTrade请求获取订单确认的详情数据并渲染到订单详情页&#xff0c;现在在toTrade请求中使用异步任务编排Completab…...

Golang | Leetcode Golang题解之第66题加一

题目&#xff1a; 题解&#xff1a; func plusOne(digits []int) []int {n : len(digits)for i : n - 1; i > 0; i-- {if digits[i] ! 9 {digits[i]for j : i 1; j < n; j {digits[j] 0}return digits}}// digits 中所有的元素均为 9digits make([]int, n1)digits[0]…...

c++ STL 之栈—— stack 详解

vector 是 stl 的一个关联容器,名叫“栈”&#xff0c;何为“栈”&#xff1f;其实就是一个数组&#xff0c;但有了数组何必还需栈&#xff0c;这是一个高深的问题。 一、简介 1. 定义 栈&#xff0c;是一个柔性数组&#xff08;可变长数组&#xff09;&#xff0c;可以变大变小…...

鸿蒙开发接口Ability框架:【(窗口扩展能力)】

窗口扩展能力 WindowExtensionAbility基于ExtensionAbility&#xff0c;WindowExtensionAbility中展示的内容作为一个控件(AbilityComponent)内容展示在其他应用窗口中&#xff0c;实现在一个窗口中展示多个应用程序内容的功能。 说明&#xff1a; 本模块首批接口从API versio…...

AutoCAD中密集的填充打散后消失的问题

有时候在AutoCAD中&#xff0c;图案填充的填充面积过大或填充太过密集时&#xff0c;将该填充打散&#xff0c;也就是执行Explode时&#xff0c;会发现填充图案消失了。 原因是打散后线条太大&#xff0c;系统就不显示了。可以通过设置&#xff1a;HPMAXLINES 值&#xff0c;来…...

基于Matplotlib的模型性能可视化工作

一、项目简介 本项目是科技考古墓葬识别工作的中间过程&#xff0c;因为需要大量复用所以另起一章好了。 主要涉及到数据读取、数据可视化和少量的数据处理过程。 二、相关知识 PandasMatplotlib 三、实验过程 1. 数据探索性分析 1.1 准备工作–导入模块 import pandas…...

KAN网络最全解析——比肩MLP和Transformer?

1 基本思路 1.1 MLP与Spline的优缺点 多层感知器 (MLP)是深度学习的基础理论模块&#xff0c;是目前可用于逼近非线性函数的默认模型&#xff0c;其表征能力已由通用逼近定理证明。但MLP也有明显的缺点&#xff0c;例如在 Transformer中&#xff0c;MLP 的参数量巨大&#xf…...

ASP.NET学生信息管理系统

摘 要 本文介绍了在ASP.net环境下采用“自上而下地总体规划&#xff0c;自下而上地应用开发”的策略开发一个管理信息系统的过程。通过分析某一学校学生管理的不足&#xff0c;创建了一套行之有效的计算机管理学生的方案。文章介绍了学生管理信息系统的系统分析部分&#xff0c…...

图片改大小尺寸怎么改?几招教你搞定图片修改

在社交媒体平台上发布图片时&#xff0c;调整图片的尺寸大小可以确保图片适合平台的要求&#xff0c;不同的社交媒体平台可能对图片的尺寸有不同的要求&#xff0c;通过调整图片尺寸&#xff0c;可以更加完美的展现出来&#xff0c;那么有没有比较简单的图片改大小的方法呢&…...

Scala编程入门:从零开始的完整教程

目录 引言环境准备创建第一个Scala项目基本语法高阶概念进阶资源结语 引言 Scala是一种强大的、静态类型的、多范式编程语言&#xff0c;它结合了面向对象和函数式编程的特点。本教程将指导您如何从零开始学习Scala&#xff0c;并搭建一个简单的开发环境。让我们开始探索Scala…...

Proxmox VE 8 SDN创建VLAN隔离用户网络

作者&#xff1a;田逸&#xff08;formyz&#xff09; 在上一篇文章中&#xff0c;我们用SDN的Simple对租户&#xff08;用户&#xff09;网络实现了隔离功能&#xff0c;但它有个限制&#xff0c;仅仅能在单个物理节点上进行通信&#xff0c;而不能跨越物理节点&#xff08;除…...

API低代码平台介绍3-异构数据源的数据查询功能

异构数据源的数据查询功能 在上一篇文章中我们通过API平台定义了一个最基本的数据查询接口&#xff0c;本篇文章我们将上升难度&#xff0c;在原有接口的基础上&#xff0c;实现在MySQL数据库和Oracle数据库同时进行数据查询。   什么场景会需要同时对异构数据源进行查询&…...

【Linux】-网络请求和下载、端口[6]

目录 一、网络请求和下载 1、ping命令 2、wget命令 3、curl命令 二、端口 1、虚拟端口 2、查看端口占用 一、网络请求和下载 1、ping命令 可以通过ping命令&#xff0c;检查指定的网络服务器是否可联通状态 语法&#xff1a;ping [ -c num ] ip或主机名 选项&…...

Github2024-05-10开日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-05-10统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4TypeScript项目4JavaScript项目1Lua项目1C项目1Rust项目1Dart项目1 RustDesk: 用Rust编写的开源远…...

2016-2021年全国范围的2.5m分辨率的建筑屋顶数据

一、论文介绍 摘要&#xff1a;大规模且多年的建筑屋顶面积&#xff08;BRA&#xff09;地图对于解决政策决策和可持续发展至关重要。此外&#xff0c;作为人类活动的细粒度指标&#xff0c;BRA可以为城市规划和能源模型提供帮助&#xff0c;为人类福祉带来好处。然而&#xf…...

Gitea 上传用户签名

在 Gitea 的用户管理部分&#xff0c;有一个 SSH 和 GPG 的选项。 单击这个选项&#xff0c;可以在选项上添加 Key。 Key 的来源 如是 Windows 的用户&#xff0c;可以选择 Kleopatra 这个软件。 通过这个软件生成的 Key 的界面中有一个导出功能。 单击这个导出&#xff0c;…...

【原创】springboot+mysql物资库存管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…...

如何用AnythingLLM打造你的智能文档聊天机器人:5大核心功能全解析

如何用AnythingLLM打造你的智能文档聊天机器人&#xff1a;5大核心功能全解析 【免费下载链接】anything-llm 这是一个全栈应用程序&#xff0c;可以将任何文档、资源&#xff08;如网址链接、音频、视频&#xff09;或内容片段转换为上下文&#xff0c;以便任何大语言模型&…...

OpenClaw故障自愈方案:百川2-13B模型异常日志分析与重试机制

OpenClaw故障自愈方案&#xff1a;百川2-13B模型异常日志分析与重试机制 1. 问题背景与需求场景 上周我在用OpenClaw对接百川2-13B模型处理夜间自动化任务时&#xff0c;遇到了一个典型问题&#xff1a;凌晨3点突然收到飞书告警&#xff0c;显示"模型响应超时"。当…...

3大实战技巧:专业级Python通达信数据接口深度应用指南

3大实战技巧&#xff1a;专业级Python通达信数据接口深度应用指南 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 在量化投资和金融数据分析领域&#xff0c;获取稳定、全面且经济的数据是开展工作…...

XUnity.AutoTranslator:打破Unity游戏语言壁垒的开源解决方案

XUnity.AutoTranslator&#xff1a;打破Unity游戏语言壁垒的开源解决方案 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 当你面对一款内容精彩但语言不通的Unity游戏时&#xff0c;是否曾因语言障碍而错…...

【BLE系列-第四篇】数据链路层(LL)实战:广播与连接参数优化指南

1. BLE数据链路层核心参数解析 低功耗蓝牙&#xff08;BLE&#xff09;的数据链路层&#xff08;LL&#xff09;就像交通系统中的红绿灯和道路规划&#xff0c;它决定了设备间如何高效、稳定地建立通信。在实际开发中&#xff0c;我经常遇到工程师对着几十个参数发愁&#xff1…...

嵌入式开发:裸机到OS的技术挑战与优化

嵌入式开发从裸机到操作系统的技术挑战分析1. 系统性能需求变化1.1 CPU运行速度要求嵌入式系统引入操作系统后&#xff0c;CPU需要承担额外的调度开销。实时控制系统通常需要1ms甚至更短的tick间隔来保证控制精度&#xff0c;这进一步增加了CPU的负担。现代32位微控制器的性能提…...

Ubuntu24.04上快速部署Odoo18开发环境的完整指南

1. 为什么选择Ubuntu24.04作为Odoo18开发环境 作为一个在ERP领域摸爬滚打多年的开发者&#xff0c;我强烈推荐使用Ubuntu24.04作为Odoo18的开发平台。这不仅仅是因为官方文档的建议&#xff0c;更是来自实际项目中的血泪教训。记得去年接手一个企业ERP项目时&#xff0c;客户坚…...

Windows下OpenClaw全流程指南:ollama GLM-4-7-Flash接入与技能扩展

Windows下OpenClaw全流程指南&#xff1a;ollama GLM-4-7-Flash接入与技能扩展 1. 为什么选择OpenClawGLM-4-7-Flash组合 去年我在处理日常办公自动化时&#xff0c;发现很多重复性工作既耗时又容易出错。尝试过各种RPA工具后&#xff0c;最终被OpenClaw的"AI智能体本地…...

别再只画流程图了!用AntV G6-Editor在Angular里搭建一个可交互的作业调度系统

用AntV G6-Editor在Angular中构建企业级作业调度可视化平台 当我们需要在Angular项目中实现复杂的作业调度系统时&#xff0c;传统的流程图工具往往难以满足业务需求。AntV G6-Editor作为专业级可视化编辑框架&#xff0c;提供了从基础绘图到深度定制的完整解决方案。本文将带你…...

OpenClaw+nanobot:个人学习计划智能生成与跟踪

OpenClawnanobot&#xff1a;个人学习计划智能生成与跟踪 1. 为什么需要AI驱动的学习计划助手 去年备考PMP认证时&#xff0c;我陷入了典型的学习规划困境&#xff1a;教材有600多页&#xff0c;模拟题库超过2000题&#xff0c;而我的备考时间只有8周。传统学习计划工具&…...