44100 * 16 * 2 = 1378.125kbps
1378.125 * 60 / 8 / 1024 = 10.09MB
1.WAV编码 特点:音质非常好,大量软件都支持。 适用场合:多媒体开发的中间文件、保存音乐和音效素材。 2.MP3编码 特点:音质在128Kbit/s以上表现还不错,压缩比比较高,大量软件和硬件都支持,兼容性好。 适用场合:高比特率下对兼容性有要求的音乐欣赏。 3.AAC编码 特点:在小于128Kbit/s的码率下表现优异,并且多用于视频中的音频编码。 适用场合:128Kbit/s以下的音频编码,多用于视频中音频轨的编码。 4.Ogg编码 特点:可以用比MP3更小的码率实现比MP3更好的音质,高中低码率下均有良好的表现,兼容性不够好,流媒体特性不支持。 适用场合:语音聊天的音频消息场景。
#include <jni.h>
#include <string>
#include <android/log.h>
#include <android/native_window_jni.h>
#include <unistd.h>
extern "C" {
//编码
#include "libavcodec/avcodec.h"
//封装格式处理
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
//像素处理
#include "libswscale/swscale.h"
}
#define LOG_TAG "aruba"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_aruba_ffmpegapplication_DecodeActivity_decodeAudio(JNIEnv *env, jobject instance,
jstring inputFilePath_,
jstring outputFilePath_) {
const char *inputFilePath = env->GetStringUTFChars(inputFilePath_, 0);
const char *outputFilePath = env->GetStringUTFChars(outputFilePath_, 0);
//注册FFmpeg中各大组件
av_register_all();
//打开文件
AVFormatContext *formatContext = avformat_alloc_context();
if (avformat_open_input(&formatContext, inputFilePath, NULL, NULL) != 0) {
LOGE("打开失败");
avformat_free_context(formatContext);
env->ReleaseStringUTFChars(inputFilePath_, inputFilePath);
env->ReleaseStringUTFChars(outputFilePath_, outputFilePath);
return;
}
//将文件信息填充进AVFormatContext
if (avformat_find_stream_info(formatContext, NULL) < 0) {
LOGE("获取文件信息失败");
avformat_free_context(formatContext);
env->ReleaseStringUTFChars(inputFilePath_, inputFilePath);
env->ReleaseStringUTFChars(outputFilePath_, outputFilePath);
return;
}
//获取视频流的编解码器上下文
AVCodecContext *codecContext = NULL;
int audio_stream_idx = -1;
for (int i = 0; i < formatContext->nb_streams; ++i) {
if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {//如果是视频流
codecContext = formatContext->streams[i]->codec;
audio_stream_idx = i;
break;
}
}
if (codecContext == NULL) {
avformat_free_context(formatContext);
env->ReleaseStringUTFChars(inputFilePath_, inputFilePath);
env->ReleaseStringUTFChars(outputFilePath_, outputFilePath);
return;
}
//根据编解码器上下文的id获取视频流解码器
AVCodec *codec = avcodec_find_decoder(codecContext->codec_id);
//打开解码器
if (avcodec_open2(codecContext, codec, NULL) < 0) {
LOGE("解码失败");
avformat_free_context(formatContext);
env->ReleaseStringUTFChars(inputFilePath_, inputFilePath);
env->ReleaseStringUTFChars(outputFilePath_, outputFilePath);
return;
}
//开始读每一帧
//存放压缩数据
AVPacket *pkt = (AVPacket *) (av_malloc(sizeof(AVPacket)));
av_init_packet(pkt);
//存放解压数据
AVFrame *picture = av_frame_alloc();
int picture_ptr = 0;
//音频转码组件上下文
SwrContext *swrContext = swr_alloc();
// struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
// int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
// int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
// int log_offset, void *log_ctx);
//AV_CH_LAYOUT_STEREO:双声道 AV_SAMPLE_FMT_S16:量化格式 16位 codecContext->sample_rate:采样率 Hz
swr_alloc_set_opts(swrContext, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16,
codecContext->sample_rate,//输出采样率和输入采样率应相同
codecContext->channel_layout, codecContext->sample_fmt,
codecContext->sample_rate, 0, NULL
);
//原音频通道数
int channel_count = av_get_channel_layout_nb_channels(codecContext->channel_layout);
//单通道最大存放转码数据 所占字节 = 采样率*量化格式 / 8
int out_size = 44100 * 16 / 8;
uint8_t *out = (uint8_t *) (av_malloc(out_size));
//文件
FILE *output_file = fopen(outputFilePath, "wb");
while (av_read_frame(formatContext, pkt) == 0) {//读到每一帧的压缩数据存放在AVPacket
if (pkt->stream_index == audio_stream_idx) {
//解码
avcodec_decode_audio4(codecContext, picture, &picture_ptr, pkt);
LOGE("picture_ptr %d", picture_ptr);
if (picture_ptr > 0) {
//转码
swr_convert(swrContext, &out, out_size,
(const uint8_t **) (picture->data), picture->nb_samples);
// int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
// enum AVSampleFormat sample_fmt, int align);
//缓冲区真实大小
int size = av_samples_get_buffer_size(NULL, channel_count, picture->nb_samples,
AV_SAMPLE_FMT_S16, 1);
fwrite(out, sizeof(uint8_t), size, output_file);
}
}
av_free_packet(pkt);
}
//关闭文件
fclose(output_file);
//释放资源
av_freep(out);
swr_free(&swrContext);
av_frame_free(&picture);
avcodec_close(codecContext);
avformat_free_context(formatContext);
env->ReleaseStringUTFChars(inputFilePath_, inputFilePath);
env->ReleaseStringUTFChars(outputFilePath_, outputFilePath);
}
我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1v7genpiu1cy3