Java 如何构建&x2B;将FFMPEG包含到现有的Android项目中
我已经找到了许多关于FFMPEG的问题和教程,但我似乎不理解其中的大部分。我读过的所有指南都忽略了较大的差距,并且不倾向于解释事情 我有一个现有的Android应用程序,它使用一个叫做AAC解码器的第三方库来传输音频。出于各种原因,我需要切换到使用FFMPEG,但不知道如何使用。我已经设法按照指南来构建FFMPEG,但是我不明白我应该如何处理输出 我的应用只需要从远程URL传输音频。流可以有多种格式 如果有人能把我和一些全面、详细的指南联系起来,或者给我提供指导,那就太好了Java 如何构建&x2B;将FFMPEG包含到现有的Android项目中,java,android,ffmpeg,audio-streaming,Java,Android,Ffmpeg,Audio Streaming,我已经找到了许多关于FFMPEG的问题和教程,但我似乎不理解其中的大部分。我读过的所有指南都忽略了较大的差距,并且不倾向于解释事情 我有一个现有的Android应用程序,它使用一个叫做AAC解码器的第三方库来传输音频。出于各种原因,我需要切换到使用FFMPEG,但不知道如何使用。我已经设法按照指南来构建FFMPEG,但是我不明白我应该如何处理输出 我的应用只需要从远程URL传输音频。流可以有多种格式 如果有人能把我和一些全面、详细的指南联系起来,或者给我提供指导,那就太好了 谢谢。您需要交叉编译
谢谢。您需要交叉编译FFMPEG以支持android。在项目中创建
jni
文件夹,并将FFMPEG
文件夹放入jni中。安装程序android NDK
这里有一个Config.sh的副本,我用它交叉编译android的ffmpeg
Config.sh
#!/bin/sh
PLATFORM=/home/nishant/Desktop/android/android-ndk-r5b/platforms/android-8/arch-arm
PREBUILT=/home/nishant/Desktop/android/android-ndk-r5b/toolchains/arm-eabi-4.4.0/prebuilt/linux-x86
LIBX264=/home/nishant/Desktop/android/workspace/DemoProject/jni/x264
LIB=/home/nishant/Desktop/android/workspace/DemoProject/jni
EXTRA_LIBS="-lgcc -lm -ldl -lz -lc"
#EXTRA_EXE_LDFLAGS="$PLATFORM/usr/lib/crtbegin_dynamic.o $PLATFORM/usr/lib/crtend_android.o"
./configure --target-os=linux \
--arch=arm \
--enable-version3 \
--enable-gpl \
--enable-nonfree \
--disable-stripping \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffserver \
--disable-ffprobe \
--enable-encoders \
--enable-libfaac \
--disable-muxers \
--disable-devices \
--disable-protocols \
--enable-protocol=file \
--enable-avfilter \
--disable-network \
--disable-mpegaudio-hp \
--disable-avdevice \
--enable-cross-compile \
--cc=$PREBUILT/bin/arm-eabi-gcc \
--nm=$PREBUILT/bin/arm-eabi-nm \
--prefix=/home/nishant/Desktop/android/workspace/DemoProject/jni \
--cross-prefix=$PREBUILT/bin/arm-eabi- \
--enable-postproc \
--extra-libs="$EXTRA_LIBS" \
--extra-cflags="-I$PLATFORM/usr/include/ -I$LIB/include/ -I/home/admin1/x264 -std=gnu99 -fPIC -DANDROID -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -DANDROID -Wa,--noexecstack -MMD -MP" \
--disable-asm \
--enable-neon \
--enable-armv5te \
--enable-static \
--disable-shared \
--extra-ldflags="-Wl,-rpath-link=$LIB/lib -L$LIB/lib -nostdlib -Bdynamic -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,nocopyreloc -Wl,-soname,/system/lib/libz.so -Wl,-rpath-link=$PLATFORM/usr/lib,-dynamic-linker=/system/bin/linker -L/usr/lib -L$PLATFORM/usr/lib -nostdlib $PLATFORM/usr/lib/crtbegin_dynamic.o $PLATFORM/usr/lib/crtend_android.o"
您可以使用此配置文件交叉编译ffmpeg,并对其进行一些修改
使用ndk build
命令编译config.sh
编辑:
FFMPEG与所有音频编码器和解码器捆绑在一起。对于AAC编码和解码,使用libfaac
和libfaad
。您可以在libavcodecs
api example.c
文件中找到音频解码示例。您需要创建一个JNI包装类
来操作编解码器。我在这里发布的文件中的一个解码示例
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int out_size, len;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
av_init_packet(&avpkt);
printf("Audio decoding\n");
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(CODEC_ID_MP2);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c= avcodec_alloc_context();
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(c);
exit(1);
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
exit(1);
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
fwrite(outbuf, 1, out_size, outfile);
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(outfile);
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
}
静态无效音频解码示例(常量字符*输出文件名,常量字符*文件名)
{
AVCodec*编解码器;
AVCodecContext*c=NULL;
int out_大小,len;
文件*f,*outfile;
uint8_t*f;
uint8\u t inbuf[音频inbuf\u大小+FF\u输入缓冲区\u填充大小];
avpkt;
av_init_数据包(&avpkt);
printf(“音频解码”);
/*查找mpeg音频解码器*/
codec=avcodec\u find\u解码器(codec\u ID\u MP2);
如果(!编解码器){
fprintf(stderr,“找不到编解码器”);
出口(1);
}
c=avcodec_alloc_context();
/*打开它*/
如果(avcodec_打开(c,codec)<0){
fprintf(stderr,“无法打开编解码器”\n);
出口(1);
}
exputf=malloc(AVCODEC\u MAX\u AUDIO\u FRAME\u SIZE);
f=fopen(文件名,“rb”);
如果(!f){
fprintf(stderr,“无法打开%s\n”,文件名);
出口(1);
}
outfile=fopen(outfilename,“wb”);
如果(!outfile){
无AVU(c);
出口(1);
}
/*解码到eof*/
avpkt.data=inbuf;
avpkt.size=fread(inbuf,1,AUDIO_inbuf_size,f);
而(avpkt.size>0){
out_size=AVCODEC_MAX_AUDIO_FRAME_size;
len=avcodec\U decode\U AUDIO 3(c,(短*)突发、大小和avpkt);
if(len<0){
fprintf(stderr,“解码时出错\n”);
出口(1);
}
如果(输出大小>0){
/*如果一帧已解码,则将其输出*/
fwrite(突出,1,超出尺寸,超出文件);
}
avpkt.size-=len;
avpkt.data+=len;
if(avpkt.size<音频\重新填充\阈值){
/*重新填充输入缓冲区,以避免尝试解码
*不完整的框架。除此之外,还可以使用
*解析器,或通过
*libav格式*/
memmove(inbuf,avpkt.data,avpkt.size);
avpkt.data=inbuf;
len=fread(avpkt.data+avpkt.size,1,
音频尺寸-avpkt.SIZE,f);
如果(len>0)
avpkt.size+=len;
}
}
fclose(输出文件);
fclose(f);
免费(免费);
avcodec_close(c);
无AVU(c);
}
希望它能帮助您。您需要交叉编译FFMPEG以支持android。在项目中创建
jni
文件夹,并将FFMPEG
文件夹放入jni中。安装程序android NDK
这里有一个Config.sh的副本,我用它交叉编译android的ffmpeg
Config.sh
#!/bin/sh
PLATFORM=/home/nishant/Desktop/android/android-ndk-r5b/platforms/android-8/arch-arm
PREBUILT=/home/nishant/Desktop/android/android-ndk-r5b/toolchains/arm-eabi-4.4.0/prebuilt/linux-x86
LIBX264=/home/nishant/Desktop/android/workspace/DemoProject/jni/x264
LIB=/home/nishant/Desktop/android/workspace/DemoProject/jni
EXTRA_LIBS="-lgcc -lm -ldl -lz -lc"
#EXTRA_EXE_LDFLAGS="$PLATFORM/usr/lib/crtbegin_dynamic.o $PLATFORM/usr/lib/crtend_android.o"
./configure --target-os=linux \
--arch=arm \
--enable-version3 \
--enable-gpl \
--enable-nonfree \
--disable-stripping \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffserver \
--disable-ffprobe \
--enable-encoders \
--enable-libfaac \
--disable-muxers \
--disable-devices \
--disable-protocols \
--enable-protocol=file \
--enable-avfilter \
--disable-network \
--disable-mpegaudio-hp \
--disable-avdevice \
--enable-cross-compile \
--cc=$PREBUILT/bin/arm-eabi-gcc \
--nm=$PREBUILT/bin/arm-eabi-nm \
--prefix=/home/nishant/Desktop/android/workspace/DemoProject/jni \
--cross-prefix=$PREBUILT/bin/arm-eabi- \
--enable-postproc \
--extra-libs="$EXTRA_LIBS" \
--extra-cflags="-I$PLATFORM/usr/include/ -I$LIB/include/ -I/home/admin1/x264 -std=gnu99 -fPIC -DANDROID -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -DANDROID -Wa,--noexecstack -MMD -MP" \
--disable-asm \
--enable-neon \
--enable-armv5te \
--enable-static \
--disable-shared \
--extra-ldflags="-Wl,-rpath-link=$LIB/lib -L$LIB/lib -nostdlib -Bdynamic -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,nocopyreloc -Wl,-soname,/system/lib/libz.so -Wl,-rpath-link=$PLATFORM/usr/lib,-dynamic-linker=/system/bin/linker -L/usr/lib -L$PLATFORM/usr/lib -nostdlib $PLATFORM/usr/lib/crtbegin_dynamic.o $PLATFORM/usr/lib/crtend_android.o"
您可以使用此配置文件交叉编译ffmpeg,并对其进行一些修改
使用ndk build
命令编译config.sh
编辑:
FFMPEG与所有音频编码器和解码器捆绑在一起。对于AAC编码和解码,使用libfaac
和libfaad
。您可以在libavcodecs
api example.c
文件中找到音频解码示例。您需要创建一个JNI包装类
来操作编解码器。我在这里发布的文件中的一个解码示例
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int out_size, len;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
av_init_packet(&avpkt);
printf("Audio decoding\n");
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(CODEC_ID_MP2);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c= avcodec_alloc_context();
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(c);
exit(1);
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
exit(1);
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
fwrite(outbuf, 1, out_size, outfile);
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(outfile);
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
}
静态无效音频解码示例(常量字符*输出文件名,常量字符*文件名)
{
AVCodec*编解码器;
AVCodecContext*c=NULL;
int out_大小,len;
文件*f,*outfile;
uint8_t*f;
uint8\u t inbuf[音频inbuf\u大小+FF\u输入缓冲区\u填充大小];
avpkt;
av_init_数据包(&avpkt);
printf(“音频解码”);
/*查找mpeg音频解码器*/
codec=avcodec\u find\u解码器(codec\u ID\u MP2);
如果(!编解码器){
fprintf(stderr,“找不到编解码器”);
出口(1);
}
c=avcodec_alloc_context();
/*打开它*/
如果(avcodec_打开(c,codec)<0){
fprintf(stderr,“无法打开编解码器”\n);
出口(1);
}
exputf=malloc(AVCODEC\u MAX\u AUDIO\u FRAME\u SIZE);
f=fopen(文件名,“rb”);
如果(!f){
fprintf(stderr,“无法打开%s\n”,文件名);
出口(1);
}
outfile=fopen(outfilename,“wb”);
如果(!outfile){
无AVU(c);
出口(1);
}
/*解码到eof*/
avpkt.data=inbuf;
avpkt.size=fread(inbuf,1,AUDIO_inbuf_size,f);
而(avpkt.size>0){
out_size=AVCODEC_MAX_AUDIO_FRAME_size;
len=avcodec\U decode\U AUDIO 3(c,(短*)突发、大小和avpkt);
if(len<0){
fprintf(s)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libavcodec
LOCAL_SRC_FILES := ffmpeg/$(TARGET_ARCH_ABI)/lib/$(LOCAL_MODULE).so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/$(TARGET_ARCH_ABI)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libavformat
LOCAL_SRC_FILES := ffmpeg/$(TARGET_ARCH_ABI)/lib/$(LOCAL_MODULE).so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/$(TARGET_ARCH_ABI)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libavutil
LOCAL_SRC_FILES := ffmpeg/$(TARGET_ARCH_ABI)/lib/$(LOCAL_MODULE).so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/$(TARGET_ARCH_ABI)/include
include $(PREBUILT_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
ndk-build clean
ndk-build