FFmpeg-aac、h264封装flv及时间转换

文章目录

      • 时间概念
      • 流程
      • api
      • 核心代码

时间概念

dts: 解码时间戳, 表示压缩帧的解码时间
pts: 显示时间戳, 表示将压缩帧解码后得到的原始帧的显示时间
时间基: time_base , 通常以ms为单位
时间戳: timestamp , 多少个时间基
真实时间:time_base * timestamp

如一个视频帧的dts为40(时间戳) ,time_base:1/1000s
真实时间: 40 * 1/1000 s

ffmpeg/ffplay命令参数:
tbr: 通常为帧率
tbn: 视频流的时间基
tbc: 视频解码的时间基

ffmepg内部时间基:
#define AV_TIME_BASE 1000000 //微妙

时间转换
av_q2d():将时间从AVRational(分数)形式转换为double形式

static inline double av_q2d(AVRational a){return a.num / (double) a.den;
}

时间基转换函数
av_rescale_q() :⽤于将时间值从⼀种时间基转换为另⼀种时间基
av_rescale_rnd():用于时间取整
av_packet_rescale_ts:⽤于将AVPacket中各种时间值从⼀种时间基转换为另⼀种时间基

1 视频流

转封装过程中的时间基转换

AVStream.time_base是AVPacket中pts和dts的时间单位

  • 对于输⼊流:打开输⼊⽂件后,调⽤avformat_find_stream_info()可获取到每个流中的time_base
  • 对于输出流:打开输出⽂件后,调⽤avformat_write_header()可根据输出⽂件封装格式确定每个流的time_base并写⼊输出⽂件中

转码过程中的时间基转换

编解码器中的时间基为 AVCodecContext.time_base,值为帧率(视频帧)的倒数

解码视频帧:

时间基为 1/framerate

  • 视频解码过程中的时间基转换处理:
    若从av_read_frame读取的packet,是以AVSteam->time_base,是avcodec_receive_frame后以AVSteam->time_base为准
  • 视频编码过程中的时间基转换处理:
    编码的时候frame如果以AVstream为time_base送编码器,
    则avcodec_receive_packet读取的时候也是以转成AVSteam->time_base

2 视频流

解码后的原始视频帧时间基为 1/framerate

流程

首先生成一个h264和aac,封装为flv add_stream函数类似编码过程
请添加图片描述

api

  • avformat_write_header : 写⽂件头
  • av_write_frame/av_interleaved_write_frame: 写packet
  • av_write_trailer : 写⽂件尾
  • avcodec_parameters_from_context: 将AVCodecContext结构体中码流参数拷⻉到AVCodecParameters结构体中
  • int avformat_alloc_output_context2 – 根据filename申请上下文
  • AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) // 新增流通道
 int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat,const char *format_name, const char *filename) {}        ctx:需要创建的context,返回NULL表示失败format:指定对应的AVOutputFormatformat_name: 指定⾳视频的格式,⽐如“flv”,“mpeg”等,如果设置为NULL,则由filename进⾏指定,让ffmpeg⾃⼰推断filename: 指定⾳视频⽂件的路径

核心代码

命令行参数: test.flv aac h264创建流生成

如何转换时间time_base:
open_audio: 关联编码器,会设置codec_ctx->time_base
avformat_write_header: base_time 转化为 1/1000

write_audio_frame中调用write_frame,pts会进行转化
如采样率44.1hz , pts_after = pts_before(-1024) * 1/44100 * 1000 = -23

//输出⽂件容器格式,生成flv文件,对应的ffmepg的源文件为flvenc.c
AVOutputFormat ff_flv_muxer = {.name           = "flv",.long_name      = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),.mime_type      = "video/x-flv",.extensions     = "flv",.priv_data_size = sizeof(FLVContext),.audio_codec    = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF,.video_codec    = AV_CODEC_ID_FLV1,.init           = flv_init,.write_header   = flv_write_header,.write_packet   = flv_write_packet,.write_trailer  = flv_write_trailer,.check_bitstream= flv_check_bitstream,
};static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
{int ret;AVCodecContext *codec_ctx;AVFrame *frame;int got_packet = 0;AVPacket pkt = { 0 };codec_ctx = ost->enc;frame = get_video_frame(ost);av_init_packet(&pkt);/* encode the image */avcodec_encode_video2(codec_ctx, &pkt, frame, &got_packet);if (got_packet){ret = write_frame(oc, &codec_ctx->time_base, ost->st, &pkt);}else{ret = 0;}if (ret < 0){fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret));exit(1);}return (frame || got_packet) ? 0 : 1;
}int main(int argc, char **argv)
{OutputStream video_st = { 0 }; // 封装视频编码相关的OutputStream audio_st = { 0 }; // 封装音频编码相关的const char *filename;   // 输出文件// AVOutputFormat ff_flv_muxerAVOutputFormat *fmt;    // 输出文件容器格式, 封装了复用规则,AVInputFormat则是封装了解复用规则AVFormatContext *oc;AVCodec *audio_codec, *video_codec;int ret;int have_video = 0, have_audio = 0;int encode_video = 0, encode_audio = 0;AVDictionary *opt = NULL;int i;filename = argv[1];/* 分配AVFormatContext并根据filename绑定合适的AVOutputFormat */avformat_alloc_output_context2(&oc, NULL, NULL, filename);fmt = oc->oformat; // 获取绑定的AVOutputFormat// 我们音视频课程音视频编解码主要涉及H264和AAC, 所以我们指定为H264+AACfmt->video_codec = AV_CODEC_ID_H264;    // 指定编码器fmt->audio_codec = AV_CODEC_ID_AAC;     // 指定编码器/* 使用指定的音视频编码格式增加音频流和视频流 */if (fmt->video_codec != AV_CODEC_ID_NONE){add_stream(&video_st, oc, &video_codec, fmt->video_codec);have_video = 1;encode_video = 1;}if (fmt->audio_codec != AV_CODEC_ID_NONE){add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec);have_audio = 1;encode_audio = 1;}if (have_video)open_video(oc, video_codec, &video_st, opt);if (have_audio)open_audio(oc, audio_codec, &audio_st, opt);/* open the output file, if needed */if (!(fmt->flags & AVFMT_NOFILE)){// 打开对应的输出文件,没有则创建avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);}// audio AVstream->base_time = 1/44100, video AVstream->base_time = 1/25// base_time audio = 1/1000 video = 1/1000avformat_write_header(oc, &opt);while (encode_video || encode_audio){/* select the stream to encode */if (encode_video &&         // video_st.next_pts值 <= audio_st.next_pts时(!encode_audio || av_compare_ts(video_st.next_pts, video_st.enc->time_base,audio_st.next_pts, audio_st.enc->time_base) <= 0)) {printf("\nwrite_video_frame\n");encode_video = !write_video_frame(oc, &video_st);}else{printf("\nwrite_audio_frame\n");encode_audio = !write_audio_frame(oc, &audio_st);}}av_write_trailer(oc);/* Close each codec. */if (have_video)close_stream(oc, &video_st);if (have_audio)close_stream(oc, &audio_st);if (!(fmt->flags & AVFMT_NOFILE))avio_closep(&oc->pb);avformat_free_context(oc);return 0;
}

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

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

相关文章

谷歌(edge)浏览器过滤,只查看后端发送的请求

打开F12 调试工具 选择Network 这是我们会发现 什么图片 文件 接口的请求很多很多&#xff0c;我们只需要查看我们后端发送的请求是否成功就好了 正常情况我们需要的都是只看接口 先点击这里这个 过滤 我们只需要点击 Fetch/XHR 即可过滤掉其他请求信息的展示 这样烦恼的问题就…

vulhub中GitLab 远程命令执行漏洞复现(CVE-2021-22205)

GitLab是一款Ruby开发的Git项目管理平台。在11.9以后的GitLab中&#xff0c;因为使用了图片处理工具ExifTool而受到漏洞CVE-2021-22204的影响&#xff0c;攻击者可以通过一个未授权的接口上传一张恶意构造的图片&#xff0c;进而在GitLab服务器上执行任意命令。 环境启动后&am…

ChatGPT提示词方法的原理

关于提示词&#xff0c;我之前的一些文章可以参考&#xff1a; 【AIGC】AI作图最全提示词prompt集合&#xff08;收藏级&#xff09;https://giszz.blog.csdn.net/article/details/134815245?ydrefereraHR0cHM6Ly9tcC5jc2RuLm5ldC9tcF9ibG9nL21hbmFnZS9hcnRpY2xlP3NwbT0xMDExL…

Tomcat Seeion 集群

部署&#xff1a;nginx服务器&#xff1a;11-11&#xff1b;tomcat1:11-3; tomcat2:11-6 nginx服务器11-11做搭建&#xff1a; [rootmcb-11 ~]# systemctl stop firewalld [rootmcb-11 ~]# setenforce 0 [rootmcb-11 ~]# yum install epel-release.noarch -y [rootmcb…

华为三层交换机:ACL的基本实验

实验要求&#xff1a; PC1不允许访问PC3&#xff0c;PC3可以访问PC1 分析问题&#xff1a; PC1不允许访问PC3&#xff0c;问题中含有“目标地址”则我们需要设置目标地址&#xff0c;这样基本ACL是不行的&#xff0c;必须使用高级ACL [sw1]acl ? INTEGER<2000-2999>…

Flutter 多语言自动化本地化生成器

Flutter 多语言自动化本地化生成器 这是一个为Flutter设计的插件&#xff0c;通过从Excel表格提取的CSV文件自动生成Dart本地化文件&#xff0c;以简化应用程序本地化的流程。这个工具通过自动化创建多语言资源文件&#xff0c;简化了开发人员和翻译人员的工作流程。 录屏2024…

网络学习:邻居发现协议NDP

目录 前言&#xff1a; 一、报文内容 二、地址解析----NS/NA 目标的被请求组播IP地址 邻居不可达性检测&#xff1a; 重复地址检测 路由器发现 地址自动配置 默认路由器优先级和路由信息发现 重定向 前言&#xff1a; 邻居发现协议NDP&#xff08;Neighbor Discovery…

论文阅读——Rein

Stronger, Fewer, & Superior: Harnessing Vision Foundation Models for Domain Generalized Semantic Segmentation 一、引言 是一个对Domain Generalized Semantic Segmentation (DGSS)任务的视觉大模型的微调方法&#xff0c;即Rein。 Rein 专为 DGSS 任务量身定制&a…

数据结构——lesson8二叉树的实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

【玩转pandas系列】pandas数据结构—DataFrame

文章目录 前言一、DataFrame创建1.1 字典创建1.2 NumPy二维数组创建 二、DataFrame切片2.1 行切片2.2 列切片2.3 行列切片 三、DataFrame运算3.1 DataFrame和标量的运算3.2 DataFrame之间的运算3.3 Series和DataFrame之间的运算 四、DataFrame多层次索引4.1 多层次索引构造1.隐…

软考高级:架构描述语言 ADL 概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

【Linux】Ubuntu使用Netplan配置静态/动态IP

1、说明 Ubuntu 18.04开始,Ubuntu和Debian移除了以前的ifup/ifdown命令和/etc/network/interfaces配置文件,转而使用ip link set或者/etc/netplan/01-netcfg.yaml模板和sudo netplan apply命令实现网络管理。 Netplan 是抽象网络配置描述器,用于配置Linux网络。 通过netpla…

旧华硕电脑开机非常慢 电脑开机黑屏很久才显示品牌logo导致整体开机速度非常的慢怎么办

前提条件 电池需要20&#xff05;&#xff08;就是电池没有报废&#xff09;且电脑接好电源&#xff0c;千万别断电&#xff0c;电脑会变成砖头的 解决办法 更新bios即可解决&#xff0c;去对应品牌官网下载最新的bios版本就行了 网上都是一些更新驱动啊

【Godot4.2】颜色完全使用手册

概述 本篇简单汇总Godot中的颜色的构造和使用&#xff0c;内容包括了&#xff1a; RGB、RGBA&#xff0c;HSV以及HTML16进制颜色值、颜色常量等形式构造颜色颜色的运算以及取反、插值用类型化数组、紧缩数组或PNG图片形式存储多个颜色 构造颜色 因为颜色是一种视觉元素&…

8-图像缩放

其实&#xff0c;就是开辟一个zoomwidth&#xff0c;zoomheight的内存&#xff0c;再分别赋值即可。 void CDib::Scale(float xZoom, float yZoom) { //指向原图像指针 LPBYTE p_data GetData(); //指向原像素的指针 LPBYTE lpSrc; //指向缩放图像对应像素的指针 LPBYTE lpDs…

基于grafana+elk等开源组件的 云服务监控大屏架构

本套大屏,在某云服务大规模测试环境,良好运行3年. 本文主要展示这套监控大屏的逻辑架构.不做具体操作与配置的解释. 监控主要分为三部分: 数据展示部分数据存储数据采集 1. 数据展示 数据展示方面主要使用grafana 2. 数据存储 根据数据种类和特性和用途的不同,本套监控采用…

Mysql的行级锁

MySQL 中锁定粒度最小的一种锁&#xff0c;是 针对索引字段加的锁 &#xff0c;只针对当前操作的行记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小&#xff0c;并发度高&#xff0c;但加锁的开销也最大&#xff0c;加锁慢&#xff0c;会出现死锁。行级锁和存…

Vue项目的搭建

Node.js 下载 Node.js — Download (nodejs.org)https://nodejs.org/en/download/ 安装 测试 winR->cmd执行 node -v配置 在安装目录下创建两个子文件夹node_cache和node_global,我的就是 D:\nodejs\node_cache D:\nodejs\node_global 在node_global文件下再创建一个…

ArkTS 基础组件

目录 一、常用组件 二、文本显示&#xff08;Text/Span) 2.1 创建文本 2.2 属性 2.3 添加子组件(Span) 2.4 添加事件 三、按钮&#xff08;Button&#xff09; 3.1 创建按钮 3.2 设置按钮类型 3.3 悬浮按钮 四、文本输入&#xff08;TextInput/TextArea&#xff09;…

Flask学习(四):路由转换器

默认的路由转换器&#xff1a; string &#xff08;缺省值&#xff09; 接受任何不包含斜杠的文本int接受正整数float接受正浮点数 path类似 string&#xff0c;但可以包含斜杠uuid接受 UUID 字符串 代码示例&#xff1a; app.route(/user/<username>) def show_u…