编码成amr格式
来源:互联网 发布:js鼠标悬停图片放大 编辑:程序博客网 时间:2024/06/05 06:23
==============================================================================
解决什么问题
解决语音聊天时,录音文件体积偏大的问题。
怎么解决
使用amr格式来编码,可有效降低体积并保持较好的音质。
==============================================================================
简介
使用ffmpeg跟opencore-amrnb来完成amr格式的编码保存。
==============================================================================
代码演示,在ios上运行的代码
// 打开解码器
- (BOOL)openInCodec
{
NSString* inpath = _infilepath;
BOOL openSuccess = NO;
int audio_stream_index = -1;
do {
_inFormatContext = avformat_alloc_context();
int ret = avformat_open_input(&_inFormatContext, [inpath UTF8String], NULL, NULL);
if (ret != 0) {
NSLog(@"open input failed");
break;
}
ret = avformat_find_stream_info(_inFormatContext, NULL);
if (ret < 0) {
NSLog(@"find stream info failed");
break;
}
for (int pos = 0; pos < _inFormatContext->nb_streams; pos ++) {
if (_inFormatContext->streams[pos]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_stream_index = pos;
break;
}
}
if (audio_stream_index == -1) {
NSLog(@"no audio stream");
break;
}
_inCodecContext = _inFormatContext->streams[audio_stream_index]->codec;
_inCodec = avcodec_find_decoder(_inCodecContext->codec_id);
if (_inCodec == NULL) {
NSLog(@"no avcodec found");
_inCodecContext = NULL;
break;
}
ret = avcodec_open2(_inCodecContext, _inCodec, NULL);
if (ret != 0) {
NSLog(@"open codec failed");
_inCodecContext = NULL;
break;
}
_audiostream_index = audio_stream_index;
openSuccess = YES;
}while (0);
if (!openSuccess) {
[self destroyffmpeg];
}
return openSuccess;
}
// 打开amr编码器
- (BOOL)openOutCodec
{
NSString* outpath = [NSHomeDirectory()stringByAppendingString:@"/Documents/out.amr"];
NSString* outfilepath = outpath;
BOOL openSuccess = NO;
do {
int ret = avformat_alloc_output_context2(&_outFormatContext, NULL, "amr", [outfilepath UTF8String]);
if (ret < 0) {
NSLog(@"alloc output format failed");
break;
}
AVOutputFormat* outFormat = _outFormatContext->oformat;
outFormat->audio_codec = AV_CODEC_ID_AMR_NB;
outFormat->video_codec = AV_CODEC_ID_NONE;
_outCodec = avcodec_find_encoder(outFormat->audio_codec);
if (_inCodec == NULL) {
NSLog(@"no encoder found");
break;
}
AVStream* audioStream = avformat_new_stream(_outFormatContext, _outCodec);
if (audioStream == NULL) {
NSLog(@"new stream failed");
break;
}
audioStream->id = 0;
audioStream->index = 0;
_outCodecContext = audioStream->codec;
if (_outCodecContext == NULL) {
NSLog(@"no codecContext in stream");
break;
}
_outCodecContext->sample_fmt = AV_SAMPLE_FMT_S16;
_outCodecContext->channels = 1;
_outCodecContext->channel_layout = av_get_default_channel_layout(1);
_outCodecContext->sample_rate = 8000;
_outCodecContext->bit_rate = 12200;
if (outFormat->flags & AVFMT_GLOBALHEADER) {
_outCodecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
ret = avcodec_open2(_outCodecContext, _outCodec, NULL);
if (ret < 0) {
NSLog(@"open encoder failed");
break;
}
av_dump_format(_outFormatContext, 0, [outfilepath UTF8String], 1);
if (!(_outFormatContext->flags & AVFMT_NOFILE)) {
ret = avio_open2(&_outFormatContext->pb, [outfilepath UTF8String], AVIO_FLAG_WRITE, &_outFormatContext->interrupt_callback, NULL);
if (ret < 0) {
NSLog(@"avio_open2 failed: %d(%s)", ret, av_err2str(ret));
break;
}
}
AVDictionary* dict = NULL;
ret = avformat_write_header(_outFormatContext, &dict);
if (ret < 0) {
NSLog(@"write header failed: %d(%s)", ret, av_err2str(ret));
break;
}
openSuccess = YES;
}while (0);
if (!openSuccess) {
[self destroyffmpeg];
}
return openSuccess;
}
// 解码的过程,编码成amr(有些细节还需要考虑)
- (void)convert
{
BOOL eof = NO;
while (1) {
AVPacket packet;
int ret = av_read_frame(_inFormatContext, &packet);
if (ret < 0) {
if (ret == AVERROR_EOF || url_feof(_inFormatContext->pb)) {
NSLog(@"read_frame eof");
eof = YES;
break;
}
else {
NSLog(@"av_read_frame failed, %d(%s)", ret, av_err2str(ret));
break;
}
}
if (packet.stream_index == _audiostream_index) {
int size = packet.size;
AVFrame frame;
AVPacket encodePacket;
void* out_buffer = NULL;
while (size > 0) {
// av_frame_unref(&frame);
int gotframe = 0;
int len = avcodec_decode_audio4(_inCodecContext, &frame, &gotframe, &packet);
if (len < 0) {
NSLog(@"audio decode failed");
break;
}
if (gotframe) {
bool needConvert = true;
int targetSampelrate = 8000;
int targetChannels = 1;
if (needConvert) {
int out_size = av_samples_get_buffer_size(NULL, targetChannels, frame.nb_samples, AV_SAMPLE_FMT_S16, 0);
if (out_size >= 0) {
// if (_swr) { // more think here for if
// [self deletetSwr];
// }
bool initswr = true;
if (_swr == NULL) {
uint64_t in_channel_layout = av_get_default_channel_layout(av_frame_get_channels(&frame));
uint64_t out_channel_layout = av_get_default_channel_layout(targetChannels);
int inSamplerate = frame.sample_rate;
_swr = swr_alloc_set_opts(NULL,
out_channel_layout, (enum AVSampleFormat )AV_SAMPLE_FMT_S16, targetSampelrate,
in_channel_layout, (enum AVSampleFormat)frame.format, inSamplerate, 0, NULL);
int ret = swr_init(_swr);
if (ret != 0) {
initswr = false;
}
}
if (_swr && initswr) {
if (frame.extended_data && frame.data[0] && frame.linesize[0] > 0) {
out_buffer = av_malloc(out_size);
if (out_buffer) {
int convertSamples = swr_convert(_swr, (uint8_t**)(&out_buffer), frame.nb_samples, (const uint8_t**)frame.extended_data, frame.nb_samples);
int len = convertSamples * targetChannels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
int nb_samples = _outCodecContext->frame_size / 1;
int buffer_size = av_samples_get_buffer_size( NULL, _outCodecContext->channels, nb_samples, AV_SAMPLE_FMT_S16, 0 );
AVFrame* decodeframe = avcodec_alloc_frame();
decodeframe->nb_samples = nb_samples;
ret = avcodec_fill_audio_frame( decodeframe, _outCodecContext->sample_fmt, AV_SAMPLE_FMT_S16, (const uint8_t *)out_buffer, buffer_size, 0 );
if( ret < 0 )
{
NSLog( @"avcodec_fill_audio_frame error!");
break;
}
encodePacket.data = NULL;
encodePacket.size = 0;
av_init_packet(&encodePacket);
ret = avcodec_encode_audio2(_outCodecContext, &encodePacket, decodeframe, &gotframe);
if (ret < 0) {
NSLog(@"encode audio fail: %d(%s)", ret, av_err2str(ret));
break;
}
if (gotframe == 0) {
NSLog(@"did not got frame");
break;
}
encodePacket.stream_index = 0;
ret = av_write_frame(_outFormatContext, &encodePacket);
if (ret < 0) {
NSLog(@"av_write_frame failed: %d(%s)", ret, av_err2str(ret));
break;
}
size -= len;
}
}
}
}
}
}
}
av_free_packet(&encodePacket);
if (out_buffer) {
av_free(out_buffer);
}
}
}
if (eof) {
av_write_trailer(_outFormatContext);
}
}
==============================================================================
后续
* ffmpeg在android与ios上的编译与使用
* opencore-amr的编译与使用
==============================================================================
解决什么问题
解决语音聊天时,录音文件体积偏大的问题。
怎么解决
使用amr格式来编码,可有效降低体积并保持较好的音质。
==============================================================================
简介
使用ffmpeg跟opencore-amrnb来完成amr格式的编码保存。
==============================================================================
代码演示,在ios上运行的代码
// 打开解码器
- (BOOL)openInCodec
{
NSString* inpath = _infilepath;
BOOL openSuccess = NO;
int audio_stream_index = -1;
do {
_inFormatContext = avformat_alloc_context();
int ret = avformat_open_input(&_inFormatContext, [inpath UTF8String], NULL, NULL);
if (ret != 0) {
NSLog(@"open input failed");
break;
}
ret = avformat_find_stream_info(_inFormatContext, NULL);
if (ret < 0) {
NSLog(@"find stream info failed");
break;
}
for (int pos = 0; pos < _inFormatContext->nb_streams; pos ++) {
if (_inFormatContext->streams[pos]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_stream_index = pos;
break;
}
}
if (audio_stream_index == -1) {
NSLog(@"no audio stream");
break;
}
_inCodecContext = _inFormatContext->streams[audio_stream_index]->codec;
_inCodec = avcodec_find_decoder(_inCodecContext->codec_id);
if (_inCodec == NULL) {
NSLog(@"no avcodec found");
_inCodecContext = NULL;
break;
}
ret = avcodec_open2(_inCodecContext, _inCodec, NULL);
if (ret != 0) {
NSLog(@"open codec failed");
_inCodecContext = NULL;
break;
}
_audiostream_index = audio_stream_index;
openSuccess = YES;
}while (0);
if (!openSuccess) {
[self destroyffmpeg];
}
return openSuccess;
}
// 打开amr编码器
- (BOOL)openOutCodec
{
NSString* outpath = [NSHomeDirectory()stringByAppendingString:@"/Documents/out.amr"];
NSString* outfilepath = outpath;
BOOL openSuccess = NO;
do {
int ret = avformat_alloc_output_context2(&_outFormatContext, NULL, "amr", [outfilepath UTF8String]);
if (ret < 0) {
NSLog(@"alloc output format failed");
break;
}
AVOutputFormat* outFormat = _outFormatContext->oformat;
outFormat->audio_codec = AV_CODEC_ID_AMR_NB;
outFormat->video_codec = AV_CODEC_ID_NONE;
_outCodec = avcodec_find_encoder(outFormat->audio_codec);
if (_inCodec == NULL) {
NSLog(@"no encoder found");
break;
}
AVStream* audioStream = avformat_new_stream(_outFormatContext, _outCodec);
if (audioStream == NULL) {
NSLog(@"new stream failed");
break;
}
audioStream->id = 0;
audioStream->index = 0;
_outCodecContext = audioStream->codec;
if (_outCodecContext == NULL) {
NSLog(@"no codecContext in stream");
break;
}
_outCodecContext->sample_fmt = AV_SAMPLE_FMT_S16;
_outCodecContext->channels = 1;
_outCodecContext->channel_layout = av_get_default_channel_layout(1);
_outCodecContext->sample_rate = 8000;
_outCodecContext->bit_rate = 12200;
if (outFormat->flags & AVFMT_GLOBALHEADER) {
_outCodecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
ret = avcodec_open2(_outCodecContext, _outCodec, NULL);
if (ret < 0) {
NSLog(@"open encoder failed");
break;
}
av_dump_format(_outFormatContext, 0, [outfilepath UTF8String], 1);
if (!(_outFormatContext->flags & AVFMT_NOFILE)) {
ret = avio_open2(&_outFormatContext->pb, [outfilepath UTF8String], AVIO_FLAG_WRITE, &_outFormatContext->interrupt_callback, NULL);
if (ret < 0) {
NSLog(@"avio_open2 failed: %d(%s)", ret, av_err2str(ret));
break;
}
}
AVDictionary* dict = NULL;
ret = avformat_write_header(_outFormatContext, &dict);
if (ret < 0) {
NSLog(@"write header failed: %d(%s)", ret, av_err2str(ret));
break;
}
openSuccess = YES;
}while (0);
if (!openSuccess) {
[self destroyffmpeg];
}
return openSuccess;
}
// 解码的过程,编码成amr(有些细节还需要考虑)
- (void)convert
{
BOOL eof = NO;
while (1) {
AVPacket packet;
int ret = av_read_frame(_inFormatContext, &packet);
if (ret < 0) {
if (ret == AVERROR_EOF || url_feof(_inFormatContext->pb)) {
NSLog(@"read_frame eof");
eof = YES;
break;
}
else {
NSLog(@"av_read_frame failed, %d(%s)", ret, av_err2str(ret));
break;
}
}
if (packet.stream_index == _audiostream_index) {
int size = packet.size;
AVFrame frame;
AVPacket encodePacket;
void* out_buffer = NULL;
while (size > 0) {
// av_frame_unref(&frame);
int gotframe = 0;
int len = avcodec_decode_audio4(_inCodecContext, &frame, &gotframe, &packet);
if (len < 0) {
NSLog(@"audio decode failed");
break;
}
if (gotframe) {
bool needConvert = true;
int targetSampelrate = 8000;
int targetChannels = 1;
if (needConvert) {
int out_size = av_samples_get_buffer_size(NULL, targetChannels, frame.nb_samples, AV_SAMPLE_FMT_S16, 0);
if (out_size >= 0) {
// if (_swr) { // more think here for if
// [self deletetSwr];
// }
bool initswr = true;
if (_swr == NULL) {
uint64_t in_channel_layout = av_get_default_channel_layout(av_frame_get_channels(&frame));
uint64_t out_channel_layout = av_get_default_channel_layout(targetChannels);
int inSamplerate = frame.sample_rate;
_swr = swr_alloc_set_opts(NULL,
out_channel_layout, (enum AVSampleFormat )AV_SAMPLE_FMT_S16, targetSampelrate,
in_channel_layout, (enum AVSampleFormat)frame.format, inSamplerate, 0, NULL);
int ret = swr_init(_swr);
if (ret != 0) {
initswr = false;
}
}
if (_swr && initswr) {
if (frame.extended_data && frame.data[0] && frame.linesize[0] > 0) {
out_buffer = av_malloc(out_size);
if (out_buffer) {
int convertSamples = swr_convert(_swr, (uint8_t**)(&out_buffer), frame.nb_samples, (const uint8_t**)frame.extended_data, frame.nb_samples);
int len = convertSamples * targetChannels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
int nb_samples = _outCodecContext->frame_size / 1;
int buffer_size = av_samples_get_buffer_size( NULL, _outCodecContext->channels, nb_samples, AV_SAMPLE_FMT_S16, 0 );
AVFrame* decodeframe = avcodec_alloc_frame();
decodeframe->nb_samples = nb_samples;
ret = avcodec_fill_audio_frame( decodeframe, _outCodecContext->sample_fmt, AV_SAMPLE_FMT_S16, (const uint8_t *)out_buffer, buffer_size, 0 );
if( ret < 0 )
{
NSLog( @"avcodec_fill_audio_frame error!");
break;
}
encodePacket.data = NULL;
encodePacket.size = 0;
av_init_packet(&encodePacket);
ret = avcodec_encode_audio2(_outCodecContext, &encodePacket, decodeframe, &gotframe);
if (ret < 0) {
NSLog(@"encode audio fail: %d(%s)", ret, av_err2str(ret));
break;
}
if (gotframe == 0) {
NSLog(@"did not got frame");
break;
}
encodePacket.stream_index = 0;
ret = av_write_frame(_outFormatContext, &encodePacket);
if (ret < 0) {
NSLog(@"av_write_frame failed: %d(%s)", ret, av_err2str(ret));
break;
}
size -= len;
}
}
}
}
}
}
}
av_free_packet(&encodePacket);
if (out_buffer) {
av_free(out_buffer);
}
}
}
if (eof) {
av_write_trailer(_outFormatContext);
}
}
==============================================================================
后续
* ffmpeg在android与ios上的编译与使用
* opencore-amr的编译与使用
==============================================================================
0 0
- 编码成amr格式
- amr编码
- Amr格式分析
- AMR音频文件格式分析
- amr格式解析
- AMR音频文件格式分析
- amr格式解析
- AMR 编码方式列表
- AMR 语音编码
- 播放amr格式的音频
- android pcm转amr格式
- ffmpeg PCM转AMR格式
- 分享AMR音频编码DLL
- AMR2与AMR编码区别
- ffmpeg-libopencore-amr 语音编码
- ios 使用音频队列播放amr格式转换成wav的格式,只有嘈杂声
- amr格式转换为MP3格式
- AMR 编码 PCM & WAV (opencore-amr-0.1.5)
- 回文词(Palindromes, UVa401)
- APPCAN页面图片自适应等比例显示
- lightoj1311 - Unlucky Bird【物理题】
- hdu 1573(中国剩余定理非互质情况)
- Java RMI codebase 小议
- 编码成amr格式
- AngularJs路由机制
- 【Maven由浅入深】3.在Eclipse中创建maven工程
- linux: find locate whereis which type
- 设计模式:门面模式
- JAVA入门自学笔记
- redis 的无序集合和hash操作
- C++ STL仿函数
- CookieContainer加不了cookie加不了Cookie解决办法