ffmpeg转码多路输出(二)

来源:互联网 发布:漫步者煲机软件 编辑:程序博客网 时间:2024/05/29 04:23

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_stream2Out_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_stream3Out_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; //申请mapm_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);//释放mapif (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 infoint 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 pramAVAudioFifo * 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 infouser_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;                                 //读取输入文件packetextern map<int,Out_stream_info*> m_list_out_stream_info;  //多路输出的list//初始化demuxint ffmpeg_init_demux(char * inurlname,AVFormatContext ** iframe_c); //释放demuxint 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);        //copyvoid 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;                                           //读取输入文件packetmap<int,Out_stream_info*> m_list_out_stream_info ;           //多路输出的liststatic 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;   //设置profileoutput_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);//设置profileav_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);//设置profileav_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 = NULL; // packet data will be allocated by the encoder  pkt_t.size = 0;  int frameFinished = 0 ;  if (stream_type == OUT_AUDIO_ID)  {  cctext = out_stream_info->m_oaudio_st->codec;int64_t pts_t = picture->pts;  int duration_t = 0;  //要编码的一帧持续时间duration_t = (double)cctext->frame_size * (out_stream_info->m_oaudio_st->codec->time_base.den /out_stream_info->m_oaudio_st->codec->time_base.num)/   out_stream_info->m_oaudio_st->codec->sample_rate;  AVFrame * pFrameResample = avcodec_alloc_frame();  pFrameResample = av_frame_alloc();  pFrameResample->nb_samples     = cctext->frame_size;  pFrameResample->channel_layout = cctext->channel_layout;  pFrameResample->channels = cctext->channels;  pFrameResample->format         = cctext->sample_fmt;  pFrameResample->sample_rate    = cctext->sample_rate;  int error = 0;  if ((error = av_frame_get_buffer(pFrameResample, 0)) < 0)  {  av_frame_free(&pFrameResample);  return error;  }  while (av_audio_fifo_size(out_stream_info->m_audiofifo) >= pFrameResample->nb_samples) //取出写入的未读的包  {  av_audio_fifo_read(out_stream_info->m_audiofifo,(void **)pFrameResample->data,pFrameResample->nb_samples);  if(out_stream_info->m_is_first_audio_pts == 0)  {  out_stream_info->m_first_audio_pts = pts_t; out_stream_info->m_is_first_audio_pts = 1;  }  pFrameResample->pts = out_stream_info->m_first_audio_pts; out_stream_info->m_first_audio_pts += duration_t;  pFrameResample->pkt_pts = pFrameResample->pts;pFrameResample->pkt_dts = pFrameResample->pts;ret = avcodec_encode_audio2(cctext,&pkt_t,pFrameResample,&frameFinished);  if (ret>=0 && frameFinished)  {  ffmpeg_write_frame2(out_stream_info,OUT_AUDIO_ID,pkt_t); av_free_packet(&pkt_t);  }  } if (pFrameResample)  {  av_frame_free(&pFrameResample);  pFrameResample = NULL;  }  }  else if (stream_type == OUT_VIDEO_ID)  {  cctext = out_stream_info->m_ovideo_st->codec;  picture->pts = av_rescale_q_rnd(picture->pts, m_icodec->streams[m_in_video_stream_idx]->codec->time_base, out_stream_info->m_ovideo_st->codec->time_base, AV_ROUND_NEAR_INF);  picture->pkt_pts = picture->pts;picture->pkt_dts = picture->pts;avcodec_encode_video2(cctext,&pkt_t,picture,&frameFinished);  picture->pts++;  if (frameFinished)  {  ffmpeg_write_frame2(out_stream_info,OUT_VIDEO_ID,pkt_t);  av_free_packet(&pkt_t);  }   }  ret = 1;return ret;}void ffmpeg_perform_yuv_conversion(Out_stream_info * out_stream_info,AVFrame * pinframe,AVFrame * poutframe){int ret = 0;//设置转换context  if (out_stream_info->m_img_convert_ctx_video == NULL)     {  out_stream_info->m_img_convert_ctx_video = sws_getContext(m_icodec->streams[m_in_video_stream_idx]->codec->width, m_icodec->streams[m_in_video_stream_idx]->codec->height,   m_icodec->streams[m_in_video_stream_idx]->codec->pix_fmt,  out_stream_info->m_dwWidth, out_stream_info->m_dwHeight,  (AVPixelFormat)out_stream_info->m_video_pixelfromat,  out_stream_info->m_sws_flags, NULL, NULL, NULL);  if (out_stream_info->m_img_convert_ctx_video == NULL)  {  printf("Cannot initialize the conversion context\n");  }  }  //开始转换  sws_scale(out_stream_info->m_img_convert_ctx_video, pinframe->data, pinframe->linesize,           0, m_icodec->streams[m_in_video_stream_idx]->codec->height, poutframe->data, poutframe->linesize);  poutframe->pkt_pts = pinframe->pkt_pts;  poutframe->pkt_dts = pinframe->pkt_dts;  //有时pkt_pts和pkt_dts不同,并且pkt_pts是编码前的dts,这里要给avframe传入pkt_dts而不能用pkt_pts  //poutframe->pts = poutframe->pkt_pts;  poutframe->pts = pinframe->pkt_dts;  poutframe->key_frame = pinframe->key_frame;if (poutframe->key_frame == 1){poutframe->pict_type = AV_PICTURE_TYPE_I;}else{poutframe->pict_type = AV_PICTURE_TYPE_P;}ret = 1;return;}SwrContext * ffmpeg_init_pcm_resample(Out_stream_info * out_stream_info,AVFrame *in_frame, AVFrame *out_frame){SwrContext * swr_ctx = NULL;  swr_ctx = swr_alloc();  if (!swr_ctx)  {  printf("swr_alloc error \n");  return NULL;  }  AVCodecContext * audio_dec_ctx = m_icodec->streams[m_in_audio_stream_idx]->codec;  AVSampleFormat sample_fmt;  sample_fmt = (AVSampleFormat)out_stream_info->m_dwBitsPerSample; //样本  int out_channel_layout = av_get_default_channel_layout(out_stream_info->m_dwChannelCount);if (audio_dec_ctx->channel_layout == 0)  {  audio_dec_ctx->channel_layout = av_get_default_channel_layout(m_icodec->streams[m_in_audio_stream_idx]->codec->channels);  }  /* set options */  av_opt_set_int(swr_ctx, "in_channel_layout",    audio_dec_ctx->channel_layout, 0);  av_opt_set_int(swr_ctx, "in_sample_rate",       audio_dec_ctx->sample_rate, 0);  av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", audio_dec_ctx->sample_fmt, 0);  av_opt_set_int(swr_ctx, "out_channel_layout",   out_channel_layout, 0);   av_opt_set_int(swr_ctx, "out_sample_rate",       out_stream_info->m_dwFrequency, 0);  av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", sample_fmt, 0);  swr_init(swr_ctx);  int64_t src_nb_samples = in_frame->nb_samples; //计算输出的samples 和采样率有关 例如:48000转44100,samples则是从1152转为1059,除法out_frame->nb_samples = av_rescale_rnd(src_nb_samples, out_stream_info->m_dwFrequency, audio_dec_ctx->sample_rate, AV_ROUND_UP);int ret = av_samples_alloc(out_frame->data, &out_frame->linesize[0],   out_stream_info->m_dwChannelCount, out_frame->nb_samples,out_stream_info->m_oaudio_st->codec->sample_fmt,1);  if (ret < 0)  {  return NULL;  }  out_stream_info->m_audiofifo  = av_audio_fifo_alloc(out_stream_info->m_oaudio_st->codec->sample_fmt, out_stream_info->m_oaudio_st->codec->channels,  out_frame->nb_samples);   return swr_ctx;  }int ffmpeg_preform_pcm_resample(Out_stream_info * out_stream_info,SwrContext * pSwrCtx,AVFrame *in_frame, AVFrame *out_frame){int ret = 0;int samples_out_per_size = 0;              //转换之后的samples大小  if (pSwrCtx != NULL)   {  //这里注意下samples_out_per_size这个值和 out_frame->nb_samples这个值有时候不一样,ffmpeg里面做了策略不是问题。samples_out_per_size = swr_convert(pSwrCtx, out_frame->data, out_frame->nb_samples,   (const uint8_t**)in_frame->data, in_frame->nb_samples);  if (samples_out_per_size < 0)  {  return -1;  }  AVCodecContext * audio_dec_ctx = m_icodec->streams[m_in_audio_stream_idx]->codec; int buffersize_in = av_samples_get_buffer_size(&in_frame->linesize[0],audio_dec_ctx->channels,  in_frame->nb_samples, audio_dec_ctx->sample_fmt, 1);//修改分包内存  int buffersize_out = av_samples_get_buffer_size(&out_frame->linesize[0], out_stream_info->m_oaudio_st->codec->channels,  samples_out_per_size, out_stream_info->m_oaudio_st->codec->sample_fmt, 1); int fifo_size = av_audio_fifo_size(out_stream_info->m_audiofifo);  fifo_size = av_audio_fifo_realloc(out_stream_info->m_audiofifo, av_audio_fifo_size(out_stream_info->m_audiofifo) + out_frame->nb_samples);  av_audio_fifo_write(out_stream_info->m_audiofifo,(void **)out_frame->data,samples_out_per_size);  fifo_size = av_audio_fifo_size(out_stream_info->m_audiofifo); out_frame->pkt_pts = in_frame->pkt_pts;  out_frame->pkt_dts = in_frame->pkt_dts;  //有时pkt_pts和pkt_dts不同,并且pkt_pts是编码前的dts,这里要给avframe传入pkt_dts而不能用pkt_pts  //out_frame->pts = out_frame->pkt_pts;  out_frame->pts = in_frame->pkt_dts;  //测试用if (out_stream_info->user_stream_id ==11){if (pcm_file == NULL){pcm_file = fopen("11.pcm","wb");}int wtiresize = fwrite(out_frame->data[0],buffersize_out,1, pcm_file);fflush(pcm_file);}}  ret = 1;return ret;}void ffmpeg_uinit_pcm_resample(SwrContext * swr_ctx,AVAudioFifo * audiofifo){ if (swr_ctx)  {  swr_free(&swr_ctx);  swr_ctx = NULL;  }  if(audiofifo)  {  av_audio_fifo_free(audiofifo);  audiofifo = NULL;  }     }void ffmpeg_write_frame(Out_stream_info * out_stream_info,int ID,AVPacket pkt_t){int64_t pts = 0, dts = 0;  int ret = -1;  if(ID == OUT_VIDEO_ID)  {  AVPacket videopacket_t;  av_init_packet(&videopacket_t);  videopacket_t.pts = av_rescale_q_rnd(pkt_t.pts, m_icodec->streams[m_in_video_stream_idx]->time_base, out_stream_info->m_ovideo_st->time_base, AV_ROUND_NEAR_INF);  videopacket_t.dts = av_rescale_q_rnd(pkt_t.dts, m_icodec->streams[m_in_video_stream_idx]->time_base, out_stream_info->m_ovideo_st->time_base, AV_ROUND_NEAR_INF);  videopacket_t.duration = av_rescale_q(pkt_t.duration,m_icodec->streams[m_in_video_stream_idx]->time_base, out_stream_info->m_ovideo_st->time_base);  videopacket_t.flags = pkt_t.flags;  videopacket_t.stream_index = OUT_VIDEO_ID; //这里add_out_stream顺序有影响  videopacket_t.data = pkt_t.data;  videopacket_t.size = pkt_t.size;  videopacket_t.pos = -1;ret = av_interleaved_write_frame(out_stream_info->m_ocodec, &videopacket_t);  if (ret != 0)  {  printf("error av_interleaved_write_frame _ video\n");  }  printf("video\n");  }  else if(ID == OUT_AUDIO_ID)  {  AVPacket audiopacket_t;  av_init_packet(&audiopacket_t);  audiopacket_t.pts = av_rescale_q_rnd(pkt_t.pts, m_icodec->streams[m_in_audio_stream_idx]->time_base, out_stream_info->m_oaudio_st->time_base, AV_ROUND_NEAR_INF);  audiopacket_t.dts = av_rescale_q_rnd(pkt_t.dts, m_icodec->streams[m_in_audio_stream_idx]->time_base, out_stream_info->m_oaudio_st->time_base, AV_ROUND_NEAR_INF);  audiopacket_t.duration = av_rescale_q(pkt_t.duration,m_icodec->streams[m_in_audio_stream_idx]->time_base, out_stream_info->m_oaudio_st->time_base); audiopacket_t.flags = pkt_t.flags;  audiopacket_t.stream_index = OUT_AUDIO_ID; //这里add_out_stream顺序有影响  audiopacket_t.data = pkt_t.data;  audiopacket_t.size = pkt_t.size; audiopacket_t.pos = -1;//添加过滤器  if(! strcmp(out_stream_info->m_ocodec->oformat-> name,  "mp4" ) ||  !strcmp (out_stream_info->m_ocodec ->oformat ->name , "mov" ) ||  !strcmp (out_stream_info->m_ocodec ->oformat ->name , "3gp" ) ||  !strcmp (out_stream_info->m_ocodec ->oformat ->name , "flv" ))  {  if (out_stream_info->m_oaudio_st->codec->codec_id == AV_CODEC_ID_AAC)  {  if (out_stream_info->m_vbsf_aac_adtstoasc != NULL)  {  AVPacket filteredPacket = audiopacket_t;   int a = av_bitstream_filter_filter(out_stream_info->m_vbsf_aac_adtstoasc,                                             out_stream_info->m_oaudio_st->codec, NULL,&filteredPacket.data, &filteredPacket.size,  audiopacket_t.data, audiopacket_t.size, audiopacket_t.flags & AV_PKT_FLAG_KEY);   if (a >  0)               {                  av_free_packet(&audiopacket_t);   filteredPacket.destruct = av_destruct_packet;    audiopacket_t = filteredPacket;               }     else if (a == 0)  {  audiopacket_t = filteredPacket;     }  else if (a < 0)              {                  fprintf(stderr, "%s failed for stream %d, codec %s",  out_stream_info->m_vbsf_aac_adtstoasc->filter->name,audiopacket_t.stream_index,out_stream_info->m_oaudio_st->codec->codec ?  out_stream_info->m_oaudio_st->codec->codec->name : "copy");  av_free_packet(&audiopacket_t);     }  }  }  }  ret = av_interleaved_write_frame(out_stream_info->m_ocodec, &audiopacket_t);  if (ret != 0)  {  printf("error av_interleaved_write_frame _ audio\n");  }  printf("audio\n");  } }void ffmpeg_write_frame2(Out_stream_info * out_stream_info,int ID,AVPacket pkt_t){int64_t pts = 0, dts = 0;  int ret = -1;  if(ID == OUT_VIDEO_ID)  {  AVPacket videopacket_t;  av_init_packet(&videopacket_t);  videopacket_t.pts = av_rescale_q_rnd(pkt_t.pts, out_stream_info->m_ovideo_st->codec->time_base, out_stream_info->m_ovideo_st->time_base, AV_ROUND_NEAR_INF);  videopacket_t.dts = av_rescale_q_rnd(pkt_t.dts, out_stream_info->m_ovideo_st->codec->time_base, out_stream_info->m_ovideo_st->time_base, AV_ROUND_NEAR_INF);  videopacket_t.duration = av_rescale_q(pkt_t.duration,out_stream_info->m_ovideo_st->codec->time_base, out_stream_info->m_ovideo_st->time_base);  videopacket_t.flags = pkt_t.flags;  videopacket_t.stream_index = OUT_VIDEO_ID; //这里add_out_stream顺序有影响  videopacket_t.data = pkt_t.data;  videopacket_t.size = pkt_t.size;  ret = av_interleaved_write_frame(out_stream_info->m_ocodec, &videopacket_t);  if (ret != 0)  {  printf("error av_interleaved_write_frame _ video\n");  }  printf("video\n"); }  else if(ID == OUT_AUDIO_ID)  {  AVPacket audiopacket_t;  av_init_packet(&audiopacket_t);  audiopacket_t.pts = av_rescale_q_rnd(pkt_t.pts, out_stream_info->m_oaudio_st->codec->time_base, out_stream_info->m_oaudio_st->time_base, AV_ROUND_NEAR_INF);  audiopacket_t.dts = av_rescale_q_rnd(pkt_t.dts, out_stream_info->m_oaudio_st->codec->time_base, out_stream_info->m_oaudio_st->time_base, AV_ROUND_NEAR_INF);  audiopacket_t.duration = av_rescale_q(pkt_t.duration,out_stream_info->m_oaudio_st->codec->time_base, out_stream_info->m_oaudio_st->time_base); audiopacket_t.flags = pkt_t.flags;  audiopacket_t.stream_index = OUT_AUDIO_ID; //这里add_out_stream顺序有影响  audiopacket_t.data = pkt_t.data;  audiopacket_t.size = pkt_t.size;  //添加过滤器  if(! strcmp(out_stream_info->m_ocodec->oformat-> name,  "mp4" ) ||  !strcmp (out_stream_info->m_ocodec ->oformat ->name , "mov" ) ||  !strcmp (out_stream_info->m_ocodec ->oformat ->name , "3gp" ) ||  !strcmp (out_stream_info->m_ocodec ->oformat ->name , "flv" ))  {  if (out_stream_info->m_oaudio_st->codec->codec_id == AV_CODEC_ID_AAC)  {  if (out_stream_info->m_vbsf_aac_adtstoasc != NULL)  {  AVPacket filteredPacket = audiopacket_t;   int a = av_bitstream_filter_filter(out_stream_info->m_vbsf_aac_adtstoasc,                                             out_stream_info->m_oaudio_st->codec, NULL,&filteredPacket.data, &filteredPacket.size,  audiopacket_t.data, audiopacket_t.size, audiopacket_t.flags & AV_PKT_FLAG_KEY);   if (a >  0)               {                  av_free_packet(&audiopacket_t);   filteredPacket.destruct = av_destruct_packet;    audiopacket_t = filteredPacket;               }     else if (a == 0)  {  audiopacket_t = filteredPacket;     }  else if (a < 0)              {                  fprintf(stderr, "%s failed for stream %d, codec %s",  out_stream_info->m_vbsf_aac_adtstoasc->filter->name,audiopacket_t.stream_index,out_stream_info->m_oaudio_st->codec->codec ?  out_stream_info->m_oaudio_st->codec->codec->name : "copy");  av_free_packet(&audiopacket_t);     }  }  }  }  ret = av_interleaved_write_frame(out_stream_info->m_ocodec, &audiopacket_t);  if (ret != 0)  {  printf("error av_interleaved_write_frame _ audio\n");  }  printf("audio\n");  } }int ffmpeg_transcode(int original_user_stream_id){int ret = 0;  int is_audio_decodefinish = 0;           //音频解码成功int is_video_decodefinish = 0;           //视频解码成功AVFrame * m_pin_temp_video_frame = avcodec_alloc_frame();AVFrame * m_pin_temp_audio_frame = avcodec_alloc_frame();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_pout_audio_frame = avcodec_alloc_frame();out_stream_info_all->m_pout_video_frame = avcodec_alloc_frame();out_stream_info_all->m_pout_video_frame->pts = 0;out_stream_info_all->m_pout_audio_frame->pts = 0;out_stream_info_all->m_pout_video_frame->width = out_stream_info_all->m_dwWidth;out_stream_info_all->m_pout_video_frame->height = out_stream_info_all->m_dwHeight;out_stream_info_all->m_pout_video_frame->format = out_stream_info_all->m_video_pixelfromat;int Out_size = avpicture_get_size((AVPixelFormat)out_stream_info_all->m_video_pixelfromat, out_stream_info_all->m_dwWidth,out_stream_info_all->m_dwHeight);  uint8_t * pOutput_buf =( uint8_t *)malloc(Out_size * 3 * sizeof(char)); //最大分配的空间,能满足yuv的各种格式  avpicture_fill((AVPicture *)out_stream_info_all->m_pout_video_frame, (unsigned char *)pOutput_buf, (AVPixelFormat)out_stream_info_all->m_video_pixelfromat, out_stream_info_all->m_dwWidth,out_stream_info_all->m_dwHeight); //内存关联  avcodec_get_frame_defaults(out_stream_info_all->m_pout_audio_frame);  }result_all ++;}} //开始解包  while (1)  {  av_init_packet(&m_in_pkt);  if (av_read_frame(m_icodec, &m_in_pkt) < 0)  {  break;  }  //视频  if(m_in_pkt.stream_index == m_in_video_stream_idx)   {  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){  //原始流只需要copy的if(out_stream_info_all->user_stream_id == original_user_stream_id){//如果纯copy支持拷贝的格式if (out_stream_info_all->m_writeheader_seccess ==1){ffmpeg_write_frame(out_stream_info_all,OUT_VIDEO_ID,m_in_pkt); }//在这里解码是因为输出的多路流中拷贝的只有一路,即在这里只解码一次,//其他需要重新编解码的用这个解码的m_pin_temp_video_frame的数据拷贝过去即可,在这里解码避免重复解码ret = ffmpeg_perform_decode(OUT_VIDEO_ID,m_pin_temp_video_frame); if (ret == 0)  {is_video_decodefinish = 1;}}else if(out_stream_info_all->m_writeheader_seccess ==1){ if (is_video_decodefinish == 1)  {  ffmpeg_perform_yuv_conversion(out_stream_info_all,m_pin_temp_video_frame,out_stream_info_all->m_pout_video_frame);  ret = ffmpeg_perform_code2(out_stream_info_all,OUT_VIDEO_ID,out_stream_info_all->m_pout_video_frame);}  }else{}}result_all ++;}is_video_decodefinish = 0;}}  //音频  else if (m_in_pkt.stream_index == m_in_audio_stream_idx)  {  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){   //原始流只需要copy的if(out_stream_info_all->user_stream_id == original_user_stream_id){//如果纯copy支持拷贝的格式if (out_stream_info_all->m_writeheader_seccess ==1){ffmpeg_write_frame(out_stream_info_all,OUT_AUDIO_ID,m_in_pkt);  }//在这里解码是因为输出的多路流中拷贝的只有一路,即在这里只解码一次,//其他需要重新编解码的用这个解码的m_pin_temp_audio_frame的数据拷贝过去即可,在这里解码避免重复解码ret = ffmpeg_perform_decode(OUT_AUDIO_ID,m_pin_temp_audio_frame); if (ret == 0)  {is_audio_decodefinish = 1;}}else if(out_stream_info_all->m_writeheader_seccess ==1){if (is_audio_decodefinish == 1)  {  if (out_stream_info_all->m_swr_ctx == NULL)  {  out_stream_info_all->m_swr_ctx = ffmpeg_init_pcm_resample(out_stream_info_all,m_pin_temp_audio_frame,out_stream_info_all->m_pout_audio_frame);  }  ffmpeg_preform_pcm_resample(out_stream_info_all,out_stream_info_all->m_swr_ctx,m_pin_temp_audio_frame,out_stream_info_all->m_pout_audio_frame);    ffmpeg_perform_code2(out_stream_info_all,OUT_AUDIO_ID,out_stream_info_all->m_pout_audio_frame); } }else{}}result_all ++;}is_audio_decodefinish = 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){    if (out_stream_info_all->m_pout_audio_frame){avcodec_free_frame(&out_stream_info_all->m_pout_audio_frame);out_stream_info_all->m_pout_audio_frame = NULL;}if (out_stream_info_all->m_pout_video_frame){avcodec_free_frame(&out_stream_info_all->m_pout_video_frame);out_stream_info_all->m_pout_video_frame = NULL;}ffmpeg_uinit_pcm_resample(out_stream_info_all->m_swr_ctx,out_stream_info_all->m_audiofifo);}result_all ++;}}if (m_pin_temp_video_frame){avcodec_free_frame(&m_pin_temp_video_frame);m_pin_temp_video_frame = NULL;}if (m_pin_temp_audio_frame){avcodec_free_frame(&m_pin_temp_audio_frame);m_pin_temp_audio_frame = NULL;}ret = 1;return ret;}

如有错误请指正:

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