ffmpeg综合应用示例(五)——多路视频合并(Linux版本)

本文的目的为方便Linux下编译运行多路视频合成Demo

原文:ffmpeg综合应用示例(五)——多路视频合并

Ubuntu 20.04 + ffmpeg version ffmpeg-4.4-x86_64

编译

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/workspace/dengzr/linux-x64/lib:/home/workspace/dengzr/ffmpeg-4.4-x86_64/lib/  D_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/workspace/dengzr/linux-x64/lib:/home/works
g++ -o video_combine video_combine.cpp -I /home/workspace/dengzr/ffmpeg-4.4-x86_64/include/ -L /home/workspace/dengzr/ffmpeg-4.4-x86_64/lib/ -Wl,-Bstatic -Wl,-Bdynamic -lpthread -Wl,-Bstatic -Wl,-Bdynamic -lstdc++ -Wl,-Bstatic -Wl,-Bdynamic -ldl -Wl,-Bstatic -Wl,-Bdynamic -lavcodec -lavformat -lswscale -lavutil -lavfilter -lfdk-aac -lvpx -lpostproc -lavfilter -lm -lva -lOpenCL -lmfx -lstdc++ -ldl -lavformat -lm -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -lz -lfdk-aac -lvorbis -lvorbisenc -lx264 -lpthread -lm -ldl -lx265 -lva -lmfx -lstdc++ -ldl -lpostproc -lm -lswscale -lm -lswresample -lm -lavutil -lva-drm -lva -lva-x11 -lva -lm -ldrm -lmfx -lstdc++ -ldl -lOpenCL -lva -lX11 -lXext -lva -ldrm -lm -lpthread -lz -Wl,-Bstatic -Wl,-Bdynamic -lavcodec -lavformat -lswscale -lavutil -lavfilter -lfdk-aac -lvpx -lpostproc -lOpenCL -lmfx -lstdc++ -ldl -lvorbis -lvorbisenc -lx264 -lx265 -lswresample -lva-drm -lva-x11 -lX11 -lXext -Wl,-Bstatic -Wl,-Bdynamic -L /home/workspace/dengzr/ffmpeg-4.4-x86_64/lib/  -L /home/workspace/dengzr/linux-x64/lib -I /home/workspace/dengzr/linux-x64/include/ -lSDL2

Linux下修改后的代码

/**
*
* 张晖 Hui Zhang
* zhanghuicuc@gmail.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
*
* 本程序实现了对多路视频进行合并实现分屏效果,并且可以添加不同的视频滤镜。
* 目前还不支持音频合并
*/#include <stdio.h>
extern "C"
{
#include "libavutil/opt.h"
#include "libavutil/time.h"
#include "libavutil/mathematics.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
// #include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
};
// #include <crtdbg.h>/*
FIX: H.264 in some container format (FLV, MP4, MKV etc.) need
"h264_mp4toannexb" bitstream filter (BSF)
*Add SPS,PPS in front of IDR frame
*Add start code ("0,0,0,1") in front of NALU
H.264 in some container (MPEG2TS) don't need this BSF.
*/
//'1': Use H.264 Bitstream Filter   
#define USE_H264BSF 0  /*
FIX:AAC in some container format (FLV, MP4, MKV etc.) need
"aac_adtstoasc" bitstream filter (BSF)
*/
//'1': Use AAC Bitstream Filter   
#define USE_AACBSF 0  typedef enum{VFX_NULL = 0,VFX_EDGE = 1,VFX_NEGATE = 2
}VFX;typedef enum{AFX_NULL = 0,
}AFX;AVBitStreamFilterContext *aacbsfc = NULL;
AVBitStreamFilterContext* h264bsfc = NULL;
//multiple input
static AVFormatContext **ifmt_ctx;
AVFrame **frame = NULL;
//single output
static AVFormatContext *ofmt_ctx;typedef struct FilteringContext {AVFilterContext *buffersink_ctx;AVFilterContext **buffersrc_ctx;AVFilterGraph *filter_graph;
} FilteringContext;
static FilteringContext *filter_ctx;typedef struct InputFile{const char* filenames;/** position index* 0 - 1 - 2* 3 - 4 - 5* 6 - 7 - 8* ……*/uint32_t video_idx;//scale level, 0 means keep the same//uint32_t video_expand;uint32_t video_effect;uint32_t audio_effect;
} InputFile;
InputFile* inputfiles;typedef struct GlobalContext{//always be a square,such as 2x2, 3x3uint32_t grid_num;uint32_t video_num;uint32_t enc_width;uint32_t enc_height;uint32_t enc_bit_rate;InputFile* input_file;const char* outfilename;
} GlobalContext;
GlobalContext* global_ctx;static int global_ctx_config()
{int i;if (global_ctx->grid_num < global_ctx->video_num){av_log(NULL, AV_LOG_ERROR, "Setting a wrong grid_num %d \t The grid_num is smaller than video_num!! \n", global_ctx->grid_num);global_ctx->grid_num = global_ctx->video_num;//global_ctx->stride = sqrt((double)global_ctx->grid_num);av_log(NULL, AV_LOG_ERROR, "Automatically change the grid_num to be same as video_num!! \n");}//global_ctx->stride = sqrt((double)global_ctx->grid_num);for (i = 0; i < global_ctx->video_num; i++){if (global_ctx->input_file[i].video_idx >= global_ctx->grid_num){av_log(NULL, AV_LOG_ERROR, "Invalid video_inx value in the No.%d input\n", global_ctx->input_file[i].video_idx);return -1;}}return 0;
}static int open_input_file(InputFile *input_file)
{int ret;unsigned int i;unsigned int j;ifmt_ctx = (AVFormatContext**)av_malloc((global_ctx->video_num)*sizeof(AVFormatContext*));for (i = 0; i < global_ctx->video_num; i++){*(ifmt_ctx + i) = NULL;if ((ret = avformat_open_input((ifmt_ctx + i), input_file[i].filenames, NULL, NULL)) < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");return ret;}if ((ret = avformat_find_stream_info(ifmt_ctx[i], NULL)) < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");return ret;}for (j = 0; j < ifmt_ctx[i]->nb_streams; j++) {AVStream *stream;AVCodecContext *codec_ctx;stream = ifmt_ctx[i]->streams[j];codec_ctx = stream->codec;if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO|| codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {/* Open decoder */ret = avcodec_open2(codec_ctx,avcodec_find_decoder(codec_ctx->codec_id), NULL);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i);return ret;}}}av_dump_format(ifmt_ctx[i], 0, input_file[i].filenames, 0);}return 0;
}static int open_output_file(const char *filename)
{AVStream *out_stream;AVStream *in_stream;AVCodecContext *dec_ctx, *enc_ctx;AVCodec *encoder;int ret;unsigned int i;ofmt_ctx = NULL;avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", filename);if (!ofmt_ctx) {av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");return AVERROR_UNKNOWN;}for (i = 0; i < ifmt_ctx[0]->nb_streams; i++) {out_stream = avformat_new_stream(ofmt_ctx, NULL);if (!out_stream) {av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");return AVERROR_UNKNOWN;}in_stream = ifmt_ctx[0]->streams[i];out_stream->time_base = in_stream->time_base;dec_ctx = in_stream->codec;enc_ctx = out_stream->codec;if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO|| dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {			/* In this example, we transcode to same properties (picture size,* sample rate etc.). These properties can be changed for output* streams easily using filters */if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {/* in this example, we choose transcoding to same codec */encoder = avcodec_find_encoder(AV_CODEC_ID_H264);enc_ctx->height = global_ctx->enc_height;enc_ctx->width = global_ctx->enc_width;enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;/* take first format from list of supported formats */enc_ctx->pix_fmt = encoder->pix_fmts[0];enc_ctx->me_range = 16;enc_ctx->max_qdiff = 4;enc_ctx->bit_rate = global_ctx->enc_bit_rate;enc_ctx->qcompress = 0.6;/* video time_base can be set to whatever is handy and supported by encoder */enc_ctx->time_base.num = 1;enc_ctx->time_base.den = 25;enc_ctx->gop_size = 250;enc_ctx->max_b_frames = 3;AVDictionary * d = NULL;char *k = av_strdup("preset");       // if your strings are already allocated,char *v = av_strdup("ultrafast");    // you can avoid copying them like thisav_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);ret = avcodec_open2(enc_ctx, encoder, &d);}else {encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);enc_ctx->sample_rate = dec_ctx->sample_rate;enc_ctx->channel_layout = dec_ctx->channel_layout;enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);/* take first format from list of supported formats */enc_ctx->sample_fmt = encoder->sample_fmts[0];AVRational time_base = { 1, enc_ctx->sample_rate };enc_ctx->time_base = time_base;ret = avcodec_open2(enc_ctx, encoder, NULL);}if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);return ret;}       }else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i);return AVERROR_INVALIDDATA;}else {/* if this stream must be remuxed */ret = avcodec_copy_context(ofmt_ctx->streams[i]->codec,ifmt_ctx[0]->streams[i]->codec);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Copying stream context failed\n");return ret;}}if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;}av_dump_format(ofmt_ctx, 0, filename, 1);if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);return ret;}}/* init muxer, write output file header */ret = avformat_write_header(ofmt_ctx, NULL);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");return ret;}#if USE_H264BSF  h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
#endif  
#if USE_AACBSF  aacbsfc = av_bitstream_filter_init("aac_adtstoasc");
#endif return 0;
}static int init_filter(FilteringContext* fctx, AVCodecContext **dec_ctx,AVCodecContext *enc_ctx, const char *filter_spec)
{char args[512];char pad_name[10];int ret = 0;int i;AVFilter **buffersrc = (AVFilter**)av_malloc(global_ctx->video_num*sizeof(AVFilter*));AVFilter *buffersink = NULL;AVFilterContext **buffersrc_ctx = (AVFilterContext**)av_malloc(global_ctx->video_num*sizeof(AVFilterContext*));AVFilterContext *buffersink_ctx = NULL;AVFilterInOut **outputs = (AVFilterInOut**)av_malloc(global_ctx->video_num*sizeof(AVFilterInOut*));AVFilterInOut *inputs = avfilter_inout_alloc();AVFilterGraph *filter_graph = avfilter_graph_alloc();for (i = 0; i < global_ctx->video_num; i++){buffersrc[i] = NULL;buffersrc_ctx[i] = NULL;outputs[i] = avfilter_inout_alloc();}if (!outputs || !inputs || !filter_graph) {ret = AVERROR(ENOMEM);goto end;}if (dec_ctx[0]->codec_type == AVMEDIA_TYPE_VIDEO) {for (i = 0; i < global_ctx->video_num; i++){buffersrc[i] = (AVFilter *)avfilter_get_by_name("buffer");}buffersink = (AVFilter *)avfilter_get_by_name("buffersink");if (!buffersrc || !buffersink) {av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");ret = AVERROR_UNKNOWN;goto end;}for (i = 0; i < global_ctx->video_num; i++){snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",dec_ctx[i]->width, dec_ctx[i]->height, dec_ctx[i]->pix_fmt,dec_ctx[i]->time_base.num, dec_ctx[i]->time_base.den,dec_ctx[i]->sample_aspect_ratio.num,dec_ctx[i]->sample_aspect_ratio.den);snprintf(pad_name, sizeof(pad_name), "in%d", i);ret = avfilter_graph_create_filter(&(buffersrc_ctx[i]), buffersrc[i], pad_name,args, NULL, filter_graph);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");goto end;}}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 end;}ret = av_opt_set_bin(buffersink_ctx, "pix_fmts",(uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt),AV_OPT_SEARCH_CHILDREN);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");goto end;}}else if (dec_ctx[0]->codec_type == AVMEDIA_TYPE_AUDIO) {for (i = 0; i < global_ctx->video_num; i++){buffersrc[i] = (AVFilter *)avfilter_get_by_name("abuffer");}buffersink = (AVFilter *)avfilter_get_by_name("abuffersink");if (!buffersrc || !buffersink) {av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");ret = AVERROR_UNKNOWN;goto end;}for (i = 0; i < global_ctx->video_num; i++){if (!dec_ctx[i]->channel_layout)dec_ctx[i]->channel_layout =av_get_default_channel_layout(dec_ctx[i]->channels);snprintf(args, sizeof(args),"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",dec_ctx[i]->time_base.num, dec_ctx[i]->time_base.den, dec_ctx[i]->sample_rate,av_get_sample_fmt_name(dec_ctx[i]->sample_fmt),dec_ctx[i]->channel_layout);snprintf(pad_name, sizeof(pad_name), "in%d", i);ret = avfilter_graph_create_filter(&(buffersrc_ctx[i]), buffersrc[i], pad_name,args, NULL, filter_graph);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");goto end;}}if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");goto end;}ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",NULL, NULL, filter_graph);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");goto end;}ret = av_opt_set_bin(buffersink_ctx, "sample_fmts",(uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt),AV_OPT_SEARCH_CHILDREN);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");goto end;}ret = av_opt_set_bin(buffersink_ctx, "channel_layouts",(uint8_t*)&enc_ctx->channel_layout,sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");goto end;}ret = av_opt_set_bin(buffersink_ctx, "sample_rates",(uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate),AV_OPT_SEARCH_CHILDREN);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");goto end;}}/* Endpoints for the filter graph. */for (i = 0; i < global_ctx->video_num; i++){snprintf(pad_name, sizeof(pad_name), "in%d", i);outputs[i]->name = av_strdup(pad_name);outputs[i]->filter_ctx = buffersrc_ctx[i];outputs[i]->pad_idx = 0;if (i == global_ctx->video_num - 1)outputs[i]->next = NULL;elseoutputs[i]->next = outputs[i + 1];}inputs->name = av_strdup("out");inputs->filter_ctx = buffersink_ctx;inputs->pad_idx = 0;inputs->next = NULL;if (!outputs[0]->name || !inputs->name) {ret = AVERROR(ENOMEM);goto end;}if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec,&inputs, outputs, NULL)) < 0)goto end;if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)goto end;/* Fill FilteringContext */fctx->buffersrc_ctx = buffersrc_ctx;fctx->buffersink_ctx = buffersink_ctx;fctx->filter_graph = filter_graph;
end:avfilter_inout_free(&inputs);av_free(buffersrc);//	av_free(buffersrc_ctx);avfilter_inout_free(outputs);av_free(outputs);return ret;
}static int init_spec_filter(void)
{char filter_spec[512];char spec_temp[128];unsigned int i;unsigned int j;unsigned int k;unsigned int x_coor;unsigned int y_coor;AVCodecContext** dec_ctx_array;int	stream_num = ifmt_ctx[0]->nb_streams;int stride = (int)sqrt((long double)global_ctx->grid_num);int ret;filter_ctx = (FilteringContext *)av_malloc_array(stream_num, sizeof(*filter_ctx));dec_ctx_array = (AVCodecContext**)av_malloc(global_ctx->video_num*sizeof(AVCodecContext));if (!filter_ctx || !dec_ctx_array)return AVERROR(ENOMEM);for (i = 0; i < stream_num; i++) {filter_ctx[i].buffersrc_ctx = NULL;filter_ctx[i].buffersink_ctx = NULL;filter_ctx[i].filter_graph = NULL;for (j = 0; j < global_ctx->video_num; j++)dec_ctx_array[j] = ifmt_ctx[j]->streams[i]->codec;if (!(ifmt_ctx[0]->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO|| ifmt_ctx[0]->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO))continue;if (ifmt_ctx[0]->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){if (global_ctx->grid_num == 1)snprintf(filter_spec, sizeof(filter_spec), "null");else{snprintf(filter_spec, sizeof(filter_spec), "color=c=black@1:s=%dx%d[x0];", global_ctx->enc_width, global_ctx->enc_height);k = 1;for (j = 0; j < global_ctx->video_num; j++){switch (global_ctx->input_file[j].video_effect){case VFX_NULL:snprintf(spec_temp, sizeof(spec_temp), "[in%d]null[ine%d];", j, j);strcat(filter_spec, spec_temp);break;case VFX_EDGE:snprintf(spec_temp, sizeof(spec_temp), "[in%d]edgedetect[ine%d];", j, j);strcat(filter_spec, spec_temp);break;case VFX_NEGATE:snprintf(spec_temp, sizeof(spec_temp), "[in%d]negate[ine%d];", j, j);strcat(filter_spec, spec_temp);break;}x_coor = global_ctx->input_file[j].video_idx % stride;y_coor = global_ctx->input_file[j].video_idx / stride;snprintf(spec_temp, sizeof(spec_temp), "[ine%d]scale=w=%d:h=%d[inn%d];[x%d][inn%d]overlay=%d*%d/%d:%d*%d/%d[x%d];", j, global_ctx->enc_width / stride, global_ctx->enc_height / stride, j, k - 1, j, global_ctx->enc_width, x_coor, stride, global_ctx->enc_height, y_coor, stride, k);k++;strcat(filter_spec, spec_temp);}snprintf(spec_temp, sizeof(spec_temp), "[x%d]null[out]", k - 1, global_ctx->enc_width, global_ctx->enc_height);strcat(filter_spec, spec_temp);}}else{if (global_ctx->video_num == 1)snprintf(filter_spec, sizeof(filter_spec), "anull");else{snprintf(filter_spec, sizeof(filter_spec), "");for (j = 0; j < global_ctx->video_num; j++){snprintf(spec_temp, sizeof(spec_temp), "[in%d]", j);strcat(filter_spec, spec_temp);}snprintf(spec_temp, sizeof(spec_temp), "amix=inputs=%d[out]", global_ctx->video_num);strcat(filter_spec, spec_temp);}}ret = init_filter(&filter_ctx[i], dec_ctx_array,ofmt_ctx->streams[i]->codec, filter_spec);if (ret)return ret;}av_free(dec_ctx_array);return 0;
}int videocombine(GlobalContext* video_ctx)
{int ret;int tmp = 0;int got_frame_num = 0;unsigned int stream_index;AVPacket packet;AVPacket enc_pkt;AVFrame* picref;enum AVMediaType mediatype;int read_frame_done = 0;int flush_now = 0;int framecnt = 0;int i, j;int got_frame;int enc_got_frame = 0;int(*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *);int(*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *);global_ctx = video_ctx;global_ctx_config();frame = (AVFrame**)av_malloc(global_ctx->video_num*sizeof(AVFrame*));picref = av_frame_alloc();av_register_all();avfilter_register_all();if ((ret = open_input_file(global_ctx->input_file)) < 0)goto end;if ((ret = open_output_file(global_ctx->outfilename)) < 0)goto end;if ((ret = init_spec_filter()) < 0)goto end;while (1) {for (i = 0; i < global_ctx->video_num; i++){if (read_frame_done < 0){flush_now = 1;goto flush;}			while ((read_frame_done=av_read_frame(ifmt_ctx[i], &packet)) >= 0){stream_index = packet.stream_index;mediatype = ifmt_ctx[i]->streams[stream_index]->codec->codec_type;if (mediatype == AVMEDIA_TYPE_VIDEO || mediatype == AVMEDIA_TYPE_AUDIO){frame[i] = av_frame_alloc();if (!(frame[i])){ret = AVERROR(ENOMEM);goto end;}av_packet_rescale_ts(&packet,ifmt_ctx[i]->streams[stream_index]->time_base,ifmt_ctx[i]->streams[stream_index]->codec->time_base);dec_func = (mediatype == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 : avcodec_decode_audio4;ret = dec_func(ifmt_ctx[i]->streams[stream_index]->codec, frame[i], &got_frame, &packet);if (ret < 0){av_frame_free(&frame[i]);av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");goto end;}if (got_frame) {frame[i]->pts = av_frame_get_best_effort_timestamp(frame[i]);ret = av_buffersrc_add_frame(filter_ctx[stream_index].buffersrc_ctx[i], frame[i]);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");goto end;}}else{av_frame_free(&(frame[i]));}}av_free_packet(&packet);if (got_frame){got_frame = 0;break;}}}while (1) {ret = av_buffersink_get_frame_flags(filter_ctx[stream_index].buffersink_ctx, picref, 0);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){ret = 0;break;}if (ret < 0)goto end;if (picref) {								enc_pkt.data = NULL;enc_pkt.size = 0;av_init_packet(&enc_pkt);enc_func = (mediatype == AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;ret = enc_func(ofmt_ctx->streams[stream_index]->codec, &enc_pkt,picref, &enc_got_frame);	if (ret < 0){av_log(NULL, AV_LOG_ERROR, "Encoding failed\n");goto end;}if (enc_got_frame == 1){framecnt++;enc_pkt.stream_index = stream_index;//Write PTSAVRational time_base = ofmt_ctx->streams[stream_index]->time_base;//{ 1, 1000 };AVRational r_framerate1 = ifmt_ctx[0]->streams[stream_index]->r_frame_rate;// { 50, 2 };AVRational time_base_q = { 1, AV_TIME_BASE };//Duration between 2 frames (us)int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));	//内部时间戳//Parameters//enc_pkt.pts = (double)(framecnt*calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));enc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);enc_pkt.dts = enc_pkt.pts;enc_pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));enc_pkt.pos = -1;#if USE_H264BSF  av_bitstream_filter_filter(h264bsfc, in_stream->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
#endif  
#if USE_AACBSF  av_bitstream_filter_filter(aacbsfc, out_stream->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
#endif  ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);av_log(NULL, AV_LOG_INFO, "write frame %d\n", framecnt);av_free_packet(&enc_pkt);}av_frame_unref(picref);}	}}flush:/* flush filters and encoders */for (i = 0; i < ifmt_ctx[0]->nb_streams; i++) {stream_index = i;/* flush encoder */if (!(ofmt_ctx->streams[stream_index]->codec->codec->capabilities &AV_CODEC_CAP_DELAY))return 0;while (1) {enc_pkt.data = NULL;enc_pkt.size = 0;av_init_packet(&enc_pkt);enc_func = (ifmt_ctx[0]->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO) ?avcodec_encode_video2 : avcodec_encode_audio2;ret = enc_func(ofmt_ctx->streams[stream_index]->codec, &enc_pkt,NULL, &enc_got_frame);av_frame_free(NULL);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "Encoding failed\n");goto end;}if (!enc_got_frame){ret = 0;break;}printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n", enc_pkt.size);//Write PTSAVRational time_base = ofmt_ctx->streams[stream_index]->time_base;//{ 1, 1000 };AVRational r_framerate1 = ifmt_ctx[0]->streams[stream_index]->r_frame_rate;// { 50, 2 };AVRational time_base_q = { 1, AV_TIME_BASE };//Duration between 2 frames (us)int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));	//内部时间戳//Parametersenc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);enc_pkt.dts = enc_pkt.pts;enc_pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base);/* copy packet*///转换PTS/DTS(Convert PTS/DTS)enc_pkt.pos = -1;framecnt++;ofmt_ctx->duration = enc_pkt.duration * framecnt;/* mux encoded frame */ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);}}av_write_trailer(ofmt_ctx);#if USE_H264BSF  av_bitstream_filter_close(h264bsfc);
#endif  
#if USE_AACBSF  av_bitstream_filter_close(aacbsfc);
#endif  end:av_free_packet(&packet);for (i = 0; i < global_ctx->video_num; i++){av_frame_free(&(frame[i]));for (j = 0; j < ofmt_ctx->nb_streams; j++) {avcodec_close(ifmt_ctx[i]->streams[j]->codec);}}av_free(frame);av_free(picref);for (i = 0; i<ofmt_ctx->nb_streams; i++){if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && ofmt_ctx->streams[i]->codec)avcodec_close(ofmt_ctx->streams[i]->codec);av_free(filter_ctx[i].buffersrc_ctx);if (filter_ctx && filter_ctx[i].filter_graph)avfilter_graph_free(&filter_ctx[i].filter_graph);}av_free(filter_ctx);for (i = 0; i < global_ctx->video_num; i++)avformat_close_input(&(ifmt_ctx[i]));if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))avio_close(ofmt_ctx->pb);avformat_free_context(ofmt_ctx);av_free(ifmt_ctx);if (ret < 0)av_log(NULL, AV_LOG_ERROR, "Error occurred\n");return (ret ? 1 : 0);
}int main(int argc, char **argv)
{//test 2x2inputfiles = (InputFile*)av_malloc_array(4, sizeof(InputFile));if (!inputfiles)return AVERROR(ENOMEM);inputfiles[0].filenames = "in1.flv";//inputfiles[0].video_expand = 0;inputfiles[0].video_idx = 0;inputfiles[0].video_effect = VFX_EDGE;inputfiles[0].audio_effect = AFX_NULL;inputfiles[1].filenames = "in2.flv";//inputfiles[1].video_expand = 0;inputfiles[1].video_idx = 1;inputfiles[1].video_effect = VFX_NULL;inputfiles[1].audio_effect = AFX_NULL;inputfiles[2].filenames = "in3.flv";//inputfiles[2].video_expand = 0;inputfiles[2].video_idx = 2;inputfiles[2].video_effect = VFX_NULL;inputfiles[2].audio_effect = AFX_NULL;inputfiles[3].filenames = "in4.flv";//inputfiles[3].video_expand = 0;inputfiles[3].video_idx = 3;inputfiles[3].video_effect = VFX_NEGATE;inputfiles[3].audio_effect = AFX_NULL;global_ctx = (GlobalContext*)av_malloc(sizeof(GlobalContext));global_ctx->video_num = 4;global_ctx->grid_num = 4;global_ctx->enc_bit_rate = 500000;global_ctx->enc_height = 360;global_ctx->enc_width = 640;global_ctx->outfilename = "combined.flv";global_ctx->input_file = inputfiles;return videocombine(global_ctx);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/20912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jenkins使用gitlab标签发布

关于jenkins git parameter使用gitlab标签发布和分支发布的用法 手动配置的我就不说了&#xff0c;点点点就行&#xff0c;主要是说一下在pipeline里如何使用 通过分支拉取gitlab仓库代码 pipeline {agent anyenvironment {}parameters {gitParameter(branch: , branchFilte…

Sentinel dashboard的使用;Nacos保存Sentinel限流规则

Sentinel dashboard的使用 往期文章 Nacos环境搭建Nacos注册中心的使用Nacos配置中心的使用Sentinel 容灾中心的使用 参考文档 Sentinel alibaba/spring-cloud-alibaba Wiki GitHub 限流结果 下载sentinel-dashboard github地址&#xff1a;Sentinel/sentinel-dashboar…

prototype, construction, instanceof

prototype 属性的作用 JavaScript 规定&#xff0c;每个函数都有一个prototype属性&#xff0c;指向一个对象。 function f() {} typeof f.prototype // "object" ​ 上面代码中&#xff0c;函数f默认具有prototype属性&#xff0c;指向一个对象。 对于普通函数来…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 4

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

C++之观察者模式(发布-订阅)

目录 模式简介 介绍 优点 缺点 代码实现 场景说明 实现代码 运行结果 模式简介 观察者模式&#xff08;Observer Pattern&#xff09;&#xff0c;也叫我们熟知的发布-订阅模式。 它是一种行为型模式。 介绍 观察者模式主要关注的是对象的一对多的关系&#xff0c; …

Go和Java实现组合模式

Go和Java实现组合模式 我们通过部门和员工的层次结构的示例来演示组合模式的用法。 1、组合模式 组合模式&#xff0c;又叫部分整体模式&#xff0c;是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对 象&#xff0c;用来表示部分以及整体层次。这种…

【MFC】03.常用复杂控件的使用-笔记

热键&#xff1a; 对话框-类向导&#xff1a;初始化函数中&#xff0c;热键需要在最开始的时候就注册进去&#xff1a; 注册热键&#xff1a; 在这之前&#xff0c;先去定义一个宏&#xff0c;代表你这个快捷键。 参数&#xff1a;窗口句柄&#xff0c;热键编号&#xff08;热…

antd vue中遍历v-for中控制每个按钮的loading

项目中遇到一个需求&#xff0c;需要根据后台返回数据&#xff0c;遍历生成多个按钮&#xff0c;并点击出发事件。点击事件的时候需要该按钮loading状态。实现方法如下&#xff1a; <div class"center"><a-button v-for"(item,index) in btnItems&quo…

C# File.Exists与Directory.Exists用法

File.Exists&#xff1a; 用于检查给定文件路径是否存在。如果文件存在&#xff0c;则返回true&#xff0c;否则返回false。 string path“D:\\test\\example.txt” bool exists File.Exists(path); if (exists) {Console.WriteLine("File exists."); } else {Con…

Qt 实现压缩文件、文件夹和解压缩操作zip

一、实现方式 通过Qt自带的库来实现&#xff0c;使用多线程方式&#xff0c;通过信号和槽来触发压缩与解压缩&#xff0c;并将压缩和解压缩结果回传过来。 使用的类&#xff1a; #include "QtGui/private/qzipreader_p.h" #include "QtGui/private/qzipwriter…

HCIP入门静态实验

题目及要求 第一步&#xff1a;拓扑的搭建 第二步&#xff1a;路由、IP的配置 r1: <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys r1 [r1]int loop [r1]int LoopBack 0 [r1-LoopBack0]ip add 192.168.1.65 27 [r1-LoopBack0]int loop 1 […

什么是高级持续威胁(APT)攻击

目录 前言什么是高级持续威胁高级持续威胁攻击有哪些独特特征APT攻击的五个阶段APT检测及防护措施总结 前言 APT攻击是利用多个阶段和不同攻击技术的复合网络攻击。APT不是一时兴起构思或实施的攻击。相反&#xff0c;攻击者故意针对特定目标定制攻击策略。并在较长时间内进行…

接口测试如何在json中引用mock变量

在测试接口的时候&#xff0c;有的接口需要测试随机传入大量数据&#xff0c;查看数据库是否正常&#xff0c;但是大量的随机数据全靠自己手写会很慢&#xff0c;而且是通过json传递的数据。 这里我们就可以使用mock生成随机变量&#xff0c;然后在json中引用mock变量 首先看…

python与深度学习(十四):CNN和IKUN模型二

目录 1. 说明2. IKUN模型的CNN模型测试2.1 导入相关库2.2 加载模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章猫狗大战训练的模型进行测试。…

Netty+springboot开发即时通讯系统笔记(一)

业务部分从sql开始&#xff1a; /*Navicat Premium Data TransferSource Server : localhostSource Server Type : MySQLSource Server Version : 50740Source Host : localhost:3306Source Schema : im-coreTarget Server Type : MySQLTarge…

极客时间:如何成为学习高手 【学习笔记】

本文是 极客时间- 如何成为学习高手 - 高冷冷 专栏学习笔记整理&#xff0c;课程链接&#xff1a;https://time.geekbang.org/column/intro/100081501?tabcatalog 底层思维01&#xff5c;如何减少对学习的排斥和厌恶心理&#xff0c;使其变得相对愉悦&#xff1f;02&#xff…

20天学rust(一)和rust say hi

关注我&#xff0c;学习Rust不迷路 工欲善其事&#xff0c;必先利其器。第一节我们先来配置rust需要的环境和安装趁手的工具&#xff0c;然后写一个简单的小程序。 安装 Rust环境 Rust 官方有提供一个叫做 rustup 的工具&#xff0c;专门用于 rust 版本的管理&#xff0c;网…

windows下载安装FFmpeg

FFmpeg是一款强大的音视频处理软件&#xff0c;下面介绍如何在windows下下载安装FFmpeg 下载 进入官网: https://ffmpeg.org/download.html, 选择Windows, 然后选择"Windows builds from gyan.dev" 在弹出的界面中找到release builds, 然后选择一个版本&#xff0…

Day09-ES6编程

文章目录 Day09-ES6编程一 Map集合1 Map集合的特点2 基本语法3 遍历4 应用二 DEBUG第一步 打断点第二步 启动DEBUG模式第三步,让程序执行下一步第四步,结束DEBUG模式三 对象中的函数四 this的指向问题1 普通函数中的this2 对象的普通函数中的this3 事件绑定函数的this4 箭头函数…

Java面向对象之import关键字

import关键字 为使用定义在不同包中的Java类&#xff0c;需用import语句来引入指定包层次下所需要的类或全部类(.*)。import语句告诉编译器到哪里去寻找类。语法格式&#xff1a;import 包名. 类名;在源文件中使用import显式的导入指定包下的类或接口。声明在包的声明和类的声…