1. ffmpeg 视频解码一
2. ffmpeg 视频解码二
3. ffmpeg 音频解码一
4. ffmpeg 音频解码二
5. ffmpeg 音视频解码
6. ffmpeg 视频编码一
7. ffmpeg 视频编码一(精简版)
8. ffmpeg 视频编码二(基于 libswscale 转换视频)
9. ffmpeg 过滤器libavfilter的使用
10. ffmpeg 视频编码三(基于 libavfilter 转换视频)

前言

前面已经使用 libswscale 这个库已经实现了对视频的缩放,而且也对另一个可以同样实现相同功能的库 libavfilter做了简要介绍 ,这篇就来讲一下,使用 libavfilter 来处理我们的 ffmpeg 视频编码一(精简版) 当中遇到的问题吧。

流程图


这里就只是简要概述了,这里虽然标了解码的流程,但是这篇文章不做解码相关的事,后面会专门写篇完整的转码的文章,这里就不诉说了。

如果你看了 ffmpeg 视频编码一(精简版) 和 ffmpeg 过滤器libavfilter的使用 这两篇文章的话,对上面的流程图应该有个大概的理解,没看的话也不影响理解下面代码~。

源代码


#pragma once
#define __STDC_CONSTANT_MACROS
#define _CRT_SECURE_NO_WARNINGSextern "C"
{#include <libavformat/avformat.h>
#include "libavcodec/avcodec.h"
#include <libswscale/swscale.h>
#include "libavutil/imgutils.h"#include "libavutil/opt.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
}using namespace std;#define INPUT_FILE_NAME "lh_online.yuv"
#define OUTPUT_FILE_NAME "lh_online_512_512.mp4"//原视频相关参数//视频类型
#define SOURCE_AV_PIX_FMT_YUV AV_PIX_FMT_YUV420P
//的视频宽度
#define SOURCE_VIDEO_WIDTH 512
//视频高度
#define SOURCE_VIDEO_HEIGHT 288//编码相关参数
#define L_AVCODEID AV_CODEC_ID_MPEG4//带编码视频类型
#define ENC_AV_PIX_FMT_YUV AV_PIX_FMT_YUV420P
//编码之后的视频宽度
#define ENC_VIDEO_WIDTH 512
//编码之后的视频高度
#define ENC_VIDEO_HEIGHT 512
#define ENC_VIDEO_BITRATE 400000
//time_base  AVRational{1,15}
//一秒多少张图片(原视频是15。)
#define ENC_TIME_BASE_DEN 15AVFormatContext* o_fmt_ctx = NULL;
AVCodecContext* enc_c = NULL;;AVFilterContext* buffersink_ctx;
AVFilterContext* buffersrc_ctx;
AVFilterGraph* filter_graph;AVStream* out_stream;
AVFrame* frame, * tmp_frame;
AVPacket* enc_pkt;
int ret;//const char* filters_descr = "scale=512x512";
const char* filters_descr = "movie=my_logo.jpg,scale=80:50[wm];[in][wm]overlay=0:0,scale=512:512[out]";
//const char* filters_descr = "drawbox=x=100:y=100:w=100:h=100:color=red";
//const char* filters_descr = "drawtext=fontfile=方正粗黑宋简体.ttf:fontsize=32:fontcolor=red:text='Hello Word'";static void encode()
{//发送待编码数据到编码器ret = avcodec_send_frame(enc_c, tmp_frame);if (ret < 0) {fprintf(stderr, "Error sending a frame for encoding\n");exit(1);}while (1) {//编码一帧视频ret = avcodec_receive_packet(enc_c, enc_pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)break;if (ret < 0)return;//写入文件时流序号(这里只编码了视频流,而且也只实例化了一个输出流(avformat_new_stream),序号直接就是0)//多输出流的时候需要注意,后面音视频同时处理的时候,再说这个吧enc_pkt->stream_index = 0;//时间基转换(编码器->输出流)av_packet_rescale_ts(enc_pkt,enc_c->time_base,out_stream->time_base);printf("Write packet %d (size=%d)\n", enc_pkt->pts, enc_pkt->size);//写文件ret = av_interleaved_write_frame(o_fmt_ctx, enc_pkt);av_packet_unref(enc_pkt);}
}static int open_output_file()
{int ret;AVCodec* codec;o_fmt_ctx = avformat_alloc_context();avformat_alloc_output_context2(&o_fmt_ctx, NULL, NULL, OUTPUT_FILE_NAME);if (!o_fmt_ctx) {av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");return AVERROR_UNKNOWN;}//获取编码器codec = avcodec_find_encoder(L_AVCODEID);if (!codec) {av_log(NULL, AV_LOG_FATAL, "encoder Codec not found\n");return AVERROR_INVALIDDATA;}enc_c = avcodec_alloc_context3(codec);if (!enc_c) {av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n");return AVERROR(ENOMEM);}//一些默认参数的设置enc_c->codec_id = codec->id;enc_c->pix_fmt = ENC_AV_PIX_FMT_YUV;enc_c->bit_rate = ENC_VIDEO_BITRATE;enc_c->width = ENC_VIDEO_WIDTH;enc_c->height = ENC_VIDEO_HEIGHT;enc_c->time_base.num = 1;enc_c->time_base.den = ENC_TIME_BASE_DEN;enc_c->gop_size = 12;enc_c->max_b_frames = 4;if (o_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)enc_c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//实例化输出流out_stream = avformat_new_stream(o_fmt_ctx, NULL);if (!out_stream) {av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");return AVERROR_UNKNOWN;}//复制编码器参数到输出流ret = avcodec_parameters_from_context(out_stream->codecpar, enc_c);if (0 != ret){fprintf(stderr, "Failed to copy codec parameters\n");return -1;}out_stream->time_base = enc_c->time_base;//打开编码器ret = avcodec_open2(enc_c, codec, NULL);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream\n");return ret;}//打开输出文件if (!(o_fmt_ctx->oformat->flags & AVFMT_NOFILE)) {ret = avio_open(&o_fmt_ctx->pb, OUTPUT_FILE_NAME, AVIO_FLAG_WRITE);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Could not open output file\n", OUTPUT_FILE_NAME);return ret;}}//写文件头ret = avformat_write_header(o_fmt_ctx, NULL);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");return ret;}return 0;
}static int init_filter_graph()
{char args[512];int ret = 0;const AVFilter* buffersrc = avfilter_get_by_name("buffer");const AVFilter* buffersink = avfilter_get_by_name("buffersink");AVFilterInOut* outputs = avfilter_inout_alloc();AVFilterInOut* inputs = avfilter_inout_alloc();enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };filter_graph = avfilter_graph_alloc();if (!outputs || !inputs || !filter_graph) {ret = AVERROR(ENOMEM);goto clearup;}/* 缓冲视频源:从解码器解码的帧将被插入这里. */snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d",SOURCE_VIDEO_WIDTH, SOURCE_VIDEO_HEIGHT, SOURCE_AV_PIX_FMT_YUV,1, ENC_TIME_BASE_DEN);ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",args, NULL, filter_graph);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");goto clearup;}/* 缓冲视频接收:终止过滤器链. */ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",NULL, NULL, filter_graph);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");goto clearup;}ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");goto clearup;}/** 指定输入*/outputs->name = av_strdup("in");outputs->filter_ctx = buffersrc_ctx;outputs->pad_idx = 0;outputs->next = NULL;/** 指定输出*/inputs->name = av_strdup("out");inputs->filter_ctx = buffersink_ctx;inputs->pad_idx = 0;inputs->next = NULL;if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,&inputs, &outputs, NULL)) < 0)goto clearup;if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)goto clearup;clearup:avfilter_inout_free(&inputs);avfilter_inout_free(&outputs);return ret;
}//转换图片
static int filter_encode_write_frame()
{/* 将frame发送到graph进行处理. */ret = av_buffersrc_add_frame(buffersrc_ctx, frame);if (ret < 0) {av_frame_unref(frame);fprintf(stderr, "Error submitting the frame to the filtergraph:");return ret;}while (1) {/* 获取处理之后的数据. */ret = av_buffersink_get_frame(buffersink_ctx, tmp_frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)break;if (ret < 0)return ret;//送往解码encode();av_frame_unref(tmp_frame);}return ret;
}int main(int argc, char* argv[])
{//-------初始化一些配置---startint i = 0;int video_size = 0;size_t  data_size;uint8_t* temp_buffer;//输入视频基本信息//获得YUV420P像素格式每个像素占用的比特数(Bit Per Pixel)int src_bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(SOURCE_AV_PIX_FMT_YUV));//打开输入文件FILE* src_file = fopen(INPUT_FILE_NAME, "rb");//分配AVFrametmp_frame = av_frame_alloc();if (!tmp_frame) {fprintf(stderr, "Could not allocate video tmp_frame\n");exit(1);}tmp_frame->format = ENC_AV_PIX_FMT_YUV;tmp_frame->width = ENC_VIDEO_WIDTH;tmp_frame->height = ENC_VIDEO_HEIGHT;frame = av_frame_alloc();if (!frame) {fprintf(stderr, "Could not allocate video frame\n");exit(1);}frame->format = SOURCE_AV_PIX_FMT_YUV;frame->width = SOURCE_VIDEO_WIDTH;frame->height = SOURCE_VIDEO_HEIGHT;//计算 YUV420P 格式的图像需要占用的空间大小,分配内存空间temp_buffer = (uint8_t*)av_malloc(av_image_get_buffer_size(SOURCE_AV_PIX_FMT_YUV, SOURCE_VIDEO_WIDTH, SOURCE_VIDEO_HEIGHT, 1));//分配缓冲区并填入dst_data dst_linesizeif ((ret = av_image_alloc(frame->data, frame->linesize,SOURCE_VIDEO_WIDTH, SOURCE_VIDEO_HEIGHT, SOURCE_AV_PIX_FMT_YUV, 1)) < 0) {fprintf(stderr, "Could not allocate source image\n");goto end;}//分配缓冲区并填入dst_data dst_linesizeif ((ret = av_image_alloc(tmp_frame->data, tmp_frame->linesize,ENC_VIDEO_WIDTH, ENC_VIDEO_HEIGHT, ENC_AV_PIX_FMT_YUV, 1)) < 0) {fprintf(stderr, "Could not allocate source image\n");goto end;}//分配一个AVPacketenc_pkt = av_packet_alloc();if (!enc_pkt) {goto end;}//-------初始化一些配置---endret = init_filter_graph();if (ret < 0) {fprintf(stderr, "Unable to init filter graph:");goto end;}//输出处理if ((ret = open_output_file()) < 0) {av_log(NULL, AV_LOG_ERROR, "could not open output file \s.\n", OUTPUT_FILE_NAME);goto end;}video_size = SOURCE_VIDEO_WIDTH * SOURCE_VIDEO_HEIGHT;while (!feof(src_file)) {//读取数据 ,这里根据视频宽高和像素大小填充temp_bufferdata_size = fread(temp_buffer, 1, video_size * src_bpp / 8, src_file);if (!data_size)break;//填充 framememcpy(frame->data[0], temp_buffer, video_size);                    //Ymemcpy(frame->data[1], temp_buffer + video_size, video_size / 4);      //Umemcpy(frame->data[2], temp_buffer + video_size * 5 / 4, video_size / 4);  //V//转换一帧图像。//添加ptsframe->pts = i++;filter_encode_write_frame();}//写文件尾av_write_trailer(o_fmt_ctx);end://资源释放avfilter_graph_free(&filter_graph);avcodec_free_context(&enc_c);av_frame_free(&tmp_frame);av_packet_free(&enc_pkt);avformat_free_context(o_fmt_ctx);return 0;
}

到此就转码完成了,从一个512 * 288宽高的yuv的原始视频格式,编码成512 * 512 的mp4 文件,这里额外加了个水印图片到视频左上角。

看下效果:

好了,处理完成了,视频按要求拉伸成 512 * 512 的了,也没有出现 ffmpeg 视频编码一(精简版) 当中的问题,到此两个方式就介绍完成了。

ffmpeg 视频编码三(基于 libavfilter 转换视频)相关推荐

  1. LiveVideoStackCon 2018技术培训 — 从FFmpeg视频编码到抖音式视频特效实现

    LiveVideoStackCon 2018技术培训,"从FFmpeg视频编码到抖音式视频特效实现".我们拒绝"纸上谈兵",坚持技术讲解与实战训练相结合.门票火 ...

  2. 【笔记】H.265/HEVC 视频编码(二)——数字视频格式

    一.数字视频 视频技术泛指一系列的图像以电信号的方式加以捕捉.记录.处理.存储.传送与重现的各种技术.数字视频即以数字形式记录的视频,数字视频由一幅幅数字图像组成,每幅图像由N行,每行M个像素组成,每 ...

  3. android直播视频编码,Android手机直播之视频编码技术

    今天我们继续给大家讲解Android手机直播流程中的编码技术,编码过程分为视频和音频解码,这篇文字先介绍视频编码的技术.图玩智能为企业提供直播平台的二次开发服务,为大家搭建更加完善的直播系统,欢迎随时 ...

  4. ffmpeg h265编码_基于ffmpeg库mp4编码记录。

    要讨论的话题主要为以下: 话题1:音频流选用aac编码格式需要注意的地方. 话题2:音频流视频流同步需要注意的地方. 基本模式如下所示: 关于话题1部分,背景工作于基于海思平台35XX系列的SDK开发 ...

  5. Android 音视频深入 三 MP4解码播放视频 (附源码下载)

    本篇项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/%E5%AA%92%E ...

  6. linux视频采集软件,基于Video4Linux的视频图像采集实现 - 看看网

    一.Video4Linux简介 Video4Linux是Linux内核里支持影像设备的一组APIs,配合适当的视频采集设备和相应的驱动程序,可以实现影像采集.AM/FM广播.频道切换等功能,在远程会议 ...

  7. ffmpeg 视频编码一(精简版)

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  8. 【待更新】感知视频编码中的感知检测技术(显著性物体检测向)

    之前对ROI编码感兴趣,做了显著性检测方面的文献综述.截至到2019年1月13号有13400字. 现在搬上来,一来交流,二来重温 感知视频编码PVC HVS 针对HVS所构建的数学模型分类 基于HVS ...

  9. 视频教程-FFmpeg音视频编码实战屏幕录像机视频课程-基于QT5和FFMpegSDK-C/C++

    FFmpeg音视频编码实战屏幕录像机视频课程-基于QT5和FFMpegSDK 夏曹俊:南京捷帝科技有限公司创始人,南京大学计算机硕士毕业,有15年c++跨平台项目研发的经验,领导开发过大量的c++虚拟 ...

最新文章

  1. c#获取对象的唯一标识_在 Java 中利用 redis 实现分布式全局唯一标识服务
  2. ArcGIS Engine 项目10.1升级10.2
  3. vue data数据修改_Vue 超清晰思维导图(7张),详细知识点梳理!
  4. java内存模型作用是什么_什么是JVM内存模型?
  5. aes c语言 逆列混合函数,c语言aes列混合和逆列混合的实现(3页)-原创力文档
  6. 定时任务 Wpf.Quartz.Demo.3
  7. log4j的配置文件的位置
  8. python 安装 pyHook
  9. 信息安全毕设论文选题推荐
  10. WS小世界网络的建立及基本特征的求法
  11. 如何解决“数据错误,循环冗余检查”
  12. 5月18日第壹简报,星期三,农历四月十八
  13. VMware 虚拟机安装黑屏问题
  14. Scala的基础语法(超详细版)
  15. python算积分蒙特卡罗_蒙特卡罗计算积分
  16. 【7036】2年前的今晚,我给HR的转岗申请
  17. 为什么建议大家使用 Linux 开发?爽(外加七个感叹号)
  18. 基于javaweb(springboot+mybatis)网上家具商城项目设计和实现以及文档报告
  19. Burp Suite win10下安装图文教程
  20. java代码去连接flash media server服务器_flash media server 第一课:Hello world!

热门文章

  1. 【软件测试基础理论知识】3.1软件测试模型——V模型、W模型、H模型总结
  2. python识别英语语音翻译器_Python结合百度语音识别实现实时翻译软件的实现
  3. 使用TestFlight邀请外部人员测试APP
  4. 我的演讲稿《感恩父母,感谢你们你们一路陪我走来》
  5. python金融分析小知识(12)——python爬虫工具xpath使用
  6. c 语言一个数的n次方,C 语言实例 – 计算一个数的 n 次方 - C 语言基础教程
  7. Bat命令(windows)
  8. 从零开始学习cocoStudio(8)--商城
  9. 工信部牵头成立可信号码数据中心 预防电话骚扰
  10. PHP领域的术语对照(英中繁简)(转)。