#include "VideoCombine.h"
#include <stdio.h>
#include <QDebug>
#include <crtdbg.h>
#include "mainwindow.h"
#include <QDateTime>
#define USE_H264BSF 0
#define USE_AACBSF 0
#define USE_VIDEODATA_CALLBACK
AVBitStreamFilterContext *aacbsfc = NULL;
AVBitStreamFilterContext* h264bsfc = NULL;
//multiple input
static AVFormatContext **ifmt_ctx;
AVFrame **frame = NULL;
//single output
static AVFormatContext *ofmt_ctx;
int VideoCombine::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;
}
int VideoCombine::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;
}
int VideoCombine::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, NULL, 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)
{
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
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 this
av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
ret = avcodec_open2(enc_ctx, encoder, &d);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "avcodec_open2 output video failed\n");
return ret;
}else{
av_log(NULL, AV_LOG_INFO, "avcodec_open2 output video ok\n");
}
#ifdef USE_VIDEODATA_CALLBACK
m_pSwsContext = sws_getContext(global_ctx->enc_width,global_ctx->enc_height,AV_PIX_FMT_YUV420P,global_ctx->enc_width,
global_ctx->enc_height,AV_PIX_FMT_RGB24,SWS_BICUBIC,0,0,0);
avpicture_alloc(&m_pAVPicture,AV_PIX_FMT_RGB24,global_ctx->enc_width,global_ctx->enc_height);
#endif
}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, "avcodec_open2 output audio failed\n");
return ret;
}else{
av_log(NULL, AV_LOG_INFO, "avcodec_open2 output audio ok\n");
}
}
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 {
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 |= CODEC_FLAG_GLOBAL_HEADER;
}
av_log(NULL, AV_LOG_INFO, "open_output_file ok,nb_streams:%d\n",ofmt_ctx->nb_streams);
// 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;
}
}
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;
}
int VideoCombine::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_a