【FFMPEG应用篇】基于FFmpeg的转码应用(FLV MP4)
方法声明
extern "C" //ffmpeg使用c语言实现的,引入用c写的代码就要用extern
{
#include <libavcodec/avcodec.h> //注册
#include <libavdevice/avdevice.h> //设备
#include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
#include<iostream>class fcoverh264
{
public:fcoverh264(int number);//打开H264视频文件void openFile(std::string file);//根据我们需要的封装格式进行处理void outPut(std::string fileout);
private:AVFormatContext* forContext, * formatout;//保存数据的结构体 forContext存输入进来的视频信息;formatout存储最终输出的视频信息AVPacket* pkt;//pktint videoType;
};
定义实现
#include "fcoverh264.h"extern "C" //ffmpeg使用c语言实现的,引入用c写的代码就要用extern
{
#include <libavcodec/avcodec.h> //注册
#include <libavdevice/avdevice.h> //设备
#include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
fcoverh264::fcoverh264(int number):videoType(number)
{/** 转码的流程:* 1.注册组件* 2.打开视频流 打开视频文件* 3.查找有没有流数据* 4.查找视频码流数据** 6.根据要的封装格式 来猜测格式对应编辑器* 7.打开对应文件* 8.新建流* 9.写入头部信息* 10.读取一帧一帧的码流数据* 11.转码---->时间基的转化* 所以在解码的时候:显示顺序和解码的顺序是一样的;处理其他视频的时候:就需要关注 显示顺序和解码的顺序是否一致了编码有B帧? 解码:IPB* 12.写入对应的一帧数据到文件中*///注册组件av_register_all();forContext = avformat_alloc_context();}void fcoverh264::openFile(std::string file)
{//打开输入视频int res = avformat_open_input(&forContext, file.c_str(), nullptr, nullptr);//判断是否打开成功if (res < 0){std::cout << "打开失败"<<std::endl;return;}//打开视频文件成功,获取文件信息res = avformat_find_stream_info(forContext, nullptr);//查看有没有相关视频流信息if (res < 0)//判断是否有流媒体{std::cout << "没有流媒体信息" << std::endl;return;}//一个视频流有多股码流,存在forContentext中streams数组中/*int videoType = -1;*/for (int i = 0; i < forContext->nb_streams; i++) //i小于流的个数{if (forContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//视频流{videoType = i;//标识类型break;}}if (videoType == -1){std::cout << "没有视频流相关信息" << std::endl;return;}std::cout << "输入的准备已经完成"<<std::endl;
}//根据我们需要的封装格式进行处理
void fcoverh264::outPut(std::string fileout)
{//猜测编码器AVOutputFormat* avformat = av_guess_format(nullptr, fileout.c_str(), nullptr);if (avformat == nullptr){std::cout << "没有编码器!"<<std::endl;return;}std::cout << "AVOutputFormat"<<std::endl;//保存输出视频信息的结构体formatout = avformat_alloc_context();//设置输出格式formatout->oformat = avformat;//打开视频流 文件流//参数1:输入输出的上下文对象//参数2:文件流路径//参数3:文件打开格式 写的方式int res = avio_open(&formatout->pb, fileout.c_str(), AVIO_FLAG_WRITE);if (res < 0){std::cout << "open file error"<<std::endl;return;}std::cout << "avio_open"<<std::endl;//新建视频流//参数1:视频信息结构体//参数2:新建流 的 返回新建流 的地址AVStream* newStream = avformat_new_stream(formatout, nullptr);if (newStream == nullptr){std::cout << "打开视频流失败"<<std::endl;return;}std::cout << "newStream"<<std::endl;//编码器对应参数设置 拷贝参数设置 newStream:输入进入流的参数设置res = avcodec_parameters_copy(newStream->codecpar, forContext->streams[videoType]->codecpar);std::cout << "res=" << res<<std::endl;if (res < 0){std::cout << "拷贝失败!"<< std::endl;return;}std::cout << "res=" << res<<std::endl;//设置新的流里面 codec_tag 设置为0newStream->codecpar->codec_tag = 0;//头部信息写入----写入成功与否res = avformat_write_header(formatout, nullptr);//formatout封装格式的结构体//判断写入成功与否if (res < 0){std::cout << "写入头部信息失败!" <<std::endl;return;}std::cout << "res=" << res << std::endl;//开始读取码流数据pkt = (AVPacket*)malloc(sizeof(AVPacket));//算出这张图有多大int size = newStream->codecpar->width * newStream->codecpar->height;av_new_packet(pkt, size);int frameCount = 0;//一帧一帧的读取while (av_read_frame(forContext, pkt) == 0){//判断这一帧这是不是视频流if (pkt->stream_index == videoType){frameCount++;//如果是视频流----判断有没有设置过 时间基if (pkt->pts == AV_NOPTS_VALUE){//时间基 time_base AVRational属性AVRational timebase = forContext->streams[videoType]->time_base;//计算帧之间的长度(duration) double强制转换int64_t duration = (double)AV_TIME_BASE / av_q2d(forContext->streams[videoType]->r_frame_rate);//计算显示时间基(pts):公式:(当前帧数*两帧之间的长度))/(输入时间基*AV_TIME_BASE)pkt->pts = (double)(frameCount * duration) / (av_q2d(timebase) * AV_TIME_BASE);//解码时间基(dts)pkt->dts = pkt->pts;//目标两帧之间的长度pkt->duration = duration / (double)(av_q2d(timebase) * AV_TIME_BASE);}else if (pkt->pts < pkt->dts)//显示 时间基 小于 解码时间基 不要这样子的{continue;}//上述步骤为 时间基设置//解码 时间基 真正的转换 如下://显示时间基的转换pkt->pts = av_rescale_q_rnd(pkt->pts, forContext->streams[videoType]->time_base,newStream->time_base, (AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));//解码时间基的转换pkt->dts = av_rescale_q_rnd(pkt->dts, forContext->streams[videoType]->time_base,newStream->time_base, (AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));//数据时长设置pkt->duration = av_rescale_q(pkt->duration, forContext->streams[videoType]->time_base,newStream->time_base);//数据位置的设置 数据在流信息中的设置pkt->pos = -1;//数据包的标记:结合AV_PKT_FLAG_KEY使用 最小为1表示这一帧是一个关键帧pkt->flags |= AV_PKT_FLAG_KEY;//标记:当前写入的这一帧是视频流pkt->stream_index = 0;//转码后的数据包 写入 目标视频信息 结构体 中av_interleaved_write_frame(formatout, pkt);}//清空处理:重新设置包av_packet_unref(pkt);}//写入尾巴帧av_write_trailer(formatout);//用完之后进行 关闭 处理 :关闭猜测完的流avio_close(formatout->pb);//对应avio_open()std::cout << "avio_close"<<std::endl;//释放malloc的空间 释放保存信息的结构体av_free(formatout);std::cout << "av_free"<<std::endl;//关闭输入流avformat_close_input(&forContext);//对应avformat_open_inpustd::cout << "avformat_close_input"<<std::endl;//释放forContext结构体空间av_free(forContext);std::cout << "av_free"<<std::endl;
}
调用实例
#include <iostream>
#include "fcoverh264.h"int main() {fcoverh264* cover = new fcoverh264{-1}; //转码cover->openFile("test01.h264");cover->outPut("code_frame.flv");return 0;
}
相关文章:
【FFMPEG应用篇】基于FFmpeg的转码应用(FLV MP4)
方法声明 extern "C" //ffmpeg使用c语言实现的,引入用c写的代码就要用extern { #include <libavcodec/avcodec.h> //注册 #include <libavdevice/avdevice.h> //设备 #include <libavformat/avformat.h> #include <libavutil/…...
LInux初学之路linux的磁盘分区/远程控制/以及关闭图形界面/查看个人身份
虚拟机磁盘分配 hostname -I 查看ip地址 ssh root虚拟就ip 远程连接 win10之后才有 远程控制重新启动 reboot xshell 使用(个人和家庭版 免费去官方下载) init 3 关闭界面 减小内存使用空间 init 5 回复图形界面 runlevel显示的是状态 此时和上…...
Netty 介绍、使用场景及案例
Netty 介绍、使用场景及案例 1、Netty 介绍 https://github.com/netty/netty Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可扩展的网络服务器和客户端。它是一个开源项目,最初由JBoss公司开发,现在由社区维护。Netty的…...
小游戏选型(一):游戏化设计助力直播间互动和营收
一、社交直播间小游戏火爆 大家好,作为一个技术宅和游戏迷,今天来聊聊近期爆火的社交直播间小游戏的潮流。喜欢冲浪玩社交产品的小伙伴会发现,近期各大平台都推出了直播间社交小游戏,直播间氛围火爆,小游戏玩法简单&a…...
社区嵌入式服务设施建设为社区居家养老服务供给增加赋能
近年来,沈阳市浑南区委、区政府牢记在辽宁考察时的重要指示精神,认真践行以人民为中心的发展思想,聚集“一老一小”民生关切,统筹推进以社区为骨干结点的养老服务探索实践。围绕“品质养老”民生服务理念,针对社区老年…...
SpringBoot请求参数加密、响应参数解密
SpringBoot请求参数加密、响应参数解密 1.说明 在项目开发工程中,有的项目可能对参数安全要求比较高,在整个http数据传输的过程中都需要对请求参数、响应参数进行加密,也就是说整个请求响应的过程都是加密处理的,不在浏览器上暴…...
Mysql适配国产化数据库人大金仓冲突记录
1、mysql中查询中如果使用双引号,在人大金仓数据库中不支持,需改为单引号 例如: select 字段A,字段B,字段C from tableA where 字段A "1" 改为: select 字段A,字段B,字段…...
在微服务架构中认证和授权的那些事儿
在微服务架构中认证和授权是最基础的服务能力,其中这一块行业类的标准就是OAuth2 和 SSO ,而OAuth2 和 SSO 可以归类为“用户管理和身份验证”工具,OpenID Connect 1.0是 OAuth 2.0 协议之上的一个简单身份层。 Part.1 认识OAuth 2.0 OAuth…...
Git使用统一规范
为什么要统一git使用的风格? 统一的风格使我们在工作的时候无需考虑工作流程上该如何去做的问题,按照一个风格去做就好了每个人风格不同,格式凌乱,查看很不方便commit没有准确的message,后续难以追踪问题 git messag…...
如何在前端优化中处理大量的图像资源?
在前端优化中,处理大量的图像资源是一项重要的任务。由于图像占据了网站带宽的大部分,因此优化图像可以显著提高网站的性能和用户体验。下面将介绍一些在前端优化中处理大量图像资源的常见方法。 一、压缩图像 压缩图像是减少图像文件大小和优化图像的…...
【MYSQL】性能相关
SQL 语句的性能分析是一个非常重要的任务,尤其是在处理大数据时。下面是一些常用的 SQL 性能分析方法: 执行计划: 使用 EXPLAIN 命令来查看 SQL 语句的执行计划。这可以帮助你了解查询是如何被数据库执行的,从而发现可能的性能瓶颈。 注意&…...
【Jmeter之get请求传递的值为JSON体实践】
Jmeter之get请求传递的值为JSON体实践 get请求的常见传参方式 1、在URL地址后面拼接,有多个key和value时,用&链接 2、在Parameters里面加上key和value 第一次遇到value的值不是字符串也不是整型,我尝试把json放到value里面࿰…...
(1)(1.13) SiK无线电高级配置(六)
文章目录 前言 15 使用FTDI转USB调试线配置SiK无线电设备 16 强制启动加载程序模式 17 名词解释 前言 本文提供 SiK 遥测无线电(SiK Telemetry Radio)的高级配置信息。它面向"高级用户"和希望更好地了解无线电如何运行的用户。 15 使用FTDI转USB调试线配置SiK无线…...
用JAVA实现樱花飘落
用java实现一个樱花飘落的方法 package Text2;import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.List;public class Sakura extends JFrame {private List<Point> sakuraList; // 樱花的位置列表public Sakura() {sakuraList n…...
Web开发:SQLsugar的安装和使用
一、安装 第一步,在你的项目中找到解决方案,右键-管理解决方案的Nuget 第二步,下载对应的包,注意你的框架是哪个就下载哪个的包,一个项目安装一次包即可 点击应用和确定 安装好后会显示sqlsugar的包 二、使用…...
Redis面试题10
Redis 支持哪些数据结构? Redis 支持以下几种常用的数据结构: 字符串(String):用于存储字符串值,可以是文本或二进制数据。 列表(List):用于存储一个有序的字符串列表&am…...
arm64架构编译electron长征路
文章目录 1. gn工具生成1.1 问题,找不到last_commit_position.h文件问题描述如下:解决方法1.2 ninja文件不是对应架构问题问题描述:解决方法1.3 问题3:clang++找不到问题描述解决方法2. electron 编译参数生成2.1 下载对应版本debian_bullseye_arm64-sysroot错误描述...
建模软件Rhinoceros mac介绍说明
Rhinoceros mac是一款3D设计软件“犀牛”,在当今众多三维建模软件中,Rhinoceros 版因为其体积小、功能强大、对硬件要求低而广受欢迎,对于专业的3D设计人员来说它是一款不错的3D建模软件,Rhinoceros Mac中文版能轻易整合3DS MAX与…...
视频号下载小助手:教你微信视频号怎么提取视频出来
作为一名剪辑师或自由职业者,我们作为短视频创作者有时候需要下载多个视频用于制作多个解说系列的视频或者连续剧。然而,下载这些视频通常需要花费大量时间和精力,尤其是在没有合适的工具的情况下,让我们制作视频也确实困难,那么我们该如何解决呢&#x…...
C#-委托
委托类型 (delegate type) 表示对具有特定参数列表和返回类型的方法的引用。通过委托,我们能够将方法作为实体赋值给变量和作为参数传递。委托类似于在其他某些语言中的函数指针的概念,但是与函数指针不同,委托是面向对象的,并且是…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
