1.有push.cpp和push.h
push.cpp:
#include “Pusher.h”
#include <iostream>
#include “Common/config.h”
#include “appPublic.h”
#include “FifoMsg.h”

using namespace std;
using namespace mediakit;
using namespace toolkit;

enum AVCodeConst {
AV_CODER_NONE = 0,
AV_VIDEO_CODER_H264 = 1,
AV_VIDEO_CODER_HEVC = 2,
AV_AUDIO_CODER_AAC = 3
};

enum EnumFrameType {
FRAME_TYPE_VIDEO = 0,
FRAME_TYPE_AUDIO = 1,
};


#define PUSH_FIELD “push.”
const string kEnableAAC2G711A = PUSH_FIELD"EnableAAC2G711A";

#define MAX_WRITE_FAILED_TIME (10)

Pusher::Pusher(const SdpInfo &p_SdpInfo)
:m_bIsInitOK(false)
,m_SdpInfo(p_SdpInfo)
,m_audioIdx(0)
,m_videoIdx(0)
,m_ofmt_ctx(NULL)
,aac_swr_ctx(NULL)
,pAcodecContext(NULL)
,alaw_codecContext(NULL)
,m_writeFailedTime(0){

int nInitFlag = init();
if (nInitFlag == 0){
m_bIsInitOK = true;
InfoL<<“create pusher success,dev:”<<m_SdpInfo.szPlayUrl;
}
else{
nInitFlag = false;
InfoL<<“create pusher failed,dev:”<<m_SdpInfo.szPlayUrl;
release();
return;
}
}

Pusher::~Pusher(){
release();
InfoL<<m_SdpInfo.szPlayUrl<<" pusher is released";
}

void Pusher::release(){
if(m_ofmt_ctx == NULL)
return;

av_write_trailer(m_ofmt_ctx);
if (!(m_ofmt_ctx->flags & AVFMT_NOFILE)) {
avio_close(m_ofmt_ctx->pb);
}

avformat_free_context(m_ofmt_ctx);
m_ofmt_ctx = NULL;

if(pAcodecContext){
avcodec_free_context(&pAcodecContext);
pAcodecContext = NULL;
}

if (alaw_codecContext){
avcodec_free_context(&alaw_codecContext);
alaw_codecContext = NULL;
}
}


void Pusher::ffLogCallback(void *ptr, int level, const char *fmt, va_list vl)
{
if (level > av_log_get_level())
return;

char temp[1024];
vsprintf(temp, fmt, vl);
size_t len = strlen(temp);
if (len > 0 && len < 1024&&temp[len - 1] == ‘\n’)
{
temp[len - 1] = ‘\0’;
}
DebugL << (char )temp;
}


/ select layout with the highest channel count */
uint64_t Pusher::select_channel_layout(const AVCodec *codec)
{
if (!codec)
return AV_CH_LAYOUT_STEREO;

const uint64_t *p;
uint64_t best_ch_layout = 0;
int best_nb_channels = 0;

if (!codec->channel_layouts)
return AV_CH_LAYOUT_STEREO;

p = codec->channel_layouts;
while (*p) {
int nb_channels = av_get_channel_layout_nb_channels(*p);

if (nb_channels > best_nb_channels) {
best_ch_layout = *p;
best_nb_channels = nb_channels;
}
p++;
}
return best_ch_layout;
}


int Pusher::select_sample_rate(const AVCodec *codec)
{
if (!codec)
return 44100;

const int *p;
int best_samplerate = 0;

if (!codec->supported_samplerates)
return 44100;

p = codec->supported_samplerates;
while (*p) {
if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
best_samplerate = *p;
p++;
}
return best_samplerate;
}

bool Pusher::init(){
if (strlen(m_SdpInfo.szPlayUrl) <= 0){
ErrorL<<“输出URL不能为空”;
return false;
}

av_register_all();
avformat_network_init();
av_log_set_level(AV_LOG_INFO);
av_log_set_callback(ffLogCallback);

AVDictionary *pDict = NULL;
int ret = avformat_alloc_output_context2(&m_ofmt_ctx, NULL, m_SdpInfo.szFmt, m_SdpInfo.szPlayUrl);
if (ret < 0){
ErrorL<<“avformat_alloc_output_context2 failed, output:”<<m_SdpInfo.szFmt;
return -1;
}

AVCodec *pEnCodeV = NULL;
if (m_SdpInfo.nVideoCodec == AV_VIDEO_CODER_H264)
pEnCodeV = avcodec_find_encoder(AV_CODEC_ID_H264);
else
pEnCodeV = avcodec_find_encoder(AV_CODEC_ID_H265);

if(pEnCodeV)
InfoL<<“The video codec is:”<<pEnCodeV->name;

//设置视频输出格式
AVStream *pStreamO = avformat_new_stream(m_ofmt_ctx, pEnCodeV);
pStreamO->id = m_ofmt_ctx->nb_streams - 1;
pStreamO->codec->codec_tag = 0;
pStreamO->codec->width = 1280;
pStreamO->codec->height = 1080;
pStreamO->codec->pix_fmt = AV_PIX_FMT_YUV420P;
AVRational tb{ 1, 90000 };
pStreamO->time_base = tb;
AVRational fr{ 25, 1 };
pStreamO->r_frame_rate = fr; //(tbr)
pStreamO->avg_frame_rate = fr; //(fps)
AVRational sar{ 1, 1 };
pStreamO->sample_aspect_ratio = sar;
AVRational ctb{ 1, 25 };
pStreamO->codec->time_base = ctb;
pStreamO->codec->sample_aspect_ratio = sar;
pStreamO->codec->gop_size = 12;

if (m_ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
pStreamO->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}

if (avcodec_open2(pStreamO->codec, pEnCodeV, NULL) != 0) {
ErrorL << “avcodec_open2 video error”;
}

AVStream *pAStreamO = NULL;
bool bEnableAAC2G711AFlag = mINI::Instance()[kEnableAAC2G711A];
if (bEnableAAC2G711AFlag){
//设置音频输出格式
AVCodec *pEnCodeA = avcodec_find_encoder(::AV_CODEC_ID_PCM_ALAW);
pAStreamO = avformat_new_stream(m_ofmt_ctx, pEnCodeA);
pAStreamO->id = m_ofmt_ctx->nb_streams - 1;
pAStreamO->codec->codec_tag = 0;
pAStreamO->codec->sample_fmt = ::AV_SAMPLE_FMT_S16;
pAStreamO->codec->channel_layout = AV_CH_LAYOUT_MONO;
pAStreamO->codec->sample_rate = 8000;
pAStreamO->codec->channels = 1;
pAStreamO->codec->frame_size = 160/2;

if (avcodec_open2(pAStreamO->codec, pEnCodeA, NULL) != 0) {
ErrorL<<“avcodec_open2 audio error” ;
}
}else{
AVCodec *pEnCodeA = avcodec_find_encoder(::AV_CODEC_ID_AAC);
AVStream *pAStreamO = avformat_new_stream(m_ofmt_ctx, pEnCodeA);
pAStreamO->id = m_ofmt_ctx->nb_streams - 1;
pAStreamO->codec->codec_tag = 0;
pAStreamO->codec->sample_fmt = ::AV_SAMPLE_FMT_FLTP;
pAStreamO->codec->channel_layout = select_channel_layout(pAStreamO->codec->codec);
pAStreamO->codec->sample_rate = select_sample_rate(pAStreamO->codec->codec);
pAStreamO->codec->channels = ::av_get_channel_layout_nb_channels(pAStreamO->codec->channel_layout);

if (avcodec_open2(pAStreamO->codec, pEnCodeA, NULL) != 0) {
ErrorL<<“avcodec_open2 audio error” ;
}
}

if (!(m_ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&m_ofmt_ctx->pb, m_SdpInfo.szPlayUrl, AVIO_FLAG_WRITE);
}

if (0 == strcasecmp(m_SdpInfo.szFmt, “rtsp”)){
av_dict_set(&pDict, “rtsp_transport”, “tcp”, 0);
av_dict_set(&pDict, “muxdelay”, “0.1”, 0);
}

ret = avformat_write_header(m_ofmt_ctx, &pDict);
av_dump_format(m_ofmt_ctx, 0, m_SdpInfo.szPlayUrl, 1);

if (!bEnableAAC2G711AFlag){
InfoL<<“新建国标流推流器,设备:”<<m_SdpInfo.szPlayUrl;
return ret;
}

InfoL<<“使能AAC转G711A,初始化AAC解码器和G711A编码器”;

//以下为aac->alaw相关
//aac音频格式
int64_t in_channel_layout = AV_CH_LAYOUT_STEREO;
enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_FLTP;
int in_sample_rate = 44100;
int in_channels = 2;
AVRational in_timeBase = {1,44100};

//alaw音频格式
uint64_t out_channel_layout = AV_CH_LAYOUT_MONO;
enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
int out_sample_rate = 8000;
int out_nb_samples = 160;
int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);

//aac->alaw重采样器
aac_swr_ctx = swr_alloc();
aac_swr_ctx = swr_alloc_set_opts(aac_swr_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,in_channel_layout, in_sample_fmt, in_sample_rate, 0, NULL);
swr_init(aac_swr_ctx);

//初始化AAC解码器
AVCodec pAcodec = avcodec_find_decoder(AV_CODEC_ID_AAC);
pAcodecContext = avcodec_alloc_context3(pAcodec);
pAcodecContext->sample_rate = in_sample_rate;
pAcodecContext->channels = in_channels;
pAcodecContext->sample_fmt = in_sample_fmt;
pAcodecContext->time_base = in_timeBase;
avcodec_open2(pAcodecContext, pAcodec, NULL);

//初始化alaw编码器
AVCodec alaw_codec = avcodec_find_encoder(AV_CODEC_ID_PCM_ALAW);
alaw_codecContext = avcodec_alloc_context3(alaw_codec);
alaw_codecContext->codec_type = AVMEDIA_TYPE_AUDIO;
alaw_codecContext->sample_rate = 8000;
alaw_codecContext->channels = 1;
alaw_codecContext->sample_fmt = out_sample_fmt; // ALAW编码需要16位采样,U8在目前ff版本不支持
alaw_codecContext->channel_layout = AV_CH_LAYOUT_MONO;
alaw_codecContext->height = pStreamO->codec->height;
alaw_codecContext->width = pStreamO->codec->width;
alaw_codecContext->codec_id = AV_CODEC_ID_PCM_ALAW;
alaw_codecContext->bit_rate = 64000;
//alaw_codecContext->frame_size = 160/2;
ret = avcodec_open2(alaw_codecContext, alaw_codec, NULL);
if (ret < 0)
ErrorL<<“avcodec_open2 alaw_codecContext failed”;
else
InfoL<<“avcodec_open2 alaw_codecContext ok”;

av_init_packet(&m_pkt);

return ret;
}

int Pusher::WriteFrame(const int p_nFrameType,const uint8_t p_frame_data, const int p_frame_len){
if (!m_bIsInitOK)
return -1;

int64_t currentTimeStamp = 0;
if (p_nFrameType == FRAME_TYPE_VIDEO) {
currentTimeStamp = m_videoIdx * 3600;

if(strlen(m_SdpInfo.szFileName) > 0 && (m_videoIdx % 25 == 0)){
int ndownloadProgress = (int)(m_videoIdx * 100 / m_SdpInfo.nHistoryTotalFrameNum);
if(ndownloadProgress >= 100){
ndownloadProgress = 100;
}
InfoL<<“download file:”<<m_SdpInfo.szFileName<<" download progress:"<<ndownloadProgress;
m_SdpInfo.nDownloadProgress = ndownloadProgress;
m_SdpInfo.nEventType = DevProcessType_upload_download_progress;
sendFifoMsg(m_SdpInfo);
}

m_videoIdx++;
}
if (p_nFrameType == FRAME_TYPE_AUDIO) {
currentTimeStamp= m_audioIdx * 1024;
m_audioIdx++;
}

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = (uint8_t)p_frame_data;
pkt.size = p_frame_len;
pkt.pts = currentTimeStamp;
pkt.dts = currentTimeStamp;
pkt.duration = 3600;
pkt.pos = -1;
pkt.stream_index = p_nFrameType;

int ret = -1;
if (p_nFrameType == FRAME_TYPE_VIDEO) {
//std::cout<<“=====lgo 1===”<<std::endl;
if (m_ofmt_ctx){
ret = av_write_frame(m_ofmt_ctx, &pkt);
//std::cout<<“=====lgo 2===ret:”<<ret<<std::endl;
if(ret < 0){
m_writeFailedTime++;
if (MAX_WRITE_FAILED_TIME < m_writeFailedTime || ret == -32){
m_SdpInfo.nEventType = DevProcessType_stop_stream;
sendFifoMsg(m_SdpInfo);
return -1;
}
}
m_writeFailedTime = 0;
}
av_packet_unref(&pkt);
return ret;
}

bool bEnableAAC2G711AFlag = mINI::Instance()[kEnableAAC2G711A];
if (!bEnableAAC2G711AFlag){
if (m_ofmt_ctx){
ret = av_write_frame(m_ofmt_ctx, &pkt);
}
av_packet_unref(&pkt);
return ret;
}

if (p_nFrameType == FRAME_TYPE_AUDIO) {
int got_frame;
AVFrame *pAACFrame=av_frame_alloc();
ret = avcodec_decode_audio4(pAcodecContext, pAACFrame, &got_frame, &pkt);
if(ret < 0){
ErrorL<<“avcodec_decode_audio4 failed”;
return -1;
}else if (got_frame){
//解码aac成功后,重采样得到alaw数据
uint64_t out_channel_layout = AV_CH_LAYOUT_MONO;
enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
int out_nb_samples = 160;
int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
int alaw_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);

//44.1KHZ,16bit,2声道的pcm转换成pcma 8khz,16bit,1声道
uint8_t *alaw_buffer = (uint8_t *)av_malloc(pAACFrame->nb_samples);
swr_convert(aac_swr_ctx, &alaw_buffer, alaw_buffer_size, (const uint8_t *)pAACFrame->data, pAACFrame->nb_samples);


//构造alawFrame
AVFrame * alawFrame = av_frame_alloc();
//设置AVFrame的基本信息
alawFrame->sample_rate = 8000;
alawFrame->channels = 1;
alawFrame->format = AV_SAMPLE_FMT_S16;
alawFrame->channel_layout = AV_CH_LAYOUT_MONO;
alawFrame->nb_samples = alaw_buffer_size/2;
av_frame_get_buffer(alawFrame, 0);
memcpy(alawFrame->data[0], alaw_buffer, alaw_buffer_size);

int got_packet = 0;
AVPacket packet = av_packet_alloc();
av_init_packet(packet);
packet->data = alaw_buffer;
packet->size = alaw_buffer_size;
packet->stream_index = 1;
ret = avcodec_encode_audio2(alaw_codecContext, packet, alawFrame, &got_packet);
av_frame_free(&alawFrame);

if (ret < 0){
ErrorL<<“avcodec_encode_audio2 failed”;
}else if (got_packet){
//成功编码出音频包后,写输出流
int nbSamplesPerPacket = 160;
int sampleRate = 8000;
packet->pts = (m_audioIdx-1) *160;
packet->dts = packet->pts;
packet->duration = 160;
packet->stream_index = 1;
packet->pos = 1;
ret = ::av_write_frame(m_ofmt_ctx, packet);
}
av_packet_free(&packet);
av_free(alaw_buffer);
}
av_frame_free(&pAACFrame);
}
av_packet_unref(&pkt);
return 0;
}



void Pusher::sendFifoMsg(const SdpInfo &p_objSdpInfo){
if (p_objSdpInfo.nSrcPort <= 0 || strlen(p_objSdpInfo.szDevid) <= 0)
return;

char szFifoName[128] = {0};
snprintf(szFifoName, sizeof(szFifoName), FORMAT_PORT_DISPATCH_THREAD_MSG_FIFO,p_objSdpInfo.nSrcPort);

std::string strJson;
SdpParse::makeFifoMsgJson(p_objSdpInfo, strJson);

DebugL<<“send msg, fifo:”<<szFifoName<<“, msg:”<<strJson;
FifoMsg::fifo_send_msg(szFifoName, strJson);
}



push.h
#ifndef PUSHER_H
#define PUSHER_H

#include <string>
#include <string.h>
#include “SdpParse.h”
extern “C” {
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/time.h>
#include <libswresample/swresample.h>
}


class Pusher {
public:
Pusher(const SdpInfo &p_SdpInfo);
~Pusher();
int WriteFrame(const int p_nFrameType,const uint8_t *p_frame_data, const int p_frame_len);
private:
bool init();
static void ffLogCallback(void *ptr, int level, const char *fmt, va_list vl);
uint64_t select_channel_layout(const AVCodec *codec);
int select_sample_rate(const AVCodec *codec);
void release();
void sendFifoMsg(const SdpInfo &p_objSdpInfo);
private:
AVFormatContext *m_ofmt_ctx;
struct SwrContext *aac_swr_ctx;
AVCodecContext pAcodecContext;
AVCodecContext alaw_codecContext;
int m_audioIdx;
int m_videoIdx;
AVPacket m_pkt;
int m_writeFailedTime;
private:
bool m_bIsInitOK;
SdpInfo m_SdpInfo;
};

#endif

1.请描述上面代码实现的功能
1.请用c11重写以上代码，要求不能有内存泄漏，要求成员变量名称统一m_xxx来命名，做到通俗易懂