设为首页 收藏本站
查看: 1818|回复: 0

【Advanced Windows Phone Programming】在windows phone 8中录制MP3和AAC及Amr音频

[复制链接]

尚未签到

发表于 2015-5-22 10:43:52 | 显示全部楼层 |阅读模式
  PS:博主开了微博了~详情猛戳:http://weibo.com/SandCu
  wp系统中默认的给出的是WAV格式的音频,当然无论是用来存储还是与网络交互都显得过大了,不过在p7中只能是用c#进行处理,所以通常会将其保存为Amr格式比如QQ又或者是使用Speex进行编码然后打包成OGG,
  鉴于Wp8中开放了Native Code,所以我们可以考虑性价比更高的格式如AAC或者MP3格式。
  1.使用AAC格式
  wp8在winPRT中新加入了AudioVideoCaptureDevice类,通过这个类我们可以录制音频或者视频,但是因为是在prt中而不是。net类库,所以在使用的时候可能会有些限制。
  首先我们来看看录音的使用方法。
  首先在构造函数中来初始化AudioVideoCaptureDevice类的一些设置,当然初始化的时机需要根据不同的应用场景来区分,这里暂时写在页面的构造函数里



  private AudioVideoCaptureDevice AVCaptureDevice;
  private IRandomAccessStream Iras;
 private string path;
public MainPage()
  {
    InitializeComponent();
   init();
  }
private async void init()
  {
      AVCaptureDevice= await AudioVideoCaptureDevice.OpenForAudioOnlyAsync();
      AVCaptureDevice.AudioEncodingFormat = CameraCaptureAudioFormat.Aac;  
  }   
CameraCaptureAudioFormat是一个枚举值,有Aac,Amr,None,Pcm四种格式,当然不可能有Mp3,毕竟是收费格式~
下面我们来看录音函数:
我们需要使用AudioVideoCaptureDevice的的IAsyncAction StartRecordingToStreamAsync(IRandomAccessStream stream)方法,毕竟是PRT的类,所以使用IRandomAccessStream来做参数也无可厚非,WP8中各种流之间的转换是一个比较让人反胃的东西,不过习惯了就好了,下面我们来看一下录音的Record函数:



private async void Record(string fileName="sandcu")
{
StorageFile storageFile=null;
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication();
if (isStore.FileExists(localFolder.Path + "\\"+fileName+".aac"))
{
storageFile = await localFolder.GetFileAsync(fileName+".aac");
}
storageFile = storageFile ?? await localFolder.CreateFileAsync(fileName+".aac", CreationCollisionOption.ReplaceExisting);
path = storageFile.Path;
if (storageFile != null)
{
Iras= await storageFile.OpenAsync(FileAccessMode.ReadWrite);
await AVCaptureDevice.StartRecordingToStreamAsync(Iras);
}
}

  由于StorageFile 的OpenAsync方法可以很方便的返回一个IRandomAccessStream流所以我们暂且在根目录下创建这样一个临时文件存储流,这样录音之后转存的Aac文件流会直接写入文件中。
  紧接着是停止录音的方法StopRecord。很简单~停止,然后释放流。



private async void StopRecord()
{
await AVCaptureDevice.StopRecordingAsync();
Iras.AsStream().Dispose();
}
  大功告成~
  为了测试我们是否成功的录音了,可以播放一下看看:



private void Play()
{
new MediaPlayerLauncher()
{
Media = new Uri(path, UriKind.Relative),
}.Show();
}
  如果程序结束后不需要AudioVideoCaptureDevice了 记得Dispose掉;
   2.使用AMR格式
  把init中的AVCaptureDevice.AudioEncodingFormat = CameraCaptureAudioFormat.Aac;  改为 AVCaptureDevice.AudioEncodingFormat = CameraCaptureAudioFormat.Amr;就好......
  3.使用MP3格式
  这个会比较麻烦,目前使用最广的MP3编码器当然是Lame~详见 http://lame.sourceforge.net/download.php,打不开的自觉FQ,不过在wp8上使用lame略微有点麻烦,而且比较容易出错。
  在wp8中使用native库有两种方式,一是使用dll二是使用lib,但是我们不能直接在c#中使用库,所以需要用C++/CX包一层,至于如何包这一层网上有很多方法,详情请google一下,在这里我们使用Lib的静态方式来调用Lame。
  首先下载lame的源代码,然后找到他的vc_solution文件夹,这里我们需要的是vc9_lame.sln这个解决方案,而最终对我们有用的是libmp3lame-static和libmpghip-static这两个工程,其他可以先remove掉,然后直接编译就好,这里需要注意的是如果你使用模拟器调试,那么实际上需要的是win32的lib,而如果你使用真机调试,那么需要的则是Arm的lib,这也就是问什么同样的工程在模拟器下可用而在真机时则崩溃。

  编译,然后我们拿到libmpghip-static.lib和libmp3lame-static.lib两个库,然后将他们引入我们自己的wp8 project中。记得Include进来lame.h
  在不同的Platform下都要设置,比如Arm的就要引用Arm的文件夹,win32的则用win32的lib
  接着我们需要建立一个windows phone 组件来包装lib,起名就叫audio好了,下面就是audio工程设置的大概属性
DSC0000.png
  设定完lib所在的路径后则记得在链接中加入库的引用,同样也要区分平台
DSC0001.png
  准备工作做完后建立两个filter一个是include一个是source,当然不建立也没有任何问题
  然后我们建立两个类,一个是包装类叫做LameWrapper,另一个是CompressedMp3Content用作返回值,这两个类都是C++/CX的类,并且要被C#使用,所以注意这两个类必须是Public ref class并且是sealed的并且不能有public的析构函数,烦吧~~~
  我们来看LameWrapper.h的定义



public ref class LameWrapper sealed
{
public:
LameWrapper();
IAsyncOperation^ EncodePcm2Mp3(IBuffer^ inPcm, int sampleRate, int channels);
};
  然后是用作返回值的CompressedMp3Content类的定义



public ref class CompressedMp3Content sealed
{
public:
CompressedMp3Content(void);
property Platform::Array^ Mp3Data;
};
  接下来是压缩MP3的重头戏~LameWrapper.CPP
  首先Include “Lame.h”
  然后来看一下EncodePcm2Mp3方法:



Windows::Foundation::IAsyncOperation^ LameWrapper::EncodePcm2Mp3(IBuffer^ inPcm, int sampleRate, int channels)
{
lame_global_flags* lame = lame_init();
lame_set_in_samplerate(lame, sampleRate);
lame_set_num_channels(lame, channels);
lame_set_quality(lame, 5);
lame_init_params(lame);
IUnknown* pUnk = reinterpret_cast(inPcm);
IBufferByteAccess* pAccess = NULL;
byte* bytes = NULL;
HRESULT hr = pUnk->QueryInterface(__uuidof(IBufferByteAccess), (void**)&pAccess);
if (SUCCEEDED(hr))
{
hr = pAccess->Buffer(&bytes);
if (SUCCEEDED(hr))
{
return Concurrency::create_async([=]()->CompressedMp3Content^
{
CompressedMp3Content^ result = ref new CompressedMp3Content();
int pcmLength = inPcm->Length;
///TODO:此处直接获取了pcmLength的一半,在pcmLength为奇数的时候会丢掉最后一个字节~不过无所谓了......
std::vector inBuffer = std::vector(pcmLength / 2);
for (std::vector::size_type i=0; i 0)
{
result->Mp3Data = ref new Platform::Array(size);
for(int i=0; iMp3Data)->get(i) = outBuffer;
}
}
lame_close(lame);
pAccess->Release();
return result;
});
}
else
{
lame_close(lame);
pAccess->Release();
throw ref new Platform::Exception(hr, L"Couldn't get bytes from the buffer");
}
}
else
{
lame_close(lame);
throw ref new Platform::Exception(hr, L"Couldn't access the buffer");
}
}
  先设置所需参数,通常我们录下来只有一个声道了,所以channels给个1好了,当然左右声道都给同一个PCM buffer就变成双声道了也可以,lame_set_quality时有0~9个阶段的质量可选,取中就好,设的太高压缩会很慢,接下来开始process传进来的buffer,为了方便我们给进来的是byte数组,而lame要的是short数组,所以我们要先将byte*转换为short*转换完成之后直接调用lame_encode_buffer来进行转换吧,转换完成后会返回实际的字节数,然后我们将转好的byte*放入CompressedMp3Content类中以供c#进行进一步处理,然后记得release all~~~~~
  回到c#这一侧,当然要引用我们的audio工程,在C#这一侧我们先要拿到pcm流,不知道为什么使用之前提到的AudioVideoCaptureDevice录制PCM会崩溃,所以我们还是使用传统的xna下的Microphone来录制pcm流,
  录制完成后就很简单了new出一个LameWrapper后直接调用EncodePCM2Mp3就好了~



LameWrapper lame = new LameWrapper();
CompressedMp3Content item = await lame.EncodePcm2Mp3(buffer, MicrophoneWrapper.Instance.SampleRate, 1);
  附件1:录制AAC的http://files.iyunv.com/bader/RecordAAC.rar
  附件2:录制MP3的,稍后再传......
  大功告成~呼~
  
  PS:博主开了微博了~详情猛戳:http://weibo.com/SandCu
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-69500-1-1.html 上篇帖子: 我认为从预览版的情况看,windows slate(8) 很可能以失败收场 下篇帖子: Windows 8 应用商店应用开发 之 应用间文件访问
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表