使用ffmpeg解码音频文件到PCM格式
2013-10-18 15:46
447 查看
最近忙于使用ffmpeg播放音乐文件的项目,现将开发经验总结如下:
一、解码音乐文件的大致流程如下:
1,打开音乐文件,调用av_open_input_file()
2,查找audio stream,调用av_find_stream_info()
3,查找对应的decoder,调用avcodec_find_decoder()
4,打开decoder,调用avcodec_open()
5,读取一桢数据包,调用av_read_frame()
6,解码数据包,调用avcodec_decode_audio3()
7,将解码后的数据返回
这样,得到解码后的PCM数据之后,我们可以播放、也可以encode成其他格式。
二、相关代码:
1,打开文件
2,解码数据
3,关闭和释放资源
一、解码音乐文件的大致流程如下:
1,打开音乐文件,调用av_open_input_file()
2,查找audio stream,调用av_find_stream_info()
3,查找对应的decoder,调用avcodec_find_decoder()
4,打开decoder,调用avcodec_open()
5,读取一桢数据包,调用av_read_frame()
6,解码数据包,调用avcodec_decode_audio3()
7,将解码后的数据返回
这样,得到解码后的PCM数据之后,我们可以播放、也可以encode成其他格式。
二、相关代码:
1,打开文件
// return 0: OK // return -1: arguments are wrong int internal_open(const char* file) { int i = 0; int res = 0; LOGD("enter internal_open(), file name:%s", file); if (file == 0 || strlen(file) == 0) { LOGE("%s, argument file is wrong!", __FUNCTION__); return -1; } // try open file if ((res = av_open_input_file(&m_format_ctx, file, NULL, 0, NULL)) != 0) { LOGE("%s, av_open_input_file() return failed!", __FUNCTION__); return res; } // find streams information if ((res = av_find_stream_info(m_format_ctx) < 0)) { LOGE("%s, av_find_stream_info() could not find codec parameters!", __FUNCTION__); return res; } av_dump_format(m_format_ctx, 0, file, 0); for(i = 0; i < m_format_ctx->nb_streams; i++) { // get audio stream id if(m_format_ctx->streams[i]->codec->codec_type == ***MEDIA_TYPE_AUDIO) { m_audio_stream = i; break; } } if(m_audio_stream == -1) { LOGE("%s, find audioStream failed!", __FUNCTION__); return -4; } // get audio stream codec m_codec_ctx = m_format_ctx->streams[m_audio_stream]->codec; // find the mpeg audio decoder m_codec = avcodec_find_decoder(m_codec_ctx->codec_id); if (!m_codec) { LOGE("%s, codec not found!", __FUNCTION__); return -5; } // open it if (avcodec_open(m_codec_ctx, m_codec) < 0) { LOGE("%s, could not open codec!", __FUNCTION__); return -7; } LOGD("exit internal_open()"); return 0; }
2,解码数据
int internal_getaudio(unsigned char buff[], long num_samples) { //***Packet avpkt; long copied_len = 0; int frame_size = 0; int decoded_len = 0; int real_copied = 0; int decoded_audio_len = 0; unsigned char* valid_data_pointer = 0; LOGD("enter internal_getaudio()"); // copy the backup (has not copied in last time) data at first! if (m_audio_buff_backup_len > 0) { LOGI("%s, has last not copied data in backup buff, length:%d", __FUNCTION__, m_audio_buff_backup_len); if (m_audio_buff_backup_len >= num_samples) { memcpy(buff, m_audio_buff_backup, num_samples); copied_len += num_samples; LOGI("%s, only copy data from backup buff, return 0", __FUNCTION__); } else { memcpy(buff, m_audio_buff_backup, m_audio_buff_backup_len); copied_len += m_audio_buff_backup_len; LOGI("%s, copy %d length data from backup buff", __FUNCTION__, m_audio_buff_backup_len); } } // decode new data while (copied_len < num_samples && av_read_frame(m_format_ctx, &m_avpkt) >= 0) { LOGI("%s, av_read_frame() return successful!", __FUNCTION__); if (m_avpkt.stream_index == m_audio_stream) { while (m_avpkt.size > 0) { LOGI("%s, current packet size:%d", __FUNCTION__, m_avpkt.size); frame_size = ***CODEC_MAX_AUDIO_FRAME_SIZE; memset(m_audio_buff, 0, ***CODEC_MAX_AUDIO_FRAME_SIZE); decoded_len = avcodec_decode_audio3(m_codec_ctx, (short *)m_audio_buff, &frame_size, &m_avpkt); LOGI("%s, current decoded size:%d", __FUNCTION__, decoded_len); if (decoded_len > 0) { m_avpkt.size -= decoded_len; m_avpkt.data += decoded_len; // copy audio data to output buff if ((num_samples-copied_len) > decoded_audio_len) { memcpy(buff+copied_len, m_audio_buff, frame_size); copied_len += frame_size; LOGI("%s, copy1, %d bytes has copied to output buff, total:%d!", __FUNCTION__, frame_size, copied_len); } else { real_copied = (num_samples-copied_len); memcpy(buff+copied_len, m_audio_buff, real_copied); copied_len += real_copied; LOGI("%s, copy2, %d bytes has copied to output buff, total:%d!", __FUNCTION__, real_copied, copied_len); m_audio_buff_backup_len = frame_size - real_copied; memcpy(m_audio_buff_backup, m_audio_buff+real_copied, m_audio_buff_backup_len); LOGI("%s, copy2, %d bytes has copied to backup buff!", __FUNCTION__, m_audio_buff_backup_len); break; } } else { LOGE("%s, decoded size is error, returned!", __FUNCTION__); break; } } } } LOGD("exit internal_getaudio(), decoded length: %d", copied_len); return copied_len; }
3,关闭和释放资源
int internal_close() { if (m_format_ctx) { av_close_input_file(m_format_ctx); m_format_ctx = 0; } return 0; }
int internal_release() { if (m_avpkt.data) { av_free_packet(&m_avpkt); } if (!m_codec_ctx) { avcodec_close(m_codec_ctx); m_codec_ctx = 0; } return 0; }
相关文章推荐
- 使用C语言实现pcm格式音频文件播放速度的改变
- 使用C语言实现从一段pcm格式音频文件中截取一段数据
- 【FFmpeg杂记】音频解码输出PCM格式数据分析
- 使用 ffmpeg 进行网络推流:拉流->解封装->解码->处理原始数据(音频、视频)->编码->编码->推流
- FFmpeg支持的音频编解码格式
- 音频编解码·格式篇(1)Wave PCM audio format(WAV)
- 使用FFMPEG类库分离出多媒体文件中的音频码流
- 使用FFMPEG类库分离出多媒体文件中的音频码流
- FFmpeg+SDL2.0 音频解码播放(部分格式杂音处理)
- FFmpeg支持的音频和视频编解码格式
- ffmpeg解码音频数据时,进行重采样(即改变文件原有的采样率)
- ffmpeg解码音频数据时,进行重采样(即改变文件原有的采样率)
- 常见多媒体文件格式及视音频编解码总结
- 音频编解码·格式篇(1)Wave PCM audio format(WAV)
- ffmpeg音频处理——pcm格式与resample(重采样)
- ffmpeg解码音频数据时,开展重采样(即改变文件原有的采样率)
- 关于ffmpeg 的总结(一个linux 下 集 屏幕录像录音,音频视频转换,合并音频视频文件,格式转换于一身的命
- Ffmpeg快速命令使用 Ffmpeg选项详解 Ffmepg格式详解 常见视频文件格式详解
- 使用ffmpeg实现解码并保存为yuv文件
- Ffmpeg快速命令使用 Ffmpeg选项详解 Ffmepg格式详解 常见视频文件格式详解