首页 > 其他分享 >FFmpeg-aac、h264封装flv及时间转换

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

时间:2024-03-17 19:59:55浏览次数:36  
标签:FFmpeg aac h264 write base video time audio codec

文章目录

时间概念

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:指定对应的AVOutputFormat
 format_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_muxer
    AVOutputFormat *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+AAC
    fmt->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/1000
    avformat_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;
}

标签:FFmpeg,aac,h264,write,base,video,time,audio,codec
From: https://blog.csdn.net/qq_43538607/article/details/136732850

相关文章

  • ffmpeg avformat_alloc_context System.NotSupportedException 不支持所指定的方法
    这个错误报了第二次了,网上搜不到靠谱的解决方案,赶快记录一下。第一个情况:报错如题目System.NotSupportedException不支持所指定的方法第二个情况:如果换autogen版本的话,我是用的5.1.2.3,切换到5.0或者其他版本的话,会提示avformat.59dllnotfound。这个报错根本原因是没找到对......
  • centos7安装ffmpeg
     CentOS7系统默认不包含FFmpeg工具,但可以通过安装第三方YUM源来安装。以下是安装FFmpeg的步骤:升级yum:sudoyuminstallepel-release-ysudoyumupdate-y安装NuxDextopYum源:sudorpm--importhttp://li.nux.ro/download/nux/RPM-GPG-KEY-nux.rosudorpm-Uvh......
  • FFmpeg开发笔记(六)如何访问Github下载FFmpeg源码
    ​学习FFmpeg的时候,经常要到GitHub下载各种开源代码,比如FFmpeg的源码页面位于https://github.com/FFmpeg/FFmpeg。然而国内访问GitHub很不稳定,经常打不开该网站,比如在命令行执行下面的ping命令。pinggithub.com上面的ping结果如下所示,可见默认解析的DNS地址连接超时。正在......
  • FFmpeg开发笔记(五)更新MSYS的密钥环
    ​ 《FFmpeg开发实战:从零基础到短视频上线》一书提到:使用MSYS对FFmpeg进行交叉编译时,需要事先安装交叉编译工具链,也就是执行下面命令。pacman-Smingw-w64-x86_64-toolchain一般情况可以正常安装交叉编译工具链,不过有时会提示错误“signaturefrom"DavidMacek<david.mace......
  • FFmpeg命令视频音频转码参数详解
    前言全局说明FFmpeg命令转码参数详解一、参数1.1FFmpeg常用参数参数说明备注-ifilename指定输入文件(或直接写文件名,用|竖线分割),在Linux下当然也能指定:0.0(屏幕录制)或摄像头。-c:v指定视频编码器copy、libx265-crf指定视频质量,范围为0-51,0为无损,23......
  • ffmpeg aiv转mp4
    MOV0001.AVI436Mffmpeg-y-iMOV00001.AVI-c:vlibx264-crf30-presetslow-c:aaac-b:a44k-ac21.mp4转换后130M-preset:指定编码的配置。x264编码算法有很多可供配置的参数,不同的参数值会导致编码的速度大相径庭,甚至可能影响质量。为了免去用户了解算法,然后手工配......
  • ffmpeg多路视频合并
    2,3,4路视频拼接可以参考下面:https://blog.csdn.net/tianshan2010/article/details/104737576https://blog.csdn.net/Gary__123456/article/details/887427054路拼接【上下左右】:ffmpeg-i1.mp4-i2.mp4-i3.mp4-i4.mp4-filter_complex"[0:v]pad=iw2:ih2[a];[a][1:v]ove......
  • window下使用Cygwin编译ffmpeg步骤和问题记录
    window下使用Cygwin编译ffmpeg步骤和问题记录1.编译环境搭建安装Cygwin到Cygwin官网下载Cygwin的可执行程序setup-x86_64.exe官网地址:https://cygwin.com/install.html安装包地址:https://cygwin.com/setup-x86_64.exe安装操作很简单,基本是下一步,下一步就可以安装过程中,......
  • Qt/C++音视频开发69-保存监控pcm音频数据到mp4文件/监控录像/录像存储和回放/264/265/
    一、前言用ffmpeg做音视频保存到mp4文件,都会遇到一个问题,尤其是在视频监控行业,就是监控摄像头设置的音频是PCM/G711A/G711U,解码后对应的格式是pcm_s16be/pcm_alaw/pcm_mulaw,将这个原始的音频流保存到mp4文件是会报错的,在调用avformat_write_header写文件头的时候提示(-22)Invali......
  • isaac sim 常用记录
    目录常用函数常用demotask类controller类结合写好的task和cotroller常用函数添加usd资产prim_path='/World/warehouse'usd_path='/home/linhai/app/isaac/Collected_warehouse_with_forklifts/warehouse_with_forklifts.usd'stage_utils.add_ref......