|
|
@ -25,7 +25,6 @@ extern "C" { |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
#define TAG "AudioPlayer" |
|
|
|
#define TAG "AudioPlayer" |
|
|
|
#define VOLUME_VAL 0.50 |
|
|
|
|
|
|
|
#define SLEEP_TIME (1000 * 16) |
|
|
|
#define SLEEP_TIME (1000 * 16) |
|
|
|
#define MAX_AUDIO_FRAME_SIZE (48000 * 4) |
|
|
|
#define MAX_AUDIO_FRAME_SIZE (48000 * 4) |
|
|
|
|
|
|
|
|
|
|
@ -36,104 +35,6 @@ FrankVisualizer *mVisualizer; |
|
|
|
|
|
|
|
|
|
|
|
void fft_callback(JNIEnv *jniEnv, jobject thiz, jmethodID fft_method, int8_t* arg, int samples); |
|
|
|
void fft_callback(JNIEnv *jniEnv, jobject thiz, jmethodID fft_method, int8_t* arg, int samples); |
|
|
|
|
|
|
|
|
|
|
|
int init_volume_filter(AVFilterGraph **graph, AVFilterContext **src, AVFilterContext **sink, |
|
|
|
|
|
|
|
uint64_t channel_layout, AVSampleFormat inputFormat, int sample_rate) { |
|
|
|
|
|
|
|
AVFilterGraph *filter_graph; |
|
|
|
|
|
|
|
AVFilterContext *buffer_ctx; |
|
|
|
|
|
|
|
const AVFilter *buffer; |
|
|
|
|
|
|
|
AVFilterContext *volume_ctx; |
|
|
|
|
|
|
|
const AVFilter *volume; |
|
|
|
|
|
|
|
AVFilterContext *buffersink_ctx; |
|
|
|
|
|
|
|
const AVFilter *buffersink; |
|
|
|
|
|
|
|
AVDictionary *options_dict = nullptr; |
|
|
|
|
|
|
|
uint8_t ch_layout[64]; |
|
|
|
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create a new filter graph, which will contain all the filters. */ |
|
|
|
|
|
|
|
filter_graph = avfilter_graph_alloc(); |
|
|
|
|
|
|
|
if (!filter_graph) { |
|
|
|
|
|
|
|
LOGE(TAG, "Unable to create filter graph..."); |
|
|
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Create the abuffer filter: feed data into the graph. */ |
|
|
|
|
|
|
|
buffer = avfilter_get_by_name("abuffer"); |
|
|
|
|
|
|
|
if (!buffer) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not find the buffer filter..."); |
|
|
|
|
|
|
|
return AVERROR_FILTER_NOT_FOUND; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
buffer_ctx = avfilter_graph_alloc_filter(filter_graph, buffer, "src"); |
|
|
|
|
|
|
|
if (!buffer_ctx) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not allocate the buffer instance..."); |
|
|
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Set the filter options through the AVOptions API. */ |
|
|
|
|
|
|
|
av_get_channel_layout_string(reinterpret_cast<char *>(ch_layout), sizeof(ch_layout), 0, channel_layout); |
|
|
|
|
|
|
|
av_opt_set (buffer_ctx, "channel_layout", reinterpret_cast<char *>(ch_layout), AV_OPT_SEARCH_CHILDREN); |
|
|
|
|
|
|
|
av_opt_set (buffer_ctx, "sample_fmt", av_get_sample_fmt_name(inputFormat), AV_OPT_SEARCH_CHILDREN); |
|
|
|
|
|
|
|
av_opt_set_q (buffer_ctx, "time_base", (AVRational){ 1, sample_rate }, AV_OPT_SEARCH_CHILDREN); |
|
|
|
|
|
|
|
av_opt_set_int(buffer_ctx, "sample_rate", sample_rate, AV_OPT_SEARCH_CHILDREN); |
|
|
|
|
|
|
|
ret = avfilter_init_str(buffer_ctx, nullptr); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not initialize the buffer filter:%d", ret); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create volume filter. */ |
|
|
|
|
|
|
|
volume = avfilter_get_by_name("volume"); |
|
|
|
|
|
|
|
if (!volume) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not find the volume filter..."); |
|
|
|
|
|
|
|
return AVERROR_FILTER_NOT_FOUND; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
volume_ctx = avfilter_graph_alloc_filter(filter_graph, volume, "volume"); |
|
|
|
|
|
|
|
if (!volume_ctx) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not allocate the volume instance..."); |
|
|
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Passing the options is as key/value pairs in a dictionary. */ |
|
|
|
|
|
|
|
av_dict_set(&options_dict, "volume", AV_STRINGIFY(VOLUME_VAL), 0); |
|
|
|
|
|
|
|
ret = avfilter_init_dict(volume_ctx, &options_dict); |
|
|
|
|
|
|
|
av_dict_free(&options_dict); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not initialize the volume filter:%d", ret); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create the abuffersink filter: get the filtered data from graph. */ |
|
|
|
|
|
|
|
buffersink = avfilter_get_by_name("abuffersink"); |
|
|
|
|
|
|
|
if (!buffersink) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not find the abuffersink filter..."); |
|
|
|
|
|
|
|
return AVERROR_FILTER_NOT_FOUND; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, buffersink, "sink"); |
|
|
|
|
|
|
|
if (!buffersink_ctx) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not allocate the abuffersink instance..."); |
|
|
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ret = avfilter_init_str(buffersink_ctx, nullptr); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
|
|
|
|
LOGE(TAG, "Could not initialize the abuffersink instance:%d", ret); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Connect the filters */ |
|
|
|
|
|
|
|
ret = avfilter_link(buffer_ctx, 0, volume_ctx, 0); |
|
|
|
|
|
|
|
if (ret >= 0) |
|
|
|
|
|
|
|
ret = avfilter_link(volume_ctx, 0, buffersink_ctx, 0); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
|
|
|
|
LOGE(TAG, "Error connecting filters:%d", ret); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Configure the graph. */ |
|
|
|
|
|
|
|
ret = avfilter_graph_config(filter_graph, nullptr); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
|
|
|
|
LOGE(TAG, "Error configuring the filter graph:%d", ret); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*graph = filter_graph; |
|
|
|
|
|
|
|
*src = buffer_ctx; |
|
|
|
|
|
|
|
*sink = buffersink_ctx; |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int init_equalizer_filter(const char *filter_description, AVCodecContext *codecCtx, AVFilterGraph **graph, |
|
|
|
int init_equalizer_filter(const char *filter_description, AVCodecContext *codecCtx, AVFilterGraph **graph, |
|
|
|
AVFilterContext **src, AVFilterContext **sink) { |
|
|
|
AVFilterContext **src, AVFilterContext **sink) { |
|
|
|
int ret = 0; |
|
|
|
int ret = 0; |
|
|
@ -203,7 +104,7 @@ end: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
AUDIO_PLAYER_FUNC(void, play, jstring input_jstr, jstring filter_jstr) { |
|
|
|
AUDIO_PLAYER_FUNC(void, play, jstring input_jstr, jstring filter_jstr) { |
|
|
|
int got_frame = 0, ret = 0; |
|
|
|
int got_frame = 0, ret; |
|
|
|
AVPacket packet; |
|
|
|
AVPacket packet; |
|
|
|
AVFilterGraph *audioFilterGraph; |
|
|
|
AVFilterGraph *audioFilterGraph; |
|
|
|
AVFilterContext *audioSrcContext; |
|
|
|
AVFilterContext *audioSrcContext; |
|
|
@ -273,8 +174,6 @@ AUDIO_PLAYER_FUNC(void, play, jstring input_jstr, jstring filter_jstr) { |
|
|
|
|
|
|
|
|
|
|
|
/* Set up the filter graph. */ |
|
|
|
/* Set up the filter graph. */ |
|
|
|
AVFrame *filter_frame = av_frame_alloc(); |
|
|
|
AVFrame *filter_frame = av_frame_alloc(); |
|
|
|
// ret = init_volume_filter(&audioFilterGraph, &audioSrcContext, &audioSinkContext,
|
|
|
|
|
|
|
|
// in_ch_layout, in_sample_fmt, in_sample_rate);
|
|
|
|
|
|
|
|
ret = init_equalizer_filter(filter_desc, codecCtx, &audioFilterGraph, &audioSrcContext, &audioSinkContext); |
|
|
|
ret = init_equalizer_filter(filter_desc, codecCtx, &audioFilterGraph, &audioSrcContext, &audioSinkContext); |
|
|
|
if (ret < 0) { |
|
|
|
if (ret < 0) { |
|
|
|
LOGE(TAG, "Unable to init filter graph:%d", ret); |
|
|
|
LOGE(TAG, "Unable to init filter graph:%d", ret); |
|
|
@ -317,7 +216,7 @@ AUDIO_PLAYER_FUNC(void, play, jstring input_jstr, jstring filter_jstr) { |
|
|
|
LOGE(TAG, "Error add the frame to the filter graph:%d", ret); |
|
|
|
LOGE(TAG, "Error add the frame to the filter graph:%d", ret); |
|
|
|
} |
|
|
|
} |
|
|
|
/* Get all the filtered output that is available. */ |
|
|
|
/* Get all the filtered output that is available. */ |
|
|
|
while (1) { |
|
|
|
while (true) { |
|
|
|
ret = av_buffersink_get_frame(audioSinkContext, filter_frame); |
|
|
|
ret = av_buffersink_get_frame(audioSinkContext, filter_frame); |
|
|
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) |
|
|
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) |
|
|
|
break; |
|
|
|
break; |
|
|
|