版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuweigangzwg/article/details/72481966
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 = 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;
}
如有错误请指正: