首页 > 代码库 > ffmpeg转码多路输出(二)

ffmpeg转码多路输出(二)

ffmpeg转码多路输出(二)

本程序支持一路输入多路输出,可根据map配置自行添加,第1路为纯拷贝,其他2路经过编解码,格式转换缩放和重采样,纯拷贝方面不同格式适应方面还没做全,以后补充。本程序适合多分辨率切换等方面内容。注意重采样等方面的注释内容。

具体看代码:

//main.cpp

#include "ffmpeg_transcode.h"


/*
int main()
{
	AVOutputFormat *ofmt = NULL;
	AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
	AVPacket pkt;
	int ret, i;
	av_register_all();

	if ((ret = avformat_open_input(&ifmt_ctx, INPUTURL, 0, 0)) < 0) {
		fprintf(stderr, "Could not open input file ‘%s‘", INPUTURL);
	}

	if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
		fprintf(stderr, "Failed to retrieve input stream information");
	}

	av_dump_format(ifmt_ctx, 0, INPUTURL, 0);

	avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, OUTPUTURL);
	if (!ofmt_ctx) {
		fprintf(stderr, "Could not create output context\n");
		ret = AVERROR_UNKNOWN;
	}

	ofmt = ofmt_ctx->oformat;

	for (i = 0; i < ifmt_ctx->nb_streams; i++) {
		AVStream *in_stream = ifmt_ctx->streams[i];
		AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
		if (!out_stream) {
			fprintf(stderr, "Failed allocating output stream\n");
			ret = AVERROR_UNKNOWN;
		}

		ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
		if (ret < 0) {
			fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
		}
		out_stream->codec->codec_tag = 0;
		if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
			out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
	}

	if (!(ofmt->flags & AVFMT_NOFILE)) {
		ret = avio_open(&ofmt_ctx->pb, OUTPUTURL, AVIO_FLAG_WRITE);
		if (ret < 0) {
			fprintf(stderr, "Could not open output file ‘%s‘", OUTPUTURL);
		}
	}

	ret = avformat_write_header(ofmt_ctx, NULL);
	if (ret < 0) {
		fprintf(stderr, "Error occurred when opening output file\n");
	}

	av_dump_format(ofmt_ctx, 0, OUTPUTURL, 1);

	AVBitStreamFilterContext * m_vbsf_aac_adtstoasc;     //aac->adts to asc过滤器 
	m_vbsf_aac_adtstoasc =  av_bitstream_filter_init("aac_adtstoasc");

	while (1) 
	{
		AVStream *in_stream, *out_stream;

		ret = av_read_frame(ifmt_ctx, &pkt);
		if (ret < 0)
			break;

		in_stream  = ifmt_ctx->streams[pkt.stream_index];
		out_stream = ofmt_ctx->streams[pkt.stream_index];


		pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
		pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
		pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
		pkt.pos = -1;

		if (in_stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			if (m_vbsf_aac_adtstoasc != NULL)  
			{  
				AVPacket filteredPacket = pkt;   
				int a = av_bitstream_filter_filter(m_vbsf_aac_adtstoasc,                                             
					out_stream->codec, NULL,&filteredPacket.data, &filteredPacket.size,  
					pkt.data, pkt.size, pkt.flags & AV_PKT_FLAG_KEY);   
				if (a >  0)               
				{                  
					av_free_packet(&pkt);   
					filteredPacket.destruct = av_destruct_packet;    
					pkt = filteredPacket;               
				}     
				else if (a == 0)  
				{  
					pkt = filteredPacket;     
				}  
				else if (a < 0)              
				{                  
					fprintf(stderr, "%s failed for stream %d, codec %s",  
						m_vbsf_aac_adtstoasc->filter->name,pkt.stream_index,out_stream->codec->codec ?  out_stream->codec->codec->name : "copy");  
					av_free_packet(&pkt);     

				}  
			}  
		}
		ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
		if (ret < 0) 
		{
			break;
		}

		av_packet_unref(&pkt);
	}

	av_write_trailer(ofmt_ctx);

	avformat_close_input(&ifmt_ctx);

	if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
	{
		avio_closep(&ofmt_ctx->pb);
	}
	avformat_free_context(ofmt_ctx);
}
*/







int main(int argc ,char ** argv)
{
	int ret = 0;

	av_register_all();
	avformat_network_init();

	ffmpeg_init_demux(INPUTURL,&m_icodec);

	//out_stream1 用原始的
	Out_stream_info *out_stream_info1 = NULL;
	out_stream_info1 = new Out_stream_info();
	out_stream_info1->user_stream_id = 10;
	sprintf(out_stream_info1->m_outurlname,"%s",OUTPUTURL10);
	//out_stream2
	Out_stream_info *out_stream_info2 = NULL;
	out_stream_info2 = new Out_stream_info();
	out_stream_info2->user_stream_id = 11;
	sprintf(out_stream_info2->m_outurlname,"%s",OUTPUTURL11);
	out_stream_info2->m_dwWidth = 640;
	out_stream_info2->m_dwHeight = 480;
	out_stream_info2->m_dbFrameRate = 25;
	out_stream_info2->m_video_codecID = (int)AV_CODEC_ID_H264;
	out_stream_info2->m_video_pixelfromat = (int)AV_PIX_FMT_YUV420P;
	out_stream_info2->m_bit_rate = 800000;
	out_stream_info2->m_gop_size = 125;
	out_stream_info2->m_max_b_frame = 0;
	out_stream_info2->m_thread_count = 8;
	out_stream_info2->m_dwChannelCount = 2;
	out_stream_info2->m_dwBitsPerSample = AV_SAMPLE_FMT_S16_t;
	out_stream_info2->m_dwFrequency = 44100;
	out_stream_info2->m_audio_codecID = (int)AV_CODEC_ID_AAC; 
	//out_stream3
	Out_stream_info *out_stream_info3 = NULL;
	out_stream_info3 = new Out_stream_info();
	out_stream_info3->user_stream_id = 12;
	sprintf(out_stream_info3->m_outurlname,"%s",OUTPUTURL12);
	out_stream_info3->m_dwWidth = 352;
	out_stream_info3->m_dwHeight = 288;
	out_stream_info3->m_dbFrameRate = 25;
	out_stream_info3->m_video_codecID = (int)AV_CODEC_ID_H264;
	out_stream_info3->m_video_pixelfromat = (int)AV_PIX_FMT_YUV420P;
	out_stream_info3->m_bit_rate = 400000;
	out_stream_info3->m_gop_size = 125;
	out_stream_info3->m_max_b_frame = 0;
	out_stream_info3->m_thread_count = 8;
	out_stream_info3->m_dwChannelCount = 2;
	out_stream_info3->m_dwBitsPerSample = AV_SAMPLE_FMT_S16_t;
	out_stream_info3->m_dwFrequency = 44100;
	out_stream_info3->m_audio_codecID = (int)AV_CODEC_ID_AAC; 

	//申请map
	m_list_out_stream_info[out_stream_info1->user_stream_id] = (out_stream_info1);
	m_list_out_stream_info[out_stream_info2->user_stream_id] = (out_stream_info2);
	m_list_out_stream_info[out_stream_info3->user_stream_id] = (out_stream_info3);

	ffmpeg_init_mux(m_list_out_stream_info,out_stream_info1->user_stream_id);
	printf("--------程序运行开始----------\n");
	//////////////////////////////////////////////////////////////////////////
	ffmpeg_transcode(out_stream_info1->user_stream_id);
	//////////////////////////////////////////////////////////////////////////
	ffmpeg_uinit_mux(m_list_out_stream_info,out_stream_info1->user_stream_id);
	ffmpeg_uinit_demux(m_icodec);

	//释放map
	if (m_list_out_stream_info.size()> 0)
	{
		map<int,Out_stream_info*> ::iterator result_all;
		Out_stream_info * out_stream_info_all = NULL;
		for (result_all = m_list_out_stream_info.begin();result_all != m_list_out_stream_info.end();)
		{
			out_stream_info_all = result_all->second;
			if(out_stream_info_all)
			{
				delete out_stream_info_all;
				out_stream_info_all = NULL;          
			}
			m_list_out_stream_info.erase(result_all ++);
		}
		m_list_out_stream_info.clear();
	}
	printf("--------程序运行结束----------\n");
	printf("-------请按任意键退出---------\n");
	return getchar();
}

//.h

#ifndef __FFMPEG_TRANSCODE_H__  
#define __FFMPEG_TRANSCODE_H__  

#include <string.h> 
#include <stdio.h>
#include <vector>
#include <map>
#include <list>

using namespace std;

extern "C"  
{  
#include "libavformat/avformat.h"  
#include "libavformat/avio.h"  
#include "libavcodec/avcodec.h"  
#include "libswscale/swscale.h"  
#include "libavutil/avutil.h"  
#include "libavutil/mathematics.h"  
#include "libswresample/swresample.h"  
#include "libavutil/opt.h"  
#include "libavutil/channel_layout.h"  
#include "libavutil/samplefmt.h"  
#include "libavdevice/avdevice.h"  //摄像头所用  
#include "libavfilter/avfilter.h"  
#include "libavutil/error.h"  
#include "libavutil/mathematics.h"    
#include "libavutil/time.h"    
#include "libavutil/fifo.h"  
#include "libavutil/audio_fifo.h"   //这里是做分片时候重采样编码音频用的  
#include "inttypes.h"  
#include "stdint.h"  
};  

#pragma comment(lib,"avformat.lib")  
#pragma comment(lib,"avcodec.lib")  
#pragma comment(lib,"avdevice.lib")  
#pragma comment(lib,"avfilter.lib")  
#pragma comment(lib,"avutil.lib")  
#pragma comment(lib,"postproc.lib")  
#pragma comment(lib,"swresample.lib")  
#pragma comment(lib,"swscale.lib")  

//#define INPUTURL   "../in_stream/22.flv"   
//#define INPUTURL "../in_stream/闪电侠.The.Flash.S01E01.中英字幕.HDTVrip.624X352.mp4"  
//#define INPUTURL   "../in_stream/33.ts"   
//#define INPUTURL   "../in_stream/22mp4.mp4"   
//#define INPUTURL   "../in_stream/EYED0081.MOV"   
//#define INPUTURL   "../in_stream/李荣浩 - 李白.mp3"   
//#define INPUTURL   "../in_stream/avier1.mp4"   
//#define INPUTURL   "../in_stream/分歧者2预告片.mp4"   
//#define INPUTURL   "../in_stream/Class8简介.m4v"   
#define INPUTURL   "../in_stream/9160_2.ts"   
//#define INPUTURL   "../in_stream/44.mp3"  
//#define INPUTURL   "../in_stream/ceshi.mp4"  
//#define INPUTURL   "../in_stream/33.mp4"  
//#define INPUTURL   "../in_stream/father.avi"  
//#define INPUTURL   "../in_stream/22.flv"  
//#define INPUTURL   "../in_stream/西海情歌.wav"   
//#define INPUTURL   "../in_stream/Furious_7_2015_International_Trailer_2_5.1-1080p-HDTN.mp4"   
//#define INPUTURL   "../in_stream/Wildlife.wmv"   
//#define INPUTURL   "../in_stream/单身男女2.HD1280超清国语版.mp4"   
//#define INPUTURL     "rtmp://221.228.193.50:1935/live/teststream1"   
#define OUTPUTURL  "../out_stream/output.flv" 
//http://10.69.112.96:8080/live/10flv/index.m3u8
#define OUTPUTURL10  "../out_stream/10.flv"
//#define OUTPUTURL10   "rtmp://10.69.112.96:1936/live/10flv"
#define OUTPUTURL11  "../out_stream/11.flv"  
//#define OUTPUTURL11   "rtmp://10.69.112.96:1936/live/11flv"
#define OUTPUTURL12  "../out_stream/12.flv"  
//#define OUTPUTURL12   "rtmp://10.69.112.96:1936/live/12flv"
//#define OUTPUTURL    "rtmp://221.228.193.50:1935/live/zwg"  
//#define OUTPUTURL    "rtmp://221.228.193.50:1935/live/zwg"  


//样本枚举
enum AVSampleFormat_t   
{  
	AV_SAMPLE_FMT_NONE_t = -1,  
	AV_SAMPLE_FMT_U8_t,          ///< unsigned 8 bits  
	AV_SAMPLE_FMT_S16_t,         ///< signed 16 bits  
	AV_SAMPLE_FMT_S32_t,         ///< signed 32 bits  
	AV_SAMPLE_FMT_FLT_t,         ///< float  
	AV_SAMPLE_FMT_DBL_t,         ///< double  

	AV_SAMPLE_FMT_U8P_t,         ///< unsigned 8 bits, planar  
	AV_SAMPLE_FMT_S16P_t,        ///< signed 16 bits, planar  
	AV_SAMPLE_FMT_S32P_t,        ///< signed 32 bits, planar  
	AV_SAMPLE_FMT_FLTP_t,        ///< float, planar  
	AV_SAMPLE_FMT_DBLP_t,        ///< double, planar  

	AV_SAMPLE_FMT_NB_t           ///< Number of sample formats. DO NOT USE if linking dynamically  
};  


#define OUT_AUDIO_ID            0                                                 //packet 中的ID ,如果先加入音频 pocket 则音频是 0  视频是1,否则相反(影响add_out_stream顺序)  
#define OUT_VIDEO_ID            1  

//多路输出每一路的信息结构体
typedef struct Out_stream_info_t
{
	//user info
	int user_stream_id;                 //多路输出每一路的ID
	//video param  
	int m_dwWidth;  
	int m_dwHeight;  
	double m_dbFrameRate;               //帧率                                                    
	int m_video_codecID;  
	int m_video_pixelfromat; 
	int m_bit_rate;                     //码率
	int m_gop_size;  
	int m_max_b_frame;  
	int m_thread_count;                 //用cpu内核数目  
	//audio param  
	int m_dwChannelCount;               //声道  
	AVSampleFormat_t m_dwBitsPerSample; //样本  
	int m_dwFrequency;                  //采样率  
	int m_audio_codecID; 

	//ffmpeg out pram
	AVAudioFifo * m_audiofifo;          //音频存放pcm数据  
	int64_t m_first_audio_pts;          //第一帧的音频pts  
	int m_is_first_audio_pts;           //是否已经记录第一帧音频时间戳  
	AVFormatContext* m_ocodec ;         //输出流context  
	int m_writeheader_seccess;          //写头成功也就是写的头支持里面填写的音视频格式例如采样率等等
	AVStream* m_ovideo_st;                
	AVStream* m_oaudio_st;                
	AVCodec * m_audio_codec;  
	AVCodec * m_video_codec;  
	AVPacket m_pkt;     
	AVBitStreamFilterContext * m_vbsf_aac_adtstoasc;     //aac->adts to asc过滤器  
	struct SwsContext * m_img_convert_ctx_video;  
	int m_sws_flags;                    //差值算法,双三次 
	AVFrame * m_pout_video_frame;  
	AVFrame * m_pout_audio_frame;  
	SwrContext * m_swr_ctx;  
	char m_outurlname[256];             //输出的url地址

	Out_stream_info_t()
	{
		//user info
		user_stream_id = 0;             //多路输出每一路的ID
		//video param  
		m_dwWidth = 640;  
		m_dwHeight = 480;  
		m_dbFrameRate = 25;  //帧率                                                    
		m_video_codecID = (int)AV_CODEC_ID_H264;  
		m_video_pixelfromat = (int)AV_PIX_FMT_YUV420P;  
		m_bit_rate = 400000;                //码率
		m_gop_size = 12;  
		m_max_b_frame = 0;  
		m_thread_count = 2;                 //用cpu内核数目  
		//audio param  
		m_dwChannelCount = 2;               //声道  
		m_dwBitsPerSample = AV_SAMPLE_FMT_S16_t; //样本  
		m_dwFrequency = 44100;              //采样率  
		m_audio_codecID = (int)AV_CODEC_ID_AAC; 

		//ffmpeg out pram  
		m_audiofifo = NULL;                 //音频存放pcm数据  
		m_first_audio_pts = 0;              //第一帧的音频pts  
		m_is_first_audio_pts = 0;           //是否已经记录第一帧音频时间戳  
		m_ocodec = NULL;                    //输出流context 
		m_writeheader_seccess = 0; 
		m_ovideo_st = NULL;                
		m_oaudio_st = NULL;                
		m_audio_codec = NULL;  
		m_video_codec = NULL;  
		//m_pkt;     
		m_vbsf_aac_adtstoasc = NULL;        //aac->adts to asc过滤器  
		m_img_convert_ctx_video = NULL;  
		m_sws_flags = SWS_BICUBIC;          //差值算法,双三次  
		m_pout_video_frame = NULL;  
		m_pout_audio_frame = NULL; 
		m_swr_ctx = NULL;
		memset(m_outurlname,0,256);         //清零
	}
}Out_stream_info;


extern AVFormatContext* m_icodec;                         //输入流context  
extern int m_in_dbFrameRate;                              //输入流的帧率
extern int m_in_video_stream_idx;                         //输入流的视频序列号  
extern int m_in_audio_stream_idx;                         //输入流的音频序列号
extern int m_in_video_starttime;                          //输入流的视频起始时间
extern int m_in_audio_starttime;                          //输入流的音频起始时间
extern AVPacket m_in_pkt;                                 //读取输入文件packet
extern map<int,Out_stream_info*> m_list_out_stream_info;  //多路输出的list

//初始化demux
int ffmpeg_init_demux(char * inurlname,AVFormatContext ** iframe_c); 
//释放demux
int ffmpeg_uinit_demux(AVFormatContext * iframe_c);
//初始化mux:list,原始流只需要copy的
int ffmpeg_init_mux(map<int,Out_stream_info*> list_out_stream_info,int original_user_stream_id);  
//释放mux,原始流只需要copy的不用打开编码器
int ffmpeg_uinit_mux(map<int,Out_stream_info*> list_out_stream_info,int original_user_stream_id);  

//for mux copy 
AVStream * ffmpeg_add_out_stream(AVFormatContext* output_format_context,AVMediaType codec_type_t);   
//for codec  
AVStream * ffmpeg_add_out_stream2(Out_stream_info * out_stream_info,AVMediaType codec_type_t,AVCodec **codec);   
int ffmpeg_init_decode(int stream_type);  
int ffmpeg_init_code(int stream_type,AVStream* out_stream,AVCodec * out_codec);  
int ffmpeg_uinit_decode(int stream_type);  
int ffmpeg_uinit_code(int stream_type,AVStream* out_stream); 
//转码数据,原始流只需要copy的
int ffmpeg_transcode(int original_user_stream_id);


//下面是转码数据里面用的
int ffmpeg_perform_decode(int stream_type,AVFrame * picture);   
int ffmpeg_perform_code2(Out_stream_info * out_stream_info,int stream_type,AVFrame * picture);  //用于AVAudioFifo 
void ffmpeg_perform_yuv_conversion(Out_stream_info * out_stream_info,AVFrame * pinframe,AVFrame * poutframe); 
SwrContext * ffmpeg_init_pcm_resample(Out_stream_info * out_stream_info,AVFrame *in_frame, AVFrame *out_frame);  
int ffmpeg_preform_pcm_resample(Out_stream_info * out_stream_info,SwrContext * pSwrCtx,AVFrame *in_frame, AVFrame *out_frame); 
void ffmpeg_uinit_pcm_resample(SwrContext * swr_ctx,AVAudioFifo * audiofifo);
void ffmpeg_write_frame(Out_stream_info * out_stream_info,int ID,AVPacket pkt_t);        //copy
void ffmpeg_write_frame2(Out_stream_info * out_stream_info,int ID,AVPacket pkt_t);       //codec

#endif 

//.cpp

#include "ffmpeg_transcode.h"  

AVFormatContext* m_icodec = NULL;                            //输入流context  
int m_in_dbFrameRate = 0;                                    //输入流的帧率
int m_in_video_stream_idx = -1;                              //输入流的视频序列号  
int m_in_audio_stream_idx = -1;                              //输入流的音频序列号
int m_in_video_starttime = 0;                                //输入流的视频起始时间
int m_in_audio_starttime = 0;                                //输入流的音频起始时间
AVPacket m_in_pkt;                                           //读取输入文件packet
map<int,Out_stream_info*> m_list_out_stream_info ;           //多路输出的list
static FILE * pcm_file = NULL;                               //测试存储pcm用

int ffmpeg_init_demux(char * inurlname,AVFormatContext ** iframe_c)
{  
	int ret = 0;
	int i = 0;  
	ret = avformat_open_input(iframe_c, inurlname,NULL, NULL);  
	if (ret != 0)
	{
		printf("Call avformat_open_input function failed!\n");  
		return 0;  
	}  
	if (avformat_find_stream_info(*iframe_c,NULL) < 0)  
	{  
		printf("Call av_find_stream_info function failed!\n");  
		return 0;  
	}  
	//输出视频信息  
	av_dump_format(*iframe_c, -1, inurlname, 0);  

	//添加音频信息到输出context  
	for (i = 0; i < (*iframe_c)->nb_streams; i++)  
	{  
		if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
		{  
			double FrameRate = (*iframe_c)->streams[i]->r_frame_rate.num /(double)(*iframe_c)->streams[i]->r_frame_rate.den;  
			m_in_dbFrameRate =(int)(FrameRate + 0.5);   
			m_in_video_stream_idx = i;  
			m_in_video_starttime = (*iframe_c)->streams[i]->start_time;
		}  
		else if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)  
		{  
			m_in_audio_stream_idx = i;  
			m_in_audio_starttime = (*iframe_c)->streams[i]->start_time;
		}  
	}  

	return 1;  
}  

int ffmpeg_uinit_demux(AVFormatContext * iframe_c)  
{  
	/* free the stream */  
	av_free(iframe_c);  
	return 1;  
}  

int ffmpeg_init_mux(map<int,Out_stream_info*> list_out_stream_info,int original_user_stream_id)
{
	int ret = 0;
	int i = 0;  

	if (list_out_stream_info.size()> 0)
	{
		map<int,Out_stream_info*> ::iterator result_all;
		Out_stream_info * out_stream_info_all = NULL;
		for (result_all = list_out_stream_info.begin();result_all != list_out_stream_info.end();)
		{
			out_stream_info_all = result_all->second;
			//如果存在输出
			if(out_stream_info_all)
			{
				/* allocate the output media context */  
				if (strstr(out_stream_info_all->m_outurlname,"rtmp"))
				{
					avformat_alloc_output_context2(&out_stream_info_all->m_ocodec, NULL,"flv", out_stream_info_all->m_outurlname);  
				}
				else
				{
					avformat_alloc_output_context2(&out_stream_info_all->m_ocodec, NULL,NULL, out_stream_info_all->m_outurlname);  
				} 
				if (!out_stream_info_all->m_ocodec)   
				{  
					return getchar();  
				}  
				AVOutputFormat* ofmt = NULL;  
				ofmt = out_stream_info_all->m_ocodec->oformat;  

				/* open the output file, if needed */  
				if (!(ofmt->flags & AVFMT_NOFILE))  
				{  
					if (avio_open(&out_stream_info_all->m_ocodec->pb, out_stream_info_all->m_outurlname, AVIO_FLAG_WRITE) < 0)  
					{  
						printf("Could not open ‘%s‘\n", out_stream_info_all->m_outurlname);  
						return getchar();  
					}  
				} 

				//原始流只需要copy的
				if(out_stream_info_all->user_stream_id == original_user_stream_id)
				{
					//这里添加的时候AUDIO_ID/VIDEO_ID有影响  
					//添加音频信息到输出context  
					if(m_in_audio_stream_idx != -1)//如果输入存在音频  
					{   
						out_stream_info_all->m_oaudio_st = ffmpeg_add_out_stream(out_stream_info_all->m_ocodec, AVMEDIA_TYPE_AUDIO); 

						if ((strstr(out_stream_info_all->m_ocodec->oformat->name, "flv") != NULL) ||   
							(strstr(out_stream_info_all->m_ocodec->oformat->name, "mp4") != NULL) ||   
							(strstr(out_stream_info_all->m_ocodec->oformat->name, "mov") != NULL) ||  
							(strstr(out_stream_info_all->m_ocodec->oformat->name, "3gp") != NULL))      
						{  
							if (out_stream_info_all->m_oaudio_st->codec->codec_id == AV_CODEC_ID_AAC)   
							{  
								out_stream_info_all->m_vbsf_aac_adtstoasc =  av_bitstream_filter_init("aac_adtstoasc");    
								if(out_stream_info_all->m_vbsf_aac_adtstoasc == NULL)    
								{    
									return -1;    
								}   
							}  
						}  

						//传给外层结构体
						out_stream_info_all->m_dwChannelCount = out_stream_info_all->m_oaudio_st->codec->channels;
						out_stream_info_all->m_dwBitsPerSample = (AVSampleFormat_t)out_stream_info_all->m_oaudio_st->codec->sample_fmt;
						out_stream_info_all->m_dwFrequency = out_stream_info_all->m_oaudio_st->codec->sample_rate;
						out_stream_info_all->m_audio_codecID = (int)out_stream_info_all->m_oaudio_st->codec->codec_id; 
					}  

					//添加视频信息到输出context  
					if (m_in_video_stream_idx != -1)//如果存在视频  
					{    
						out_stream_info_all->m_ovideo_st = ffmpeg_add_out_stream(out_stream_info_all->m_ocodec,AVMEDIA_TYPE_VIDEO);  

						//传给外层结构体
						out_stream_info_all->m_dwWidth = out_stream_info_all->m_ovideo_st->codec->width;
						out_stream_info_all->m_dwHeight = out_stream_info_all->m_ovideo_st->codec->height;
						out_stream_info_all->m_dbFrameRate = m_in_dbFrameRate;
						out_stream_info_all->m_video_codecID = (int)out_stream_info_all->m_ovideo_st->codec->codec_id;
						out_stream_info_all->m_video_pixelfromat = (int)out_stream_info_all->m_ovideo_st->codec->pix_fmt;
						out_stream_info_all->m_bit_rate = out_stream_info_all->m_ovideo_st->codec->bit_rate;
						out_stream_info_all->m_gop_size = out_stream_info_all->m_ovideo_st->codec->gop_size;
						out_stream_info_all->m_max_b_frame = out_stream_info_all->m_ovideo_st->codec->max_b_frames;
					}
				}
				else
				{
					//这里添加的时候AUDIO_ID/VIDEO_ID有影响  
					//添加音频信息到输出context  
					if(m_in_audio_stream_idx != -1)//如果输入存在音频  
					{   
						//添加流
						out_stream_info_all->m_oaudio_st = ffmpeg_add_out_stream2(out_stream_info_all, AVMEDIA_TYPE_AUDIO,
							&out_stream_info_all->m_audio_codec); 

						if ((strstr(out_stream_info_all->m_ocodec->oformat->name, "flv") != NULL) ||   
							(strstr(out_stream_info_all->m_ocodec->oformat->name, "mp4") != NULL) ||   
							(strstr(out_stream_info_all->m_ocodec->oformat->name, "mov") != NULL) ||  
							(strstr(out_stream_info_all->m_ocodec->oformat->name, "3gp") != NULL))      
						{  
							if (out_stream_info_all->m_oaudio_st->codec->codec_id == AV_CODEC_ID_AAC)   
							{  
								out_stream_info_all->m_vbsf_aac_adtstoasc =  av_bitstream_filter_init("aac_adtstoasc");    
								if(out_stream_info_all->m_vbsf_aac_adtstoasc == NULL)    
								{    
									return -1;    
								}   
							}  
						}  
 
						//编码初始化  
						ret = ffmpeg_init_code(OUT_AUDIO_ID,out_stream_info_all->m_oaudio_st,out_stream_info_all->m_audio_codec); 
					}  

					//添加视频信息到输出context  
					if (m_in_video_stream_idx != -1)//如果存在视频  
					{    
						//添加流
						out_stream_info_all->m_ovideo_st = ffmpeg_add_out_stream2(out_stream_info_all, AVMEDIA_TYPE_VIDEO,
							&out_stream_info_all->m_video_codec);
						//编码初始化  
						ret = ffmpeg_init_code(OUT_VIDEO_ID,out_stream_info_all->m_ovideo_st,out_stream_info_all->m_video_codec); 
					}  
				}

				//写头
				ret = avformat_write_header(out_stream_info_all->m_ocodec, NULL);  
				if (ret != 0)  
				{  
					out_stream_info_all->m_writeheader_seccess = 0;
					printf("Call avformat_write_header function failed.user_stream_id : %d\n",out_stream_info_all->user_stream_id);    
				} 
				else
				{
					out_stream_info_all->m_writeheader_seccess = 1;
				}

				//输出信息
				av_dump_format(out_stream_info_all->m_ocodec, 0, out_stream_info_all->m_outurlname, 1); 
			}   
			result_all ++;
		}
	}  

	//解码初始化  
	ret = ffmpeg_init_decode(OUT_AUDIO_ID); 
	//解码初始化  
	ret = ffmpeg_init_decode(OUT_VIDEO_ID);  

	ret = 1;
	return ret;
}

int ffmpeg_uinit_mux(map<int,Out_stream_info*> list_out_stream_info,int original_user_stream_id)
{
	int ret = 0;
	int i = 0;  

	if (m_list_out_stream_info.size()> 0)
	{
		map<int,Out_stream_info*> ::iterator result_all;
		Out_stream_info * out_stream_info_all = NULL;
		for (result_all = m_list_out_stream_info.begin();result_all != m_list_out_stream_info.end();)
		{
			out_stream_info_all = result_all->second;
			//如果存在输出
			if(out_stream_info_all && out_stream_info_all->m_writeheader_seccess == 1)
			{
				ret = av_write_trailer(out_stream_info_all->m_ocodec);  
				if (ret < 0)  
				{  
					printf("Call av_write_trailer function failed\n");  
					return getchar();
				}  
				if (out_stream_info_all->m_vbsf_aac_adtstoasc !=NULL)  
				{  
					av_bitstream_filter_close(out_stream_info_all->m_vbsf_aac_adtstoasc);   
					out_stream_info_all->m_vbsf_aac_adtstoasc = NULL;  
				}  
				av_dump_format(out_stream_info_all->m_ocodec, -1, out_stream_info_all->m_outurlname, 1);   

				if (m_in_video_stream_idx != -1)//如果存在视频  
				{  
					//原始流只需要copy的不用打开编码器
					if(out_stream_info_all->user_stream_id == original_user_stream_id)
					{
					}
					else
					{
						ffmpeg_uinit_decode(m_in_video_stream_idx);  
						ffmpeg_uinit_code(OUT_VIDEO_ID,out_stream_info_all->m_ovideo_st);
					}  
				}  
				if(m_in_audio_stream_idx != -1)//如果存在音频  
				{  
					//原始流只需要copy的不用打开编码器
					if(out_stream_info_all->user_stream_id == original_user_stream_id)
					{
					}
					else
					{
						ffmpeg_uinit_decode(m_in_audio_stream_idx);  
						ffmpeg_uinit_code(OUT_AUDIO_ID,out_stream_info_all->m_oaudio_st);  
					}  
				}  
				/* Free the streams. */  
				for (i = 0; i < out_stream_info_all->m_ocodec->nb_streams; i++)   
				{  
					av_freep(&out_stream_info_all->m_ocodec->streams[i]->codec);  
					av_freep(&out_stream_info_all->m_ocodec->streams[i]);  
				}  
				if (!(out_stream_info_all->m_ocodec->oformat->flags & AVFMT_NOFILE))  
				{  
					/* Close the output file. */  
					avio_close(out_stream_info_all->m_ocodec->pb);  
				}  
				av_free(out_stream_info_all->m_ocodec);  

				out_stream_info_all->m_writeheader_seccess = 0;
			}
			result_all ++;
		}
	}
	ret = 1;
	return ret;
}

AVStream * ffmpeg_add_out_stream(AVFormatContext* output_format_context,AVMediaType codec_type_t)
{
	int ret = 0;
	AVStream * in_stream = NULL;  
	AVStream * output_stream = NULL;  
	AVCodecContext* output_codec_context = NULL;  

	switch (codec_type_t)  
	{  
	case AVMEDIA_TYPE_AUDIO:  
		in_stream = m_icodec->streams[m_in_audio_stream_idx];  
		break;  
	case AVMEDIA_TYPE_VIDEO:  
		in_stream = m_icodec->streams[m_in_video_stream_idx];  
		break;  
	default:  
		break;  
	}  

	output_stream = avformat_new_stream(output_format_context,in_stream->codec->codec);  
	if (!output_stream)  
	{  
		return NULL;  
	}  

	output_stream->id = output_format_context->nb_streams - 1;  
	output_codec_context = output_stream->codec;  
 
	ret = avcodec_copy_context(output_stream->codec, in_stream->codec);  
	if (ret < 0)   
	{  
		printf("Failed to copy context from input to output stream codec context\n");  
		return NULL;  
	}

	//这个很重要,要么纯复用解复用,不做编解码写头会失败,  
	//另或者需要编解码如果不这样,生成的文件没有预览图,还有添加下面的header失败,置0之后会重新生成extradata  
	output_codec_context->codec_tag = 0;   

	//if(! strcmp( output_format_context-> oformat-> name,  "mp4" ) ||  
	//!strcmp (output_format_context ->oformat ->name , "mov" ) ||  
	//!strcmp (output_format_context ->oformat ->name , "3gp" ) ||  
	//!strcmp (output_format_context ->oformat ->name , "flv"))  
	if(AVFMT_GLOBALHEADER & output_format_context->oformat->flags)  
	{  
		output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;  
	}  

	return output_stream;  
}

AVStream * ffmpeg_add_out_stream2(Out_stream_info * out_stream_info,AVMediaType codec_type_t,AVCodec **codec)
{
	int ret = 0;
	AVCodecContext* output_codec_context = NULL;  
	AVStream * in_stream = NULL;  
	AVStream * output_stream = NULL;  
	AVCodecID codecID;  

	switch (codec_type_t)  
	{  
	case AVMEDIA_TYPE_AUDIO:  
		codecID = (AVCodecID)out_stream_info->m_audio_codecID;  
		in_stream = m_icodec->streams[m_in_audio_stream_idx];  
		break;  
	case AVMEDIA_TYPE_VIDEO:  
		codecID = (AVCodecID)out_stream_info->m_video_codecID;  
		in_stream = m_icodec->streams[m_in_video_stream_idx];  
		break;  
	default:  
		break;  
	}  

	/* find the encoder */  
	*codec = avcodec_find_encoder(codecID);  
	if (!(*codec))   
	{  
		return NULL;  
	}  

	output_stream = avformat_new_stream(out_stream_info->m_ocodec,*codec);  
	if (!output_stream)  
	{  
		return NULL;  
	}  

	output_stream->id = out_stream_info->m_ocodec->nb_streams - 1;  
	output_codec_context = output_stream->codec;  

	switch (codec_type_t)  
	{  
	case AVMEDIA_TYPE_AUDIO:  
		output_codec_context->codec_id = (AVCodecID)out_stream_info->m_audio_codecID;  
		output_codec_context->codec_type = codec_type_t;  
		AVRational time_base_in;
		time_base_in.num =1;
		if(!strcmp(out_stream_info->m_ocodec->oformat-> name,"mpegts" ))
		{
			time_base_in.den = 90*1000;
		}
		else
		{
			time_base_in.den = 1000;
		}
		output_stream->start_time = av_rescale_q_rnd(m_in_audio_starttime, in_stream->time_base, time_base_in, AV_ROUND_NEAR_INF);
		output_codec_context->sample_rate = out_stream_info->m_dwFrequency;//m_icodec->streams[m_in_audio_stream_idx]->codec->sample_rate;//m_dwFrequency;  
		output_codec_context->channels  = out_stream_info->m_dwChannelCount;  
		output_codec_context->channel_layout = av_get_default_channel_layout(out_stream_info->m_dwChannelCount);	  
		//这个码率有些编码器不支持特别大,例如wav的码率是1411200 比aac大了10倍多  
		output_codec_context->bit_rate = 128000;//icodec->streams[audio_stream_idx]->codec->bit_rate;   
		output_codec_context->sample_fmt  = (AVSampleFormat)out_stream_info->m_dwBitsPerSample; //样本  
		output_codec_context->block_align = 0;  
		break;  
	case AVMEDIA_TYPE_VIDEO:  
		AVRational r_frame_rate_t;  
		r_frame_rate_t.num = 100;  
		r_frame_rate_t.den = (int)(out_stream_info->m_dbFrameRate * 100);  
		output_codec_context->time_base.num = 1;  
		output_codec_context->time_base.den = out_stream_info->m_dbFrameRate;  
		output_stream->r_frame_rate.num = r_frame_rate_t.den;  
		output_stream->r_frame_rate.den = r_frame_rate_t.num;  
		output_codec_context->codec_id = (AVCodecID)out_stream_info->m_video_codecID; 
		output_codec_context->codec_type = codec_type_t;  
		if(!strcmp(out_stream_info->m_ocodec->oformat-> name,"mpegts" ))
		{
			time_base_in.den = 90*1000;
		}
		else
		{
			time_base_in.den = 1000;
		}
		output_stream->start_time = av_rescale_q_rnd(m_in_audio_starttime, in_stream->time_base, time_base_in, AV_ROUND_NEAR_INF);
		output_codec_context->pix_fmt = (AVPixelFormat)out_stream_info->m_video_pixelfromat;  
		output_codec_context->width = out_stream_info->m_dwWidth;  
		output_codec_context->height = out_stream_info->m_dwHeight;  
		output_codec_context->bit_rate = out_stream_info->m_bit_rate;  
		output_codec_context->gop_size  = out_stream_info->m_gop_size;         /* emit one intra frame every twelve frames at most */;  
		output_codec_context->max_b_frames = out_stream_info->m_max_b_frame;    //设置B帧最大数  
		output_codec_context->thread_count = out_stream_info->m_thread_count;  //线程数目  
		output_codec_context->me_range = 16;  
		output_codec_context->max_qdiff = 4;  
		output_codec_context->qmin = 20; //调节清晰度和编码速度 //这个值调节编码后输出数据量越大输出数据量越小,越大编码速度越快,清晰度越差  
		output_codec_context->qmax = 40; //调节清晰度和编码速度  
		output_codec_context->qcompress = 0.6;   
		//设置profile
		output_codec_context->profile = FF_PROFILE_H264_BASELINE;
		output_codec_context->level = 30;
		break;  
	default:  
		break;  
	}  
	//这个很重要,要么纯复用解复用,不做编解码写头会失败,  
	//另或者需要编解码如果不这样,生成的文件没有预览图,还有添加下面的header失败,置0之后会重新生成extradata  
	output_codec_context->codec_tag = 0;   
	//if(! strcmp( output_format_context-> oformat-> name,  "mp4" ) ||  
	//  !strcmp (output_format_context ->oformat ->name , "mov" ) ||  
	//  !strcmp (output_format_context ->oformat ->name , "3gp" ) ||  
	//  !strcmp (output_format_context ->oformat ->name , "flv" ))  
	if(AVFMT_GLOBALHEADER & out_stream_info->m_ocodec->oformat->flags)  
	{  
		output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;  
	}  
	return output_stream;  
}

int ffmpeg_init_decode(int stream_type)
{
	int ret = 0;
	AVCodec *pcodec = NULL;  
	AVCodecContext *cctext = NULL;  

	if (stream_type == OUT_AUDIO_ID)  
	{  
		cctext = m_icodec->streams[m_in_audio_stream_idx]->codec;  
		pcodec = avcodec_find_decoder(cctext->codec_id);  
		if (!pcodec)   
		{  
			return -1;  
		}  
	}  
	else if (stream_type == OUT_VIDEO_ID)  
	{  
		cctext = m_icodec->streams[m_in_video_stream_idx]->codec;  
		pcodec = avcodec_find_decoder(cctext->codec_id);  
		if (!pcodec)   
		{  
			return -1;  
		}  
	} 

	////实时解码关键看这句
	//cctext->flags |= CODEC_FLAG_LOW_DELAY;
	//cctext->flags2 |= CODEC_FLAG2_FAST;

	//打开解码器  
	ret = avcodec_open2(cctext, pcodec, NULL);   
	if (ret < 0)  
	{  
		printf("Could not open decoder\n");  
		return -1;  
	}  

	ret = 1; 
	return ret;
}

int ffmpeg_init_code(int stream_type,AVStream* out_stream,AVCodec * out_codec)
{
	int ret = 0;
	AVCodecContext *cctext = NULL;  

	if (stream_type == OUT_AUDIO_ID)  
	{  
		cctext = out_stream->codec; 

		//实时编码关键看这句
		av_opt_set(cctext->priv_data, "tune", "zerolatency", 0);
		//设置profile
		av_opt_set(cctext->priv_data, "profile", "baseline", AV_OPT_SEARCH_CHILDREN);

		//打开编码器  
		ret = avcodec_open2(cctext, out_codec, NULL);   
		if (ret < 0)  
		{  
			printf("Could not open encoder\n");  
			return 0;  
		}  
	}  
	else if (stream_type == OUT_VIDEO_ID)  
	{  
		cctext = out_stream->codec; 

		//实时编码关键看这句
		av_opt_set(cctext->priv_data, "tune", "zerolatency", 0);
		//设置profile
		av_opt_set(cctext->priv_data, "profile", "baseline", AV_OPT_SEARCH_CHILDREN);

		//打开编码器  
		ret = avcodec_open2(cctext, out_codec, NULL);   
		if (ret < 0)  
		{  
			printf("Could not open encoder\n");  
			return -1;  
		}  
	}  
	ret = 1;

	return ret;
}

int ffmpeg_uinit_decode(int stream_type)
{
	int ret = 0;

	AVCodecContext *cctext = NULL;  

	if (stream_type == m_in_audio_stream_idx)  
	{  
		cctext = m_icodec->streams[m_in_audio_stream_idx]->codec;   
	}  
	else if (stream_type == m_in_video_stream_idx)  
	{  
		cctext = m_icodec->streams[m_in_video_stream_idx]->codec;   
	}  
	avcodec_close(cctext);  

	ret = 1;
	return ret;
}

int ffmpeg_uinit_code(int stream_type,AVStream* out_stream)
{
	int ret = 0;
	AVCodecContext *cctext = NULL;  

	if (stream_type == OUT_AUDIO_ID)  
	{  
		cctext = out_stream->codec;   
	}  
	else if (stream_type == OUT_VIDEO_ID)  
	{  
		cctext = out_stream->codec;   
	}  
	avcodec_close(cctext);  
	
	ret = 1; 
	return ret;
}

int ffmpeg_perform_decode(int stream_type,AVFrame * picture)
{
	int ret = 0;
	AVCodecContext *cctext = NULL;  
	int frameFinished = 0 ;   

	if (stream_type == OUT_AUDIO_ID)  
	{  
		cctext = m_icodec->streams[m_in_audio_stream_idx]->codec;

		m_in_pkt.pts = av_rescale_q_rnd(m_in_pkt.pts, m_icodec->streams[m_in_audio_stream_idx]->time_base, cctext->time_base, AV_ROUND_NEAR_INF);  
		m_in_pkt.dts = av_rescale_q_rnd(m_in_pkt.dts, m_icodec->streams[m_in_audio_stream_idx]->time_base, cctext->time_base, AV_ROUND_NEAR_INF);

		avcodec_decode_audio4(cctext,picture,&frameFinished,&m_in_pkt);  
		if(frameFinished)  
		{  
			return 0;  
		}  
	}  
	else if (stream_type == OUT_VIDEO_ID)  
	{  
		cctext = m_icodec->streams[m_in_video_stream_idx]->codec; 

		m_in_pkt.pts = av_rescale_q_rnd(m_in_pkt.pts, m_icodec->streams[m_in_video_stream_idx]->time_base, cctext->time_base, AV_ROUND_NEAR_INF);  
		m_in_pkt.dts = av_rescale_q_rnd(m_in_pkt.dts, m_icodec->streams[m_in_video_stream_idx]->time_base, cctext->time_base, AV_ROUND_NEAR_INF);

		avcodec_decode_video2(cctext,picture,&frameFinished,&m_in_pkt);  
		if(frameFinished)  
		{  
			return 0;  
		}  
	}   
	ret = 1;
	return ret;
}

int ffmpeg_perform_code2(Out_stream_info * out_stream_info,int stream_type,AVFrame * picture)
{
	int ret = 0;
	AVCodecContext *cctext = NULL;  
	AVPacket pkt_t;  
	av_init_packet(&pkt_t);  
	pkt_t.data = http://www.mamicode.com/NULL; // packet data will be allocated by the encoder  >

如有错误请指正:

交流请加QQ群:62054820
QQ:379969650.



ffmpeg转码多路输出(二)