ffmpeg architecture(下)

第3章-转码

TLDR;给我看代码和执行。

  1. $ make run_transcoding

我们将跳过一些细节,但是请放心:源代码可在github上找到

在本章中,我们将创建一个用C编写的极简代码转换器,可以使用FFmpeg / libav库(尤其是libavcodec,libavformat和libavutil)将H264编码的视频转换为H265。

只是快速回顾一下:AVFormatContext是媒体文件格式的抽象,又名容器(例如:MKV,MP4,WEBM,TS)。的AV表示每种类型的用于给定格式(例如:音频,视频,字幕,元数据)的数据。所述AVPacket是从所获得的压缩数据的切片AVStream可以由一个解码avcodec:产生称为原始数据(例如AV1,H264,VP9,HEVC)AVFrame

转码

让我们从简单的转换操作开始,然后我们可以基于此代码构建,第一步是加载输入文件

  1. //分配一个AVFormatContext
  1. avfc = avformat_alloc_context();
  1. //打开输入流并读取标题。
  1. avformat_open_inputavfcin_filename NULL NULL);
  1. //读取媒体文件的数据包以获取流信息。
  1. avformat_find_stream_infoavfc NULL);

现在,我们要设置解码器,它AVFormatContext将使我们能够访问所有AVStream组件,并且对于每个组件,我们都可以获取它们AVCodec并创建特定组件AVCodecContext,最后我们可以打开给定的编解码器,以便继续进行解码处理。

所述AVCodecContext持有如比特率,帧速率,采样率,信道,高度,和许多其它有关的媒体数据的配置等。

  1. 对于(int i = 0 ; i <avfc-> nb_streams; i ++)
  1. {
  1.   AVStream * avs = avfc-> [i];
  1.   AVCodec * avc = avcodec_find_decoderavs-> codecpar- > codec_id);
  1.   AVCodecContext * avcc = avcodec_alloc_context3(* avc);
  1.  avcodec_parameters_to_context(* avccavs-> codecpar);
  1.  avcodec_open2(* avcc,* avcNULL);
  1. }

我们还需要准备输出媒体文件以进行多路传输,我们首先为输出分配内存AVFormatContext。我们以输出格式创建每个流。为了正确打包流,我们从解码器复制编解码器参数

我们设置标志 AV_CODEC_FLAG_GLOBAL_HEADER告诉编码器它可以使用全局头文件,最后打开输出文件进行写入并保留头文件。

  1. avformat_alloc_output_context2(&encoder_avfcNULLNULLout_filename);
  1. AVStream * avs = avformat_new_streamencoder_avfcNULL);
  1. avcodec_parameters_copyavs-> codecpar,解码器_avs-> codecpar);
  1. 如果(encoder_avfc-> oformat-> flagsAVFMT_GLOBALHEADER
  1.   encoder_avfc-> flags | = AV_CODEC_FLAG_GLOBAL_HEADER;
  1. avio_open(&encoder_avfc-> pb,编码器->文件名,AVIO_FLAG_WRITE);
  1. avformat_write_headerencoder- > avfc,&muxer_opts);

我们AVPacket从解码器获取,调整时间戳,并将数据包正确写入输出文件。即使函数av_interleaved_write_frame说“写帧”,我们仍在存储数据包。通过将流预告片写入文件中,我们完成了转换过程。

  1. AVFrame * input_frame = av_frame_alloc();
  1. AVPacket * input_packet = av_packet_alloc();
  1. 而(av_read_framedecoder_avfcinput_packet)> = 0
  1. {
  1.  av_packet_rescale_tsinput_packet,解码器_视频_avs-> time_base,编码器 _视频_avs- > time_base);
  1.  av_interleaved_write_frame(* avfcinput_packet)< 0));
  1. }
  1. av_write_trailerencoder_avfc);

转码

上一节展示了一个简单的transmuxer程序,现在我们将添加对文件进行编码的功能,尤其是使它能够将视频从转换h264h265

在准备好解码器之后,但在安排输出媒体文件之前,我们将设置编码器。

  1. AVRational input_framerate = av_guess_frame_ratedecoder_avfcdecoder_video_avsNULL);
  1. AVStream * video_avs = avformat_new_streamencoder_avfcNULL);
  1. char * codec_name = libx265 ;
  1. char * codec_priv_key = x265-params ;
  1. //我们将为x265使用内部选项
  1. // //禁用场景更改检测,然后修复
  1. // 60帧的GOP。
  1. char * codec_priv_value = keyint = 60min-keyint = 60scenecut = 0 ;
  1. AVCodec * video_avc = avcodec_find_encoder_by_namecodec_name);
  1. AVCodecContext * video_avcc = avcodec_alloc_context3video_avc);
  1. //编码器编解码器参数
  1. av_opt_setsc-> video_avcc-> priv_datacodec_priv_keycodec_priv_value 0);
  1. video_avcc-> height =解码器_ctx-> height;
  1. video_avcc-> width =解码器_ctx-> width;
  1. video_avcc-> pix_fmt = video_avc-> pix_fmts [ 0 ];
  1. //控制率
  1. video_avcc-> bit_rate = 2 * 1000 * 1000 ;
  1. video_avcc-> rc_buffer_size = 4 * 1000 * 1000 ;
  1. video_avcc-> rc_max_rate = 2 * 1000 * 1000 ;
  1. video_avcc-> rc_min_rate = 2.5 * 1000 * 1000 ;
  1. //时基
  1. video_avcc-> time_base = av_inv_qinput_framerate);
  1. video_avs-> time_base = sc-> video_avcc-> time_base;
  1. avcodec_open2sc-> video_avccsc-> video_avcNULL);
  1. avcodec_parameters_from_contextsc-> video_avs-> codecparsc-> video_avcc);

我们需要扩展解码循环以进行视频流转码:

  1. AVFrame * input_frame = av_frame_alloc();
  1. AVPacket * input_packet = av_packet_alloc();
  1. 而(av_read_framedecoder_avfcinput_packet)> = 0
  1. {
  1.  int响应= avcodec_send_packetdecoder_video_avccinput_packet);
  1.  while(响应> = 0){
  1.     响应= avcodec_receive_framedecoder_video_avccinput_frame);
  1.     if(响应== AVERROREAGAIN)|| response == AVERROR_EOF){
  1.        中断 ;
  1.     } else  ifresponse < 0){
  1.        返回响应;
  1.     }
  1.     if(响应> = 0){
  1.        编码(encoder_avfcdecoder_video_avsencoder_video_avsdecoder_video_avccinput_packet-> stream_index);
  1.     }
  1.     av_frame_unrefinput_frame);
  1.   }
  1.  av_packet_unrefinput_packet);
  1. }
  1. av_write_trailerencoder_avfc);
  1. //使用的函数
  1. int  编码(AVFormatContext * avfcAVStream * dec_video_avsAVStream * enc_video_avsAVCodecContext video_avcc int索引){
  1.   AVPacket * output_packet = av_packet_alloc();
  1.  int response = avcodec_send_framevideo_avccinput_frame);
  1.  while(响应> = 0){
  1.     响应= avcodec_receive_packetvideo_avccoutput_packet);
  1.     if(响应== AVERROREAGAIN)|| response == AVERROR_EOF){
  1.        中断 ;
  1.     } else  if(响应< 0){
  1.        return - 1 ;
  1.     }
  1.     output_packet-> stream_index = index ;
  1.     output_packet-> 持续时间 = enc_video_avs-> 那么time_baseden / enc_video_avs-> time_basenum / dec_video_avs-> avg_frame_ratenum * dec_video_avs-> avg_frame_rate。巢穴 ;
  1.     av_packet_rescale_tsoutput_packetdec_video_avs-> time_baseenc_video_avs-> time_base);
  1.     响应= av_interleaved_write_frameavfcoutput_packet);
  1.   }
  1.  av_packet_unrefoutput_packet);
  1.  av_packet_free(&output_packet);
  1.  返回 0 ;
  1. }

我们将媒体流从转换h264h265,正如预期的那样h265,媒体文件的版本小于,h264创建的程序能够:

  1.   / *
  1.     * H264-> H265
  1.    *音频->重混合(未触摸)
  1.    * MP4-MP4
  1. * /
  1.   StreamingParams sp = { 0 };   
  1.   sp.copy_audio = 1 ;
  1.   sp.copy_video = 0 ;
  1.   sp.video_codec = libx265 ”;
  1.  sp.codec_priv_key = x265-params ;
  1.   sp.codec_priv_value = keyint = 60min-keyint = 60scenecut = 0 ;
  1.  / *
  1.     * H264-> H264(固定gop
  1.    *音频->重混合(未触摸)
  1.    * MP4-MP4
  1. * /
  1.   StreamingParams sp = { 0 };   
  1.   sp.copy_audio = 1 ;
  1.   sp.copy_video = 0 ;
  1.  sp.video_codec = libx264 ”;
  1.   sp.codec_priv_key = x264参数” ;
  1.   sp.codec_priv_value = keyint = 60min-keyint = 60scenecut = 0force-cfr = 1 ;
  1.  / *
  1.     * H264-> H264(固定gop
  1.    *音频->重混合(
  1. 未修改)* MP4-    片段MP4
  1. * /
  1.   StreamingParams sp = { 0 };   
  1.   sp.copy_audio = 1 ;
  1.   sp.copy_video = 0 ;
  1.   sp.video_codec = libx264 ”;
  1.   sp.codec_priv_key = x264参数” ;
  1.   sp.codec_priv_value = keyint = 60min-keyint = 60scenecut = 0force-cfr = 1 ;
  1.   sp.muxer_opt_key = movflags ”;
  1.   sp.muxer_opt_value = frag_keyframe + empty_moov + default_base_moof ;
  1.  / *
  1.     * H264-> H264(固定gop
  1.    *音频-> AAC
  1.    * MP4-MPEG-TS
  1. * /
  1.   StreamingParams sp = { 0 };   
  1.   sp.copy_audio = 0 ;
  1.   sp.copy_video = 0 ;
  1.   sp.video_codec = libx264 ”;
  1.   sp.codec_priv_key = x264参数” ;
  1.   sp.codec_priv_value = keyint = 60min-keyint = 60scenecut = 0force-cfr = 1 ;
  1.   sp.audio_codec = aac ;
  1.   sp.output_extension = .ts ;
  1.  / * WIPP->它不在VLC上播放,最终比特率很高
  1.    * H264-> VP9
  1.    *音频-> Vorbis
  1.    * MP4-WebM
  1. * / // StreamingParams sp = {0}; // sp.copy_audio = 0; // sp.copy_video = 0; // sp.video_codec =“ libvpx-vp9”; // sp.audio_codec =“ libvorbis”; // sp.output_extension =“ .webm”;   
  1. 现在,说实话,这是难度比我想这会是我不得不挖掘到FFmpeg的命令行的源代码和测试了很多,我觉得我失去了一些东西,因为我不得不执行force-cfrh264工作而且我仍然看到一些警告消息,例如warning messages (forced frame type (5) at 80 was changed to frame type (3))

ffmpeg architecture(下)的更多相关文章

  1. ffmpeg architecture(中)

    ffmpeg architecture(中) 艰苦学习FFmpeg libav 您是否不奇怪有时会发出声音和视觉? 由于FFmpeg作为命令行工具非常有用,可以对媒体文件执行基本任务,因此如何在程序中 ...

  2. ffmpeg architecture(上)

    ffmpeg architecture(上) 目录 介绍 视频-您看到的是什么! 音频-您在听什么! 编解码器-缩小数据 容器-音频和视频的舒适场所 FFmpeg-命令行 FFmpeg命令行工具101 ...

  3. ffmpeg windows下编译ffmpeg

    windows下编译ffmpeg 今天由于工作需求需重新编译ffmpeg,百度,goole了一大堆,看眼花缭乱的,但几乎都是三种方案,大部分都是直接转发,一字不漏,错误的缺文件的还是照转,可是问题都大 ...

  4. FFmpeg Windows下安装与测试

    FFmpeg 简介 FFmpeg的名称来自MPEG视频编码标准,前面的"FF"代表"Fast Forward",FFmpeg是一套可以用来记录.转换数字音频.视 ...

  5. FFmpeg: mac下手动编译android上使用的FFmpeg(支持x86、armeabi-v7a、arm64-v8a)

    之前一直在linux下编译FFmpeg,最近换电脑了,尝试了下在mac下编译ffmpeg,特记录之. 一. 准备工作 1. 下载FFmpeg.(http://ffmpeg.org/download.h ...

  6. ffmpeg windows下编译安装

    安装msys2 更新源使下载速度更快 进入msys64/etc/pacman.d/目录中,分别在三个文件中增加mirrorlist.mingw32Server = http://mirrors.ust ...

  7. ffmpeg Windows下采集摄像头一帧数据,并保存为bmp图片

    这里请注意,在编译ffmpeg时,不要使用--disable-devices选项. 使用 --enable-encoder=rawvideo --enable-decoder=rawvideo 启用r ...

  8. [转载] ffmpeg Windows下采集摄像头一帧数据,并保存为bmp图片

    这里请注意,在编译ffmpeg时,不要使用--disable-devices选项. 使用 --enable-encoder=rawvideo --enable-decoder=rawvideo 启用r ...

  9. Linux下使用NDK编译FFMPEG(libstagefright)

    这个月要负责一个项目,使用FFMPEG渲染视频,主要是Android端的,由于性能要求,要使用硬解码,但网上大多数教程都是没有libstagefright的,所以个人觉得,生成的so库文件也是没有开启 ...

随机推荐

  1. Android系统自带的android.util.Base64的实现源码

    由于Android逆向还原的时候,经常需要用到android.util.Base64的代码,因此从Android 4.4.4的 系统里抠出来进行备份,懒得用其他的代码进行修改替换了. /* * Cop ...

  2. Windows核心编程 第六章 线程基础知识 (下)

    6.6 线程的一些性质 到现在为止,讲述了如何实现线程函数和如何让系统创建线程以便执行该函数.本节将要介绍系统如何使这些操作获得成功. 图6 - 1显示了系统在创建线程和对线程进行初始化时必须做些什么 ...

  3. NumPy中文文档搬砖(划掉)学习笔记(1)

    原文地址 前言 况下加速Python中的操作运行时.适用于快速数值运算的一个选项是NumPy,它当之无愧地将自己称为使用Python进行科学计算的基本软件包. 当然,很少有人将50微秒(百万分之五十秒 ...

  4. 大事件,Java被超越了,2021年5月TIOBE编程语言排行榜出炉

    TIOBE 头条 TIOBE 5月编程语言排行榜新鲜出炉.前十榜单中,C.Python.Java三大鳌头仍占据前三榜单.去年11月,Python短时间的挤掉Java跃居至榜单第二名:今年5月,Pyth ...

  5. 【JavaScript】Leetcode每日一题-组合总和4

    [JavaScript]Leetcode每日一题-组合总和4 [题目描述] 给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target .请你从 nums 中找出并返回总和为 targ ...

  6. 启动spring boot项目时报错:java.lang.ClassNotFoundException: javax.servlet.Filter

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...

  7. python三元(三目)运算

    传统的if,else写法 三元运算 name="alex" if 1==1 else "SB"

  8. 用 shell 脚本制造连接频繁中断的场景

    问题的提出 最近在准备客户端的新版本,在内部灰度过程中,发现一类奇怪的 dump,通过查看日志和堆栈,可以确定是因为每次连上后台就被后台断开了.导致多次重连后随机发生的崩溃.dump 和日志都无法提供 ...

  9. QFNU 10-30 training

    7-9 特立独行的幸福 题意:见PTA 思路:其实就是遍历进行查找,利用递归函数,为了解决是特立独行,还要用一个全局数组进行存储所有满足条件的数进行去重标记,最后在输出的时候进行判断是否是只读取过一次 ...

  10. ZOHO的下一个25年:用心为企业服务

    来源:中国软件网 作者:海策 在25周年会上,ZOHO大中华区总裁侯康宁先生豪情壮志,"25岁的ZOHO,已经成长为非典型一线大厂." 1996年,ZOHO成立.截止2021年,Z ...