Feature: change filter when playing

pull/221/head
xufuji456 2 years ago
parent e8774a77d0
commit 51960d6815
  1. 6
      app/src/main/cpp/audio_player.cpp
  2. 31
      app/src/main/cpp/audio_player_jni.cpp
  3. 53
      app/src/main/cpp/ff_audio_player.cpp
  4. 7
      app/src/main/cpp/ff_audio_player.h

@ -103,7 +103,7 @@ end:
return ret; return ret;
} }
AUDIO_PLAYER_FUNC(void, play, jstring input_jstr, jstring filter_jstr) { AUDIO_PLAYER_FUNC(void, play111, jstring input_jstr, jstring filter_jstr) {
int got_frame = 0, ret; int got_frame = 0, ret;
AVPacket packet; AVPacket packet;
AVFilterGraph *audioFilterGraph; AVFilterGraph *audioFilterGraph;
@ -262,13 +262,13 @@ end:
LOGE(TAG, "audio release..."); LOGE(TAG, "audio release...");
} }
AUDIO_PLAYER_FUNC(void, again, jstring filter_jstr) { AUDIO_PLAYER_FUNC(void, again111, jstring filter_jstr) {
if (!filter_jstr) return; if (!filter_jstr) return;
filter_again = 1; filter_again = 1;
filter_desc = env->GetStringUTFChars(filter_jstr, nullptr); filter_desc = env->GetStringUTFChars(filter_jstr, nullptr);
} }
AUDIO_PLAYER_FUNC(void, release) { AUDIO_PLAYER_FUNC(void, release111) {
filter_release = 1; filter_release = 1;
} }

@ -8,28 +8,31 @@
#define SLEEP_TIME (16000) #define SLEEP_TIME (16000)
FFAudioPlayer *audioPlayer;
AUDIO_PLAYER_FUNC(void, play, jstring path) { AUDIO_PLAYER_FUNC(void, play, jstring path) {
if (path == nullptr) if (path == nullptr)
return; return;
int result = 0; int result = 0;
const char* native_path = env->GetStringUTFChars(path, JNI_FALSE); const char* native_path = env->GetStringUTFChars(path, JNI_FALSE);
auto *audioPlayer = new FFAudioPlayer(); audioPlayer = new FFAudioPlayer();
// 打开输入流 // open stream, and init work
audioPlayer->open(native_path); audioPlayer->open(native_path);
// 初始化AudioTrack // init AudioTrack
jclass audio_class = env->GetObjectClass(thiz); jclass audio_class = env->GetObjectClass(thiz);
jmethodID audio_track_method = env->GetMethodID(audio_class, jmethodID audio_track_method = env->GetMethodID(audio_class,
"createAudioTrack", "(II)Landroid/media/AudioTrack;"); "createAudioTrack", "(II)Landroid/media/AudioTrack;");
jobject audio_track = env->CallObjectMethod(thiz, audio_track_method, audioPlayer->getSampleRate(), audioPlayer->getChannel()); jobject audio_track = env->CallObjectMethod(thiz, audio_track_method,
// 调用play函数 audioPlayer->getSampleRate(), audioPlayer->getChannel());
// play function
jclass audio_track_class = env->GetObjectClass(audio_track); jclass audio_track_class = env->GetObjectClass(audio_track);
jmethodID play_method = env->GetMethodID(audio_track_class, "play", "()V"); jmethodID play_method = env->GetMethodID(audio_track_class, "play", "()V");
env->CallVoidMethod(audio_track, play_method); env->CallVoidMethod(audio_track, play_method);
// 获取write方法id // method if of write
jmethodID write_method = env->GetMethodID(audio_track_class, "write", "([BII)I"); jmethodID write_method = env->GetMethodID(audio_track_class, "write", "([BII)I");
// 解码音频zhen // demux decode and play
while (result >= 0) { while (result >= 0) {
result = audioPlayer->decodeAudio(); result = audioPlayer->decodeAudio();
if (result == 0) { if (result == 0) {
@ -38,7 +41,7 @@ AUDIO_PLAYER_FUNC(void, play, jstring path) {
break; break;
} }
int size = result; int size = result;
// 调用AudioTrack播放(可优化:数组复用) // call AudioTrack to play(should be reused array)
jbyteArray audio_array = env->NewByteArray(size); jbyteArray audio_array = env->NewByteArray(size);
jbyte *data_address = env->GetByteArrayElements(audio_array, JNI_FALSE); jbyte *data_address = env->GetByteArrayElements(audio_array, JNI_FALSE);
memcpy(data_address, audioPlayer->getDecodeFrame(), size); memcpy(data_address, audioPlayer->getDecodeFrame(), size);
@ -46,7 +49,7 @@ AUDIO_PLAYER_FUNC(void, play, jstring path) {
env->CallIntMethod(audio_track, write_method, audio_array, 0, size); env->CallIntMethod(audio_track, write_method, audio_array, 0, size);
env->DeleteLocalRef(audio_array); env->DeleteLocalRef(audio_array);
// 延时等待 // audio sync
usleep(SLEEP_TIME); usleep(SLEEP_TIME);
} }
@ -55,4 +58,12 @@ AUDIO_PLAYER_FUNC(void, play, jstring path) {
env->CallVoidMethod(thiz, release_method); env->CallVoidMethod(thiz, release_method);
audioPlayer->close(); audioPlayer->close();
delete audioPlayer; delete audioPlayer;
} }
AUDIO_PLAYER_FUNC(void, again, jstring filter_jstr) {
if (!filter_jstr) return;
audioPlayer->setFilterAgain(true);
const char *desc = env->GetStringUTFChars(filter_jstr, nullptr);
audioPlayer->setFilterDesc(desc);
}

@ -87,15 +87,15 @@ int FFAudioPlayer::open(const char *path) {
packet = av_packet_alloc(); packet = av_packet_alloc();
out_buffer = new uint8_t [BUFFER_SIZE]; out_buffer = new uint8_t [BUFFER_SIZE];
// 打开输入流 // open input stream
ret = avformat_open_input(&formatContext, path, nullptr, nullptr); ret = avformat_open_input(&formatContext, path, nullptr, nullptr);
if (ret < 0) { if (ret < 0) {
LOGE(AUDIO_TAG, "avformat_open_input error=%s", av_err2str(ret)); LOGE(AUDIO_TAG, "avformat_open_input error=%s", av_err2str(ret));
return ret; return ret;
} }
// 查找stream信息 // (if need)find info: width、height、sample_rate、duration
avformat_find_stream_info(formatContext, nullptr); avformat_find_stream_info(formatContext, nullptr);
// 找到音频index // find audio index
for (int i=0; i<formatContext->nb_streams; i++) { for (int i=0; i<formatContext->nb_streams; i++) {
if (AVMEDIA_TYPE_AUDIO == formatContext->streams[i]->codecpar->codec_type) { if (AVMEDIA_TYPE_AUDIO == formatContext->streams[i]->codecpar->codec_type) {
audio_index = i; audio_index = i;
@ -105,30 +105,30 @@ int FFAudioPlayer::open(const char *path) {
if (audio_index == -1) { if (audio_index == -1) {
return -1; return -1;
} }
// 找到codec // find audio decoder
codec = avcodec_find_decoder(formatContext->streams[audio_index]->codecpar->codec_id); codec = avcodec_find_decoder(formatContext->streams[audio_index]->codecpar->codec_id);
codecContext = avcodec_alloc_context3(codec); codecContext = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codecContext, formatContext->streams[audio_index]->codecpar); avcodec_parameters_to_context(codecContext, formatContext->streams[audio_index]->codecpar);
// 打开解码器 // open decoder
ret = avcodec_open2(codecContext, codec, nullptr); ret = avcodec_open2(codecContext, codec, nullptr);
if (ret < 0) { if (ret < 0) {
LOGE(AUDIO_TAG, "avcodec_open2 error=%s", av_err2str(ret)); LOGE(AUDIO_TAG, "avcodec_open2 error=%s", av_err2str(ret));
return ret; return ret;
} }
// 输入:采样率、声道布局、音频格式 // input and output params
int in_sample_rate = codecContext->sample_rate; int in_sample_rate = codecContext->sample_rate;
auto in_sample_fmt = codecContext->sample_fmt; auto in_sample_fmt = codecContext->sample_fmt;
int in_ch_layout = (int)codecContext->channel_layout; int in_ch_layout = (int)codecContext->channel_layout;
out_sample_rate = in_sample_rate; // 输出采样率等于输入采样率 out_sample_rate = in_sample_rate;
out_sample_fmt = AV_SAMPLE_FMT_S16; // 16位 out_sample_fmt = AV_SAMPLE_FMT_S16;
out_ch_layout = AV_CH_LAYOUT_STEREO; // 双声道 out_ch_layout = AV_CH_LAYOUT_STEREO;
out_channel = codecContext->channels; out_channel = codecContext->channels;
// 初始化音频格式转换上下文swrContext // init resample context
swrContext = swr_alloc(); swrContext = swr_alloc();
swr_alloc_set_opts(swrContext, out_ch_layout, out_sample_fmt, out_sample_rate, swr_alloc_set_opts(swrContext, out_ch_layout, out_sample_fmt, out_sample_rate,
in_ch_layout, in_sample_fmt, in_sample_rate, 0, nullptr); in_ch_layout, in_sample_fmt, in_sample_rate, 0, nullptr);
swr_init(swrContext); swr_init(swrContext);
// init filter graph
filterFrame = av_frame_alloc(); filterFrame = av_frame_alloc();
initFilter(FILTER_DESC, codecContext, &audioFilterGraph, initFilter(FILTER_DESC, codecContext, &audioFilterGraph,
&audioSrcContext, &audioSinkContext); &audioSrcContext, &audioSinkContext);
@ -146,16 +146,16 @@ int FFAudioPlayer::getSampleRate() const {
int FFAudioPlayer::decodeAudio() { int FFAudioPlayer::decodeAudio() {
int ret; int ret;
// 读取音频数据(解封装) // demux: read a frame(should be demux thread)
ret = av_read_frame(formatContext, packet); ret = av_read_frame(formatContext, packet);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
// 判断是否位音频帧 // see if audio packet
if (packet->stream_index != audio_index) { if (packet->stream_index != audio_index) {
return 0; return 0;
} }
// 解码音频帧 // decode audio frame(should be decode thread)
ret = avcodec_send_packet(codecContext, packet); ret = avcodec_send_packet(codecContext, packet);
if (ret < 0) { if (ret < 0) {
LOGE(AUDIO_TAG, "avcodec_send_packet=%s", av_err2str(ret)); LOGE(AUDIO_TAG, "avcodec_send_packet=%s", av_err2str(ret));
@ -168,6 +168,17 @@ int FFAudioPlayer::decodeAudio() {
return ret; return ret;
} }
} }
if (filterAgain) {
filterAgain = false;
avfilter_graph_free(&audioFilterGraph);
if ((ret = initFilter(filterDesc, codecContext, &audioFilterGraph, &audioSrcContext, &audioSinkContext)) < 0) {
LOGE(AUDIO_TAG, "init_filter error, ret=%d\n", ret);
return ret;
}
LOGE(AUDIO_TAG, "play again,filter_descr=_=%s", filterDesc);
}
// put into filter // put into filter
ret = av_buffersrc_add_frame(audioSrcContext, inputFrame); ret = av_buffersrc_add_frame(audioSrcContext, inputFrame);
if (ret < 0) { if (ret < 0) {
@ -185,13 +196,13 @@ int FFAudioPlayer::decodeAudio() {
return ret; return ret;
} }
// 音频格式转换 // convert audio format and sample_rate
swr_convert(swrContext, &out_buffer, BUFFER_SIZE, swr_convert(swrContext, &out_buffer, BUFFER_SIZE,
(const uint8_t **)(filterFrame->data), filterFrame->nb_samples); (const uint8_t **)(filterFrame->data), filterFrame->nb_samples);
// 获取转换后缓冲区大小 // get buffer size after converting
int buffer_size = av_samples_get_buffer_size(nullptr, out_channel, int buffer_size = av_samples_get_buffer_size(nullptr, out_channel,
filterFrame->nb_samples, out_sample_fmt, 1); filterFrame->nb_samples, out_sample_fmt, 1);
LOGI(AUDIO_TAG, "buffer_size=%d", buffer_size);
av_frame_unref(inputFrame); av_frame_unref(inputFrame);
av_frame_unref(filterFrame); av_frame_unref(filterFrame);
av_packet_unref(packet); av_packet_unref(packet);
@ -203,6 +214,14 @@ uint8_t *FFAudioPlayer::getDecodeFrame() const {
return out_buffer; return out_buffer;
} }
void FFAudioPlayer::setFilterAgain(bool again) {
filterAgain = again;
}
void FFAudioPlayer::setFilterDesc(const char *filterDescription) {
filterDesc = filterDescription;
}
void FFAudioPlayer::close() { void FFAudioPlayer::close() {
if (formatContext) { if (formatContext) {
avformat_close_input(&formatContext); avformat_close_input(&formatContext);

@ -37,6 +37,9 @@ private:
AVFrame *filterFrame; AVFrame *filterFrame;
uint8_t *out_buffer; uint8_t *out_buffer;
bool filterAgain;
const char *filterDesc;
AVFilterGraph *audioFilterGraph; AVFilterGraph *audioFilterGraph;
AVFilterContext *audioSrcContext; AVFilterContext *audioSrcContext;
AVFilterContext *audioSinkContext; AVFilterContext *audioSinkContext;
@ -52,6 +55,10 @@ public:
uint8_t *getDecodeFrame() const; uint8_t *getDecodeFrame() const;
void setFilterAgain(bool again);
void setFilterDesc(const char *filterDescription);
void close(); void close();
}; };
#endif //LEARNINGMEDIA_FF_AUDIO_PLAYER_H #endif //LEARNINGMEDIA_FF_AUDIO_PLAYER_H

Loading…
Cancel
Save