안 드 로 이 드 는 FFmpeg 를 사용 하여 오디 오 혼합 과 조합 절 체 를 실현 합 니 다.
android studio 를 사용 하여 개발 하고 build.gradle 파일 을 설정 합 니 다.
defaultConfig {
......
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk {
abiFilters "armeabi-v7a"
}
}
cmake 파일 경 로 를 지정 합 니 다:
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
jni.srcDirs = []
}
}
FFmpeg 홈 페이지 에서 원본 코드 를 다운로드 하여 ffmpeg.so 동적 라 이브 러 리 로 컴 파일 하고 관련 원본 파일 과 헤더 파일 을 가 져 옵 니 다.그리고 cMakeLists 파일 을 설정 합 니 다:
add_library( # Sets the name of the library.
audio-handle
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/ffmpeg_cmd.c
src/main/cpp/cmdutils.c
src/main/cpp/ffmpeg.c
src/main/cpp/ffmpeg_filter.c
src/main/cpp/ffmpeg_opt.c)
add_library( ffmpeg
SHARED
IMPORTED )
set_target_properties( ffmpeg
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libffmpeg.so )
include_directories(src/main/cpp/include)
find_library( log-lib
log )
target_link_libraries( audio-handle
ffmpeg
${log-lib} )
FFmpeg :
/**
* ffmpeg
* @param handleType handleType
*/
private void doHandleAudio(int handleType){
String[] commandLine = null;
switch (handleType){
case 0://
String transformFile = PATH + File.separator + "transform.aac";
commandLine = FFmpegUtil.transformAudio(srcFile, transformFile);
break;
case 1://
String cutFile = PATH + File.separator + "cut.mp3";
commandLine = FFmpegUtil.cutAudio(srcFile, 10, 15, cutFile);
break;
case 2://
String concatFile = PATH + File.separator + "concat.mp3";
commandLine = FFmpegUtil.concatAudio(srcFile, appendFile, concatFile);
break;
case 3://
String mixFile = PATH + File.separator + "mix.aac";
commandLine = FFmpegUtil.mixAudio(srcFile, appendFile, mixFile);
break;
default:
break;
}
executeFFmpegCmd(commandLine);
}
그 중에서 오디 오 믹스,병합,잘라 내기,코드 를 바 꾸 는 FFmpeg 명령 행 의 조합 은 다음 과 같 습 니 다.
/**
* ffmpeg
* @param srcFile
* @param targetFile ( )
* @return
*/
public static String[] transformAudio(String srcFile, String targetFile){
String transformAudioCmd = "ffmpeg -i %s %s";
transformAudioCmd = String.format(transformAudioCmd, srcFile, targetFile);
return transformAudioCmd.split(" ");//
}
/**
* ffmpeg
* @param srcFile
* @param startTime ( )
* @param duration ( )
* @param targetFile
* @return
*/
@SuppressLint("DefaultLocale")
public static String[] cutAudio(String srcFile, int startTime, int duration, String targetFile){
String cutAudioCmd = "ffmpeg -i %s -ss %d -t %d %s";
cutAudioCmd = String.format(cutAudioCmd, srcFile, startTime, duration, targetFile);
return cutAudioCmd.split(" ");//
}
/**
* ffmpeg
* @param srcFile
* @param appendFile
* @param targetFile
* @return
*/
public static String[] concatAudio(String srcFile, String appendFile, String targetFile){
String concatAudioCmd = "ffmpeg -i concat:%s|%s -acodec copy %s";
concatAudioCmd = String.format(concatAudioCmd, srcFile, appendFile, targetFile);
return concatAudioCmd.split(" ");//
}
/**
* ffmpeg
* @param srcFile
* @param mixFile
* @param targetFile
* @return
*/
public static String[] mixAudio(String srcFile, String mixFile, String targetFile){
String mixAudioCmd = "ffmpeg -i %s -i %s -filter_complex amix=inputs=2:duration=first -strict -2 %s";
mixAudioCmd = String.format(mixAudioCmd, srcFile, mixFile, targetFile);
return mixAudioCmd.split(" ");//
}
FFmpeg 처리 혼 음 공식 은 다음 과 같 습 니 다.그 중에서 sample 1 은 원본 파일 샘플링 율 이 고 sample 2 는 혼합 파일 샘플링 율 입 니 다.혼 음 공식:value=sample 1+sample 2-(sample 1*sample 2/(pow(2,16-1)-1)
하위 스 레 드 를 열 고 native 방법 으로 오디 오 처 리 를 진행 합 니 다:
public static void execute(final String[] commands, final OnHandleListener onHandleListener){
new Thread(new Runnable() {
@Override
public void run() {
if(onHandleListener != null){
onHandleListener.onBegin();
}
// ffmpeg
int result = handle(commands);
if(onHandleListener != null){
onHandleListener.onEnd(result);
}
}
}).start();
}
private native static int handle(String[] commands);
중요 한 native 방법 은 자바 가 들 어 온 문자열 배열 을 2 급 포인터 배열 로 바 꾼 다음 FFmpeg 소스 코드 의 run 방법 을 호출 하 는 것 입 니 다.
JNIEXPORT jint JNICALL Java_com_frank_ffmpeg_FFmpegCmd_handle
(JNIEnv *env, jclass obj, jobjectArray commands){
int argc = (*env)->GetArrayLength(env, commands);
char **argv = (char**)malloc(argc * sizeof(char*));
int i;
int result;
for (i = 0; i < argc; i++) {
jstring jstr = (jstring) (*env)->GetObjectArrayElement(env, commands, i);
char* temp = (char*) (*env)->GetStringUTFChars(env, jstr, 0);
argv[i] = malloc(1024);
strcpy(argv[i], temp);
(*env)->ReleaseStringUTFChars(env, jstr, temp);
}
// ffmpeg
result = run(argc, argv);
//
for (i = 0; i < argc; i++) {
free(argv[i]);
}
free(argv);
return result;
}
FFmpeg 의 run 방법 에 대한 원본 코드 는 다음 과 같 습 니 다.중간 부분 은 생략 되 었 습 니 다.
int run(int argc, char **argv)
{
/**************** ********************/
//
avcodec_register_all();
#if CONFIG_AVDEVICE
avdevice_register_all();
#endif
avfilter_register_all();
av_register_all();
avformat_network_init();
show_banner(argc, argv, options);
term_init();
/**************** ********************/
//
int ret = ffmpeg_parse_options(argc, argv);
if (ret < 0)
exit_program(1);
/**************** ********************/
//
if (transcode() < 0)
exit_program(1);
/**************** ********************/
// : 、
exit_program(received_nb_signals ? 255 : main_return_code);
ffmpeg_cleanup(0);
}
그 중에서 가장 중요 한 것 은 파일 변환 부분 입 니 다.소스 코드 는 다음 과 같 습 니 다.
static int transcode(void)
{
int ret, i;
AVFormatContext *os;
OutputStream *ost;
InputStream *ist;
int64_t timer_start;
int64_t total_packets_written = 0;
//
ret = transcode_init();
if (ret < 0)
goto fail;
if (stdin_interaction) {
av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help
");
}
timer_start = av_gettime_relative();
#if HAVE_PTHREADS
if ((ret = init_input_threads()) < 0)
goto fail;
#endif
//transcode
while (!received_sigterm) {
int64_t cur_time= av_gettime_relative();
// "q" ,
if (stdin_interaction)
if (check_keyboard_interaction(cur_time) < 0)
break;
//
if (!need_output()) {
av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.
");
break;
}
ret = transcode_step();
if (ret < 0 && ret != AVERROR_EOF) {
char errbuf[128];
av_strerror(ret, errbuf, sizeof(errbuf));
av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s
", errbuf);
break;
}
//
print_report(0, timer_start, cur_time);
}
#if HAVE_PTHREADS
free_input_threads();
#endif
// stream, buffer
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
process_input_packet(ist, NULL, 0);
}
}
flush_encoders();
term_exit();
// ,
for (i = 0; i < nb_output_files; i++) {
os = output_files[i]->ctx;
if ((ret = av_write_trailer(os)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s", os->filename, av_err2str(ret));
if (exit_on_error)
exit_program(1);
}
}
//
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (ost->encoding_needed) {
av_freep(&ost->enc_ctx->stats_in);
}
total_packets_written += ost->packets_written;
}
if (!total_packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT)) {
av_log(NULL, AV_LOG_FATAL, "Empty output
");
exit_program(1);
}
//
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (ist->decoding_needed) {
avcodec_close(ist->dec_ctx);
if (ist->hwaccel_uninit)
ist->hwaccel_uninit(ist->dec_ctx);
}
}
//
return ret;
}
자,FFmpeg 를 사용 하여 오디 오 편집,믹스,맞 춤 법 과 코드 소 개 를 마 쳤 습 니 다.만약 여러분 에 게 무슨 문제 나 건의 가 있다 면,교 류 를 환영 합 니 다.소스 코드:링크 주소.도움 이 된다 면 포크 와 스타 를 귀 찮 게 해 주세요.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.