mp3编码--PCM转MP3,PCM编码为MP3,如何实现多路同时MP3编码-VC,MFC实现---QQ35744025

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xjb2006/article/details/78404523

看你又猴急了

别急,先来张图片暖暖身

看惯了美女图片

这次来张萌娃



前面一篇文章,实现了mp3解码,经测试也具备多路同时解码的能力。

在这之前,本人一直用的是BladeMP3EncDLL的动态库进行编码,其实也没什么问题,就是不能进行多线程编码。。。

__declspec(dllexport) BE_ERRbeInitStream(PBE_CONFIG pbeConfig, PDWORD dwSamples, PDWORD dwBufferSize, PHBE_STREAM phbeStream);
__declspec(dllexport) BE_ERR beEncodeChunk(HBE_STREAM hbeStream, DWORD nSamples, PSHORT pSamples, PBYTE pOutput, PDWORD pdwOutput);
// added for floating point audio  -- DSPguru, jd
__declspec(dllexport) BE_ERR beEncodeChunkFloatS16NI(HBE_STREAM hbeStream, DWORD nSamples, PFLOAT buffer_l, PFLOAT buffer_r, PBYTE pOutput, PDWORD pdwOutput);
__declspec(dllexport) BE_ERR beDeinitStream(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput);
__declspec(dllexport) BE_ERR beCloseStream(HBE_STREAM hbeStream);
__declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion);
__declspec(dllexport) BE_ERR beWriteVBRHeader(LPCSTR lpszFileName);
__declspec(dllexport) BE_ERR beFlushNoGap(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput);
__declspec(dllexport) BE_ERR beWriteInfoTag( HBE_STREAM hbeStream, LPCSTR lpszFileName );

其实多线程变通一下也行,就是比较麻烦,复制多份DLL,LOAD一个dll就是一个编码。。。如果255个,就要复制255份,这也太坑爹了吧!!!身为处女的我,哦,口误,是处女座的我是不能容忍的。好吧,自己动手写吧,网上找了下,还真不少,但没一个靠谱的。好不容易封装好了一个基于LAME的编码器,由于前一位作者添加了太多全局或者静态的东西,也只能支持单个编码,要改成多个同时编码估计头都大了。。。

又只好尝试其他方法,那用ipp吧,ipp是intel公司提供的高效媒体库,针对音视频,图片等进行处理,相当强大。

不想打字了,贴点代码吧:

/*//////////////////////////////////////////////////////////////////////////////
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2002-2008 Intel Corporation. All Rights Reserved.
//
*/


#include "umc_defs.h"
#if defined (UMC_ENABLE_MP3_AUDIO_ENCODER)


#ifndef __UMC_MP3_ENCODER_H__
#define __UMC_MP3_ENCODER_H__


#include "umc_media_data.h"
#include "umc_audio_codec.h"
#include "audio_codec_params.h"
#include "mp3_status.h"


struct _MP3Enc;


namespace UMC {




/* /////////////////////////////////////////////////////////////////////////////
//  Class:       MP3Encoder
//
//  Notes:       Implementation of MPEG-I layer 3 encoder.
//
*/
class   MP3Encoder:public AudioCodec 
{


public:


virtual Status  Init(BaseCodecParams * init);
virtual Status  Close();


virtual Status  GetFrame(MediaData * in, MediaData * out);
virtual Status  GetFrame(char * in,int nInLen, char * out,int &nOutLen);


virtual Status  GetInfo(BaseCodecParams * init);
virtual Status  GetDuration(Ipp32f *p_duration);


MP3Encoder(void);
virtual ~MP3Encoder();


virtual Status  SetParams(BaseCodecParams * params);
virtual Status  Reset();


virtual IppBool CheckBitRate(Ipp32s sample_rate,
Ipp32s layer,
Ipp32s bitrate,
Ipp32s stereo);


protected:
struct _MP3Enc  *state;
Ipp32s  m_stereo;
Ipp32s  m_freq;
Ipp32s  m_layer;
Ipp32s  m_bitrate;
Ipp32s  m_br_mode;
Ipp32s  m_stereo_mode;
Ipp32s  m_ns_mode;
Ipp32s  m_id;
Ipp32s  m_frame_size;
Ipp32s  m_upsample;
Ipp32s  m_force_mpeg1;
Ipp32s  m_mc_matrix_procedure;
Ipp32s  m_mc_lfe_filter_off;
Ipp64f  m_pts_prev;
MemID  stateMemId;
Ipp32s m_initialized;


Status StatusMP3_2_UMC(MP3Status st);
Status MemLock();
Status MemUnlock();
};


};      // namespace UMC


#endif /* __UMC_MP3_ENCODER_H__ */


#endif //UMC_ENABLE_MP3_AUDIO_ENCODER

我已经封装成了OCX,过程很艰辛,但是最后还是成功了。来一个yin 荡的傻笑大笑。。。

#pragma once
#include "Mp3Enc.h"


// Mp3encoderCtrl.h : CMp3encoderCtrl ActiveX 控件类的声明。




// CMp3encoderCtrl : 有关实现的信息,请参阅 Mp3encoderCtrl.cpp。


class CMp3encoderCtrl : public COleControl
{
DECLARE_DYNCREATE(CMp3encoderCtrl)


// 构造函数
public:
CMp3encoderCtrl();


// 重写
public:
virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
virtual void DoPropExchange(CPropExchange* pPX);
virtual void OnResetState();


// 实现
protected:
~CMp3encoderCtrl();


DECLARE_OLECREATE_EX(CMp3encoderCtrl)    // 类工厂和 guid
DECLARE_OLETYPELIB(CMp3encoderCtrl)      // GetTypeInfo
DECLARE_PROPPAGEIDS(CMp3encoderCtrl)     // 属性页 ID
DECLARE_OLECTLTYPE(CMp3encoderCtrl)// 类型名称和杂项状态


// 消息映射
DECLARE_MESSAGE_MAP()


// 调度映射
DECLARE_DISPATCH_MAP()


afx_msg void AboutBox();


// 事件映射
DECLARE_EVENT_MAP()


// 调度和事件 ID
public:
enum {
dispidFreeAll = 5L,
dispidClose = 4L,
dispidEncode = 3L,
dispidInit = 2L,
dispidInitCount = 1L
};


#define MP3COUNT 300
protected:
int m_nCount;
CMp3Enc *m_mp3[MP3COUNT];
void InitCount(LONG nCount);
void Init(LONG nIndex, LONG sample_frequency, LONG channel, LONG bitrate);
LONG Encode(LONG nIndex, BYTE* pInPCM, LONG nPCMLen, BYTE* pOutMp3);
void Close(LONG nIndex);
void FreeAll(void);
};
最多支持300路,当然再多也可以,这个看你自己需要啊,但是太多,多半CPU吃不消吧。。。

最后,贴下编码封装代码

#include "stdafx.h"
#include "Mp3Enc.h"


CMp3Enc::CMp3Enc(void)
{
m_pAudioEncoder=0;
m_pcmen=0;
m_mp3len=0;
int nSize=sizeof(MP3EncoderParams);
}


CMp3Enc::~CMp3Enc(void)
{
Close();
}


void CMp3Enc::Close()
{
if(m_pAudioEncoder)
{
delete m_pAudioEncoder;
m_pAudioEncoder=0;
}
m_pcmen=0;
m_mp3len=0;
}


void CMp3Enc::Init(int sample_frequency,int channel,int bitrate)
{
m_pcmen=0;
m_mp3len=0;
mp3enc_params.m_info_out.bitrate=bitrate;
AudioEncoderParams* par = (AudioEncoderParams*)(&mp3enc_params);

par->m_info.channel_mask = 0;
par->m_info.bitPerSample=16;
par->m_info.channels=channel;
par->m_info.sample_frequency=sample_frequency;
par->m_info.bitrate=bitrate;
par->m_info.stream_type=PCM_AUDIO;
m_pAudioEncoder=new MP3Encoder();
m_pAudioEncoder->Init(par);
}


BYTE* CMp3Enc::EncodeMp3(BYTE * in,int nInLen,int &nOutLen)
{
if(m_pcmen+nInLen<=sizeof(PCMBuf))
{
memcpy(PCMBuf+m_pcmen,in,nInLen);
m_pcmen+=nInLen;
}
AudioEncoderParams* par = (AudioEncoderParams*)(&mp3enc_params);
int nApplyPcmLen=2304*par->m_info.channels*par->m_info.sample_frequency/44100;
if(m_pcmen<nApplyPcmLen)//不够
{
nOutLen=0;
return Mp3Buf;
}
int nRead=0;
int nMp3Len=0;
BYTE BufMp3[1024*8];
for(;;)
{
BYTE *p=PCMBuf+nRead;
int nOut=4096;
BYTE *pOut=EncodeMp3_(p,nApplyPcmLen,nOut);
if(nOut>0)
{
memcpy(BufMp3+nMp3Len,pOut,nOut);
nMp3Len+=nOut;
}
nRead+=nApplyPcmLen;
m_pcmen-=nApplyPcmLen;
if(m_pcmen<nApplyPcmLen)
break;

}
if(m_pcmen>0)
memmove(PCMBuf,PCMBuf+nRead,m_pcmen);


nOutLen=nMp3Len;
return BufMp3;

}


BYTE* CMp3Enc::EncodeMp3_(BYTE * in,int nInLen,int &nOutLen)
{
char Buf[1024*4];
int nOut=sizeof(Buf);
try
{
Status s=m_pAudioEncoder->GetFrame((char*)in,nInLen,Buf,nOut);//只能输入2304*2=4608
if(s!=0)
{
nOutLen=0;
return Mp3Buf;
}
}
catch(...)
{
nOutLen=0;
return Mp3Buf;
}


memcpy(Mp3Buf+m_mp3len,Buf,nOut);
m_mp3len+=nOut;
MPADecodeContext ms;
if(m_mp3len)
{
int nReadLen=0;
nOutLen=0;
for(;;)
{
if(nReadLen>m_mp3len)
break;
int nCheck=check_header(*(uint32_t*)(Mp3Buf+nReadLen));
if(nCheck==-1)
break;
int nMp3FrameLen=decode_header(&ms,*(uint32_t*)(Mp3Buf+nReadLen));
if(m_mp3len>=nMp3FrameLen&&nMp3FrameLen>0&&nCheck==0)
{
memcpy(Buf+nReadLen,Mp3Buf+nReadLen,nMp3FrameLen);
nReadLen+=nMp3FrameLen;
m_mp3len-=nMp3FrameLen;
}
else
break;
}
nOutLen=nReadLen;
if(m_mp3len>0)
memmove(Mp3Buf,Mp3Buf+nReadLen,m_mp3len);
}


return (BYTE*)Buf;
}
编码看上去怎么这么复杂,先不害怕,理解好了其实一点也不复杂:

因为为了配合之前做的mp3解码库,解码需要输入完整的一帧或者多帧,我们也就需要这种编码器。编码后是完整的一帧或者多帧。

Status s=m_pAudioEncoder->GetFrame((char*)in,nInLen,Buf,nOut);//这句是核心编码语句,必须输入特定的PCM长度,才能编码成功!(你问我为什么知道,调试啊,经验啊),而这个大小就是下面这个公式计算出来的。

int nApplyPcmLen=2304*par->m_info.channels*par->m_info.sample_frequency/44100;

如输出44100,双声道的mp3,输入大小就是2304*2=4608Byte(下面都是这个参数来表述的哦)

但是不能保证每次输入的都是4608啊,所以,我们开一个全局变量保存PCM数据,没有就等,有4608就编码并输出。OK,输入解决了。再来解决输出吧

,输出我们要保证完整的一帧或者多帧,怎样保证呢,查了下mp3数据结构,(并没有很深入,我喜欢点到为止,并不是什么都要知道,需要什么了解什么,快速解决问题创造效益才是硬道理!),mp3一帧的前4个byte保存了这一帧的声道,采样率,帧大小等信息,所以我们根据这个,可以判断一帧后面的大小,如果编码出来一帧不够417,那么就等下一次编码,下一次累加到上一次的buf。如果编码出来超过417,那就输出完整的一帧或者多帧。看我上面的代码你就明白了。看下输出结果:

MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;16,长度:417
MP3编码时间;16,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;16,长度:417
MP3编码时间;16,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417
MP3编码时间;0,长度:417

标准的417,看上去好美,这一刻,感觉回到了初恋。。。害羞害羞害羞害羞害羞害羞


什么时候找个时间上传代码上去,最后打个广告:

需要合作的联系QQ35744025,本人03年从事工作,“精通”音视频应用编程技术(勉强加个精通,吸引眼球,哈哈),精通VC,MFC,多媒体教学软件,录播软件,直播软件的核心技术大部分已掌握,如ffmpeg技术,MP4,FLV编码合成,H264,AAC,MP3,可以运用IPP进行高效图像空间转换等,可以运用INTEL和cuda进行硬件H264编解码,可以实现240帧1080P实时编码,完全同步及平滑度极高,rtmp直播推送,rtmp服务器,YV12,YUV422,NV12,RGB24,RGB32熟悉转换,缩放,wav,AAC, mp3的编码解码,视频切换特效算法,视频水印,LOGO,文字。屏幕截取录像,摄像头捕获录像,D3D高效视频图像显示,OPENCV,图像库ximage,GDI,GDIPLUS熟练应用,语音识别及文字转换,人脸识别及匹配,局域网内远程控制,音视频实时通话,声卡捕获回放等,另外SQL数据库,ACCESS,EXCEL数据库,DOC,PDF文件打开提取,FTPServer,Client,以上所有代码均已商用。

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,一直没有仔细统计过,原来我也学会了这么多东西了啊,真佩服自己啊




猜你喜欢

转载自blog.csdn.net/xjb2006/article/details/78404523
mp3
今日推荐