Java 如何构建&x2B;将FFMPEG包含到现有的Android项目中

Java 如何构建&x2B;将FFMPEG包含到现有的Android项目中,java,android,ffmpeg,audio-streaming,Java,Android,Ffmpeg,Audio Streaming,我已经找到了许多关于FFMPEG的问题和教程,但我似乎不理解其中的大部分。我读过的所有指南都忽略了较大的差距,并且不倾向于解释事情 我有一个现有的Android应用程序,它使用一个叫做AAC解码器的第三方库来传输音频。出于各种原因,我需要切换到使用FFMPEG,但不知道如何使用。我已经设法按照指南来构建FFMPEG,但是我不明白我应该如何处理输出 我的应用只需要从远程URL传输音频。流可以有多种格式 如果有人能把我和一些全面、详细的指南联系起来,或者给我提供指导,那就太好了 谢谢。您需要交叉编译

我已经找到了许多关于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