【问题标题】:How to build + include FFMPEG into an existing Android project如何构建 + 将 FFMPEG 包含到现有的 Android 项目中
【发布时间】:2012-12-10 09:59:17
【问题描述】:

我发现了多个有关 FFMPEG 的问题和教程,但我似乎并不了解其中的大部分。我读过的所有指南都漏掉了很大的空白并且不倾向于解释事情。

我有一个现有的 Android 应用,它使用名为 AAC 解码器的第三方库流式传输音频。由于各种原因,我需要切换到使用 FFMPEG,但不知道如何。我已经设法按照指南构建 FFMPEG,但是我不明白我应该如何处理输出。

我的应用只需要从远程 URL 流式传输音频。流可以采用多种格式。

如果有人可以将我链接到一些全面、详细的指南,或者为我提供说明,那就太好了。

谢谢。

【问题讨论】:

标签: java android ffmpeg audio-streaming


【解决方案1】:

我创建了构建 FFmpeg 的脚本,请在此处查看我的答案:

arm-linux-androideabi-gcc is unable to create an executable - compile ffmpeg for android armeabi devices

你已经编译了 FFmpeg,在你的项目的根目录中创建一个“jni”文件夹。在 jni 文件夹中创建包含以下内容的 Android.mk:

include $(call all-subdir-makefiles)

然后使用这些内容创建 Application.mk:

APP_ABI := armeabi armeabi-v7a x86

接下来,在 jni 文件夹中创建以下文件夹结构:

ffmpeg/ffmpeg/

在第一个 ffmpeg 文件夹中创建另一个 Android.mk:

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)

最后,将构建文件夹的内容(从构建脚本中)移动到 /jni/ffmpeg/ffmpeg/

从项目根目录运行:

ndk-build clean

然后运行:

ndk-build 

如果你觉得懒惰,你可以简单地从我的项目中下载 jni 文件夹并删除“元数据”和“播放器”文件夹:

http://svn.code.sf.net/p/servestream/code/trunk/jni/

如果您有任何其他问题,请告诉我。

【讨论】:

  • 谢谢。我将能够建立图书馆,但我不明白如何从那里着手,你有这方面的任何指南吗?
  • 感谢您的编辑,我正在尝试使用您的构建脚本,但在最后,就在退出消息之前,我收到错误 i686-linux-android-gcc is unable to create an executable file. C compiler test failed.。我正在使用 android-ndk-r8c。有什么想法吗?
  • 不,Mac OSX,我现在在 Ubuntu VM 上尝试。除非有修复?
  • 我确实在 Ubuntu VM 上安装了 Mac OS X NDK,谢谢。之后编译得很好。我可以将 VM 中最终构建的内容复制到 Mac 上项目中的 JNI 文件夹,然后从那里继续吗?谢谢
  • @WilliamSeemann 。嗨,我已经设法正确构建它,但是我现在的问题是,如何使用它来压缩视频。从这里我应该如何继续
【解决方案2】:

您需要交叉编译 FFMPEG 以获得 android 支持。在项目中创建jni 文件夹并将FFMPEG 文件夹放在jni 中。设置android NDK

这是我用来交叉编译 ffmpeg for android 的 Config.sh 的副本。

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 编码和解码,请使用 libfaaclibfaad。您可以在 libavcodecs api-example.c 文件中找到音频解码示例。您需要创建一个JNI Wrapper Class 来操作编解码器。我在此处发布的该文件的解码示例之一。

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);
}

希望对你有所帮助。

【讨论】:

  • 谢谢,一旦 FFMPEG 库被构建到文件夹中,我该去哪里?我想我明白我必须围绕本机函数创建某种包装器。我在哪里可以找到我需要的功能?这之后我该怎么办?干杯
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 2012-01-18
  • 1970-01-01
  • 1970-01-01
  • 2012-12-03
  • 1970-01-01
  • 2016-08-21
相关资源
最近更新 更多