ffmpeg architecture(下)

第3章-转码

TLDR;给我看代码和执行。

$ 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。

转码

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

//分配一个AVFormatContextavfc = avformat_alloc_context();//打开输入流并读取标题。avformat_open_input(avfc,in_filename, NULL,NULL);//读取媒体文件的数据包以获取流信息。avformat_find_stream_info(avfc, NULL);

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

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

对于(int i = 0 ; i nb_streams; i ++){ AVStream * avs = avfc-> 流 [i]; AVCodec * avc = avcodec_find_decoder(avs-> codecpar- > codec_id); AVCodecContext * avcc = avcodec_alloc_context3(* avc); avcodec_parameters_to_context(* avcc,avs-> codecpar); avcodec_open2(* avcc,* avc,NULL);}

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

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

avformat_alloc_output_context2(&encoder_avfc,NULL,NULL,out_filename); AVStream * avs = avformat_new_stream(encoder_avfc,NULL);avcodec_parameters_copy(avs-> codecpar,解码器_avs-> codecpar); 如果(encoder_avfc-> oformat-> flags和AVFMT_GLOBALHEADER) encoder_avfc-> flags | = AV_CODEC_FLAG_GLOBAL_HEADER; avio_open(&encoder_avfc-> pb,编码器->文件名,AVIO_FLAG_WRITE);avformat_write_header(encoder- > avfc,&muxer_opts);

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

AVFrame * input_frame = av_frame_alloc();AVPacket * input_packet = av_packet_alloc(); 而(av_read_frame(decoder_avfc,input_packet)> = 0){ av_packet_rescale_ts(input_packet,解码器_视频_avs-> time_base,编码器 _视频_avs- > time_base); av_interleaved_write_frame(* avfc,input_packet)< 0));} av_write_trailer(encoder_avfc);

转码

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

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

AVStream在编码器中创建视频,avformat_new_stream
使用AVCodec所谓的libx265,avcodec_find_encoder_by_name
AVCodecContext在创建的编解码器中创建基础,avcodec_alloc_context3
设置转码会话的基本属性,并
打开编解码器,然后将参数从上下文复制到流中。avcodec_open2和avcodec_parameters_from_context

AVRational input_framerate = av_guess_frame_rate(decoder_avfc,decoder_video_avs,NULL);AVStream * video_avs = avformat_new_stream(encoder_avfc,NULL); char * codec_name = “ libx265 ” ;char * codec_priv_key = “ x265-params ” ;//我们将为x265使用内部选项// //禁用场景更改检测,然后修复// 60帧的GOP。char * codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0 ” ; AVCodec * video_avc = avcodec_find_encoder_by_name(codec_name);AVCodecContext * video_avcc = avcodec_alloc_context3(video_avc);//编码器编解码器参数av_opt_set(sc-> video_avcc-> priv_data,codec_priv_key,codec_priv_value, 0);video_avcc-> height =解码器_ctx-> height;video_avcc-> width =解码器_ctx-> width;video_avcc-> pix_fmt = video_avc-> pix_fmts [ 0 ];//控制率 video_avcc-> bit_rate = 2 * 1000 * 1000 ;video_avcc-> rc_buffer_size = 4 * 1000 * 1000 ;video_avcc-> rc_max_rate = 2 * 1000 * 1000 ;video_avcc-> rc_min_rate = 2.5 * 1000 * 1000 ;//时基video_avcc-> time_base = av_inv_q(input_framerate);video_avs-> time_base = sc-> video_avcc-> time_base; avcodec_open2(sc-> video_avcc,sc-> video_avc,NULL);avcodec_parameters_from_context(sc-> video_avs-> codecpar,sc-> video_avcc);

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

将空发送AVPacket给解码器,avcodec_send_packet 接收未压缩的AVFrame,avcodec_receive_frame
开始对该原始帧进行转码,发送原始帧, avcodec_send_frame
根据我们的编解码器接收压缩的文件AVPacket,avcodec_receive_packet
设置时间戳,并 av_packet_rescale_ts 将其写入输出文件。 av_interleaved_write_frame

AVFrame * input_frame = av_frame_alloc();AVPacket * input_packet = av_packet_alloc(); 而(av_read_frame(decoder_avfc,input_packet)> = 0){ int响应= avcodec_send_packet(decoder_video_avcc,input_packet); while(响应> = 0){ 响应= avcodec_receive_frame(decoder_video_avcc,input_frame); if(响应== AVERROR(EAGAIN)|| response == AVERROR_EOF){ 中断 ; } else if(response < 0){ 返回响应; } if(响应> = 0){ 编码(encoder_avfc,decoder_video_avs,encoder_video_avs,decoder_video_avcc,input_packet-> stream_index); } av_frame_unref(input_frame); } av_packet_unref(input_packet);}av_write_trailer(encoder_avfc); //使用的函数int 编码(AVFormatContext * avfc,AVStream * dec_video_avs,AVStream * enc_video_avs,AVCodecContext video_avcc int索引){ AVPacket * output_packet = av_packet_alloc(); int response = avcodec_send_frame(video_avcc,input_frame); while(响应> = 0){ 响应= avcodec_receive_packet(video_avcc,output_packet); if(响应== AVERROR(EAGAIN)|| response == AVERROR_EOF){ 中断 ; } else if(响应< 0){ return - 1 ; } output_packet-> stream_index = index ; output_packet-> 持续时间 = enc_video_avs-> 那么time_base。den / enc_video_avs-> time_base。num / dec_video_avs-> avg_frame_rate。num * dec_video_avs-> avg_frame_rate。巢穴 ; av_packet_rescale_ts(output_packet,dec_video_avs-> time_base,enc_video_avs-> time_base); 响应= av_interleaved_write_frame(avfc,output_packet); } av_packet_unref(output_packet); av_packet_free(&output_packet); 返回 0 ;}

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

/ * * H264-> H265 *音频->重混合(未触摸) * MP4-MP4 * / StreamingParams sp = { 0 }; sp.copy_audio = 1 ; sp.copy_video = 0 ; sp.video_codec = “ libx265 ”; sp.codec_priv_key = “ x265-params ” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0 ” ; / * * H264-> H264(固定gop) *音频->重混合(未触摸) * MP4-MP4 * / StreamingParams sp = { 0 }; sp.copy_audio = 1 ; sp.copy_video = 0 ; sp.video_codec = “ libx264 ”; sp.codec_priv_key = “ x264参数” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0:force-cfr = 1 ” ; / * * H264-> H264(固定gop) 音频->重混合(未修改) MP4- 片段MP4 * / StreamingParams sp = { 0 }; sp.copy_audio = 1 ; sp.copy_video = 0 ; sp.video_codec = “ libx264 ”; sp.codec_priv_key = “ x264参数” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0:force-cfr = 1 ” ; sp.muxer_opt_key = “ movflags ”; sp.muxer_opt_value = “ frag_keyframe + empty_moov + default_base_moof ” ; / * * H264-> H264(固定gop) *音频-> AAC * MP4-MPEG-TS * / StreamingParams sp = { 0 }; sp.copy_audio = 0 ; sp.copy_video = 0 ; sp.video_codec = “ libx264 ”; sp.codec_priv_key = “ x264参数” ; sp.codec_priv_value = “ keyint = 60:min-keyint = 60:scenecut = 0:force-cfr = 1 ” ; sp.audio_codec = “ aac ” ; sp.output_extension = “ .ts ” ; / * WIP:P->它不在VLC上播放,最终比特率很高 * H264-> VP9 *音频-> Vorbis * MP4-WebM * / // StreamingParams sp = {0}; // sp.copy_audio = 0; // sp.copy_video = 0; // sp.video_codec =“ libvpx-vp9”; // sp.audio_codec =“ libvorbis”; // sp.output_extension =“ .webm”;

现在,说实话,这是难度比我想这会是我不得不挖掘到FFmpeg的命令行的源代码和测试了很多,我觉得我失去了一些东西,因为我不得不执行force-cfr的h264工作而且我仍然看到一些警告消息,例如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(上) · 视频-您看到的是什么! · 如果您有一系列图像序列,并以给定的频率(例如每秒24张图像)进行更改,则会产生运动的错觉.总之,这是视频背后的基本概念:一 ...

  3. FFmpeg - Windows下使用MSYS2和VS编译FFmpeg

    文章目录 0. 说明 1. 安装MSYS2 1.1 下载 1.2 安装 2. 下载FFmpeg及其他源码 3. 编译配置依赖库 3.1 打开一个新的MSYS2终端 3.2 编译x264 3.3 编译 ...

  4. Opencv FFmpeg Ubuntu下编译问题

    FFmpeg转码错误Cannot load libcuda.so.1 https://blog.csdn.net/yzhang6_10/article/details/81349532 srs2.0 ...

  5. FFmpeg Windows下安装与测试

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

  6. ffmpeg window下批量转换MP3为wav

    转载链接:https://blog.csdn.net/fuchuchen/article/details/55214216 ffmpeg 在window下将MP3转换为wav文件 1)ffmpeg   ...

  7. 【FFMPEG系列】FFMPEG linux下集成x264

    FFMPEG集成x264 1.x264下载地址: http://download.videolan.org/pub/videolan/x264/snapshots/ 2. FFMPEG引入外部库x26 ...

  8. ffmpeg Windows下录制桌面视频命令

    ffmpeg -f gdigrab -framerate 30 -i desktop out.yuv 命令执行结果如下 C:\Users\Administrator>ffmpeg -f gdig ...

  9. FFmpeg —— Linux下进行编译配置(硬件加速编解码)

    前提      这里首先需要大家在自己的Linux系统上安装了nvidia显卡驱动.cuda.        查看nvidia是否安装成功:nvidia-smi      查看cuda是否安装成功: ...

最新文章

  1. 图文详解 23 种设计模式
  2. Json返回时间中出现乱码问题的两种解决方法
  3. FreeRTOS系列第2篇---FreeRTOS入门指南
  4. Elasticsearch技术解析与实战(二)文档的CRUD操作
  5. LeetCode算法入门- 4Sum -day11
  6. Qt UDP组播的应用
  7. LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话(简单易懂)
  8. js ajax 表单异步提交
  9. 如何搭建企业大数据分析平台
  10. 还有没换国旗头像的么 头像领取方法 不要再@微信官方啦
  11. windows11 怎么使用IE浏览器,修改edge参数来实现
  12. Flutter——打包Windows桌面应用(流程)
  13. 你是阳光,你的世界充满阳光---心在哪,成就就在哪
  14. 无线AP概念功率mW、灵敏度dBm、增益dBi
  15. 《大规模元搜索引擎技(1)》一第1章 绪言
  16. tm1650中文资料_TM1650+msp430单片机 调试及遇到问题的总结
  17. Codeforces Round #540 (Div. 3) D. Coffee and Coursework 二分
  18. stm32山外虚拟示波器笔记
  19. ssis oracle配置,通过SSIS执行Oracle参数是什么?
  20. VLC电脑串流视频到手机播放

热门文章

  1. 2021-2027年中国智能制造行业市场前景预测研究报告
  2. liunx上mysql源码安装mysql,搞定linux上MySQL编程(一):linux上源码安装MySQL
  3. Solr部署如何启动
  4. 5 用python进行OpenCV实战之图像变换2(旋转)
  5. Windows10自带搜索增强设置
  6. 如何学习:自考小组学习
  7. LeetCode简单题之数组的度
  8. SoC(System on chip)与NoC(network-on-chip)
  9. PyTorch 进行 Neural-Transfer
  10. 地理围栏API服务开发