#include <stdio.h>
#include <string>
#include <iostream>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavutil/frame.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"
#include "libavutil/bprint.h"
//add
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
#include "libavutil/buffer.h"
#include "libavutil/error.h"
#include "libavutil/hwcontext.h"
// #include "libavutil/hwcontext_qsv.h"
#include "libavutil/mem.h"
#include "libavutil/imgutils.h"
#include <libswscale/swscale.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
}
using namespace std;
int save_yuv_to_file(AVFrame *frame, int num);
AVFrame* get_frame_from_jpeg_or_png_file(const char *filename,AVRational *logo_tb,AVRational *logo_fr);
int main()
{
int ret = 0; int err;
//打开输入文件
// char filename[] = "juren-30s.mp4";
char filename[] = "jjren.mp4";
AVFormatContext *fmt_ctx = avformat_alloc_context();
if (!fmt_ctx) {
printf("error code %d \n",AVERROR(ENOMEM));
return ENOMEM;
}
if((err = avformat_open_input(&fmt_ctx, filename,NULL,NULL)) < 0){
printf("can not open file %d \n",err);
return err;
}
//打开解码器
AVCodecContext *avctx = avcodec_alloc_context3(NULL);
ret = avcodec_parameters_to_context(avctx, fmt_ctx->streams[0]->codecpar);
if (ret < 0){
printf("error code %d \n",ret);
return ret;
}
const AVCodec *codec = avcodec_find_decoder(avctx->codec_id);
if ((ret = avcodec_open2(avctx, codec, NULL)) < 0) {
printf("open codec faile %d \n",ret);
return ret;
}
AVFilterGraph *filter_graph = NULL;
AVFilterContext *mainsrc_ctx,*logo_ctx,*resultsink_ctx = NULL;
AVPacket *pkt = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
AVFrame *result_frame = av_frame_alloc();
AVRational logo_tb = {0};
AVRational logo_fr = {0};
AVFrame *logo_frame = get_frame_from_jpeg_or_png_file("logo.png",&logo_tb,&logo_fr);
if( NULL == logo_frame ){
printf("logo.jpg not exist\n");
return 888;
}
int64_t logo_next_pts = 0,main_next_pts = 0;
int read_end = 0;
int frame_num = 0;
for(;;){
if( 1 == read_end ){
break;
}
ret = av_read_frame(fmt_ctx, pkt);
//跳过不处理音频包
if( 1 == pkt->stream_index ){
av_packet_unref(pkt);
continue;
}
if ( AVERROR_EOF == ret) {
//读取完文件,这时候 pkt 的 data 跟 size 应该是 null
avcodec_send_packet(avctx, NULL);
}else {
if( 0 != ret){
printf("read error code %d \n",ret);
return ENOMEM;
}else{
retry:
if (avcodec_send_packet(avctx, pkt) == AVERROR(EAGAIN)) {
printf("Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
//这里可以考虑休眠 0.1 秒,返回 EAGAIN 通常是 ffmpeg 的内部 api 有bug
goto retry;
}
//释放 pkt 里面的编码数据
av_packet_unref(pkt);
}
}
//循环不断从解码器读数据,直到没有数据可读。
for(;;){
//读取 AVFrame
ret = avcodec_receive_frame(avctx, frame);
/* 释放 frame 里面的YUV数据,
* 由于 avcodec_receive_frame 函数里面会调用 av_frame_unref,所以下面的代码可以注释。
* 所以我们不需要 手动 unref 这个 AVFrame
* */
//av_frame_unref(frame);
if( AVERROR(EAGAIN) == ret ){
//提示 EAGAIN 代表 解码器 需要 更多的 AVPacket
//跳出 第一层 for,让 解码器拿到更多的 AVPacket
break;
}else if( AVERROR_EOF == ret ){
/* 提示 AVERROR_EOF 代表之前已经往 解码器发送了一个 data 跟 size 都是 NULL 的 AVPacket
* 发送 NULL 的 AVPacket 是提示解码器把所有的缓存帧全都刷出来。
* 通常只有在 读完输入文件才会发送 NULL 的 AVPacket,或者需要用现有的解码器解码另一个的视频流才会这么干。
*
* */
//跳出 第二层 for,文件已经解码完毕。
read_end = 1;
break;
}else if( ret >= 0 ){
//这两个变量在本文里没有用的,只是要传进去。
AVFilterInOut *inputs, *cur, *outputs;
if( NULL == filter_graph ){
//初始化滤镜容器
filter_graph = avfilter_graph_alloc();
if (!filter_graph) {
printf("Error: allocate filter graph failed\n");
return -1;
}
// 因为 filter 的输入是 AVFrame ,所以 filter 的时间基就是 AVFrame 的时间基
AVRational tb = fmt_ctx->streams[0]->time_base;
AVRational fr = av_guess_frame_rate(fmt_ctx, fmt_ctx->streams[0], NULL);
AVRational logo_sar = logo_frame->sample_aspect_ratio;
AVRational sar = frame->sample_aspect_ratio;
AVBPrint args;
av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
av_bprintf(&args,
"buffer=video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d:frame_rate=%d/%d[main];"
"buffer=video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d:frame_rate=%d/%d[logo];"
"[main][logo]overlay=x=10:y=10[result];"
"[result]format=nv12[result_2];"
"[result_2]buffersink",
frame->width, frame->height, frame->format, tb.num,tb.den,sar.num, sar.den,fr.num, fr.den,
logo_frame->width, logo_frame->height, logo_frame->format, logo_tb.num,logo_tb.den ,
logo_sar.num,logo_sar.den, logo_fr.num, logo_fr.den);
ret = avfilter_graph_parse2(filter_graph, args.str, &inputs, &outputs);
if (ret < 0) {
printf("Cannot configure graph\n");
return ret;
}
//正式打开滤镜
ret = avfilter_graph_config(filter_graph, NULL);
if (ret < 0) {
printf("Cannot configure graph\n");
return ret;
}
//根据 名字 找到 AVFilterContext
mainsrc_ctx = avfilter_graph_get_filter(filter_graph, "Parsed_buffer_0");
logo_ctx = avfilter_graph_get_filter(filter_graph, "Parsed_buffer_1");
resultsink_ctx = avfilter_graph_get_filter(filter_graph, "Parsed_buffersink_4");
ret = av_buffersrc_add_frame_flags(logo_ctx, logo_frame,AV_BUFFERSRC_FLAG_PUSH);
if(ret < 0){
printf("Error: av_buffersrc_add_frame failed\n");
return ret;
overlay-simple
需积分: 5 126 浏览量
2023-11-15
16:01:11
上传
评论
收藏 30.85MB ZIP 举报
、、、、燕庆伟、、、、
- 粉丝: 6446
- 资源: 8
最新资源
- # 微信小程序-健康菜谱 基于微信小程序的一个查找检索菜谱的应用 ### 效果 !动态图(./res/gif/demo
- zabbix-get命令包资源
- 毕业设计,基于PyQt5实现的可视化界面的Python车牌自动识别系统源码
- 26-朴素贝叶斯分类.rar
- 没有安Matlab 也可以 生成FIR抽头系数工具.py
- python烟花代码.rar
- 实验目的: 1.构建基于verilog语言的组合逻辑电路和时序逻辑电路; 2.掌握verilog语言的电路设计技巧 3.完成如
- 扩展卡尔曼滤波matlab仿真
- 3_base.apk.1
- 躺赢者PRO飞控常见典型问题合集(续一)无名小哥 余义 20240501待修
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈