返回

探索 Linux 下 ffmpeg 的交叉编译之旅,助力 Android 平台绽放异彩

Android

Linux 下编译 ffmpeg,一探究竟

  1. 安装依赖库

    sudo apt-get update
    sudo apt-get install build-essential autoconf automake libtool libx264-dev libx265-dev libass-dev libfdk-aac-dev libmp3lame-dev libopus-dev
    
  2. 下载 ffmpeg 源代码

    wget http://ffmpeg.org/releases/ffmpeg-5.0.1.tar.bz2
    tar xjf ffmpeg-5.0.1.tar.bz2
    cd ffmpeg-5.0.1
    
  3. 配置并编译

    ./configure --prefix=/usr/local/ffmpeg --enable-shared --enable-gpl --enable-libmp3lame --enable-libopus --enable-libx264 --enable-libx265 --enable-nonfree
    make
    make install
    
  4. 验证编译结果

    ffmpeg -version
    

    输出应类似于:

    ffmpeg version 5.0.1 Copyright (c) 2000-2022 the FFmpeg developers
    

Android 平台上的 ffmpeg,锦上添花

  1. 下载 Android NDK

    wget https://dl.google.com/android/repository/android-ndk-r23c-linux-x86_64.zip
    unzip android-ndk-r23c-linux-x86_64.zip
    
  2. 交叉编译 ffmpeg

    cd ffmpeg-5.0.1
    ./configure --target-os=android --prefix=/usr/local/ffmpeg-android --enable-cross-compile --enable-shared --enable-gpl --enable-libmp3lame --enable-libopus --enable-libx264 --enable-libx265 --enable-nonfree --cross-prefix=arm-linux-androideabi- --arch=arm --cpu=cortex-a8 --sysroot=$ANDROID_NDK/platforms/android-21/arch-arm
    make
    make install
    
  3. 将 ffmpeg 移植到 Android 项目

    1. 复制 ffmpeg-android/include 目录下的头文件到 Android 项目的 include 目录下。
    2. 复制 ffmpeg-android/lib 目录下的库文件到 Android 项目的 libs 目录下。
    3. 在 Android 项目的 build.gradle 文件中添加如下内容:
      ```gradle
      externalNativeBuild {
        ndkBuild {
          path "src/main/jni/Android.mk"
        }
      }
    
    1. 在 Android 项目的 src/main/jni 目录下创建 Android.mk 文件,内容如下:
    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE    := ffmpeg
    LOCAL_SRC_FILES := ffmpeg.c
    LOCAL_LDLIBS    := -llog -landroid
    
    include $(BUILD_SHARED_LIBRARY)
    
    1. 在 Android 项目的 src/main/java 目录下创建 ffmpeg.c 文件,内容如下:
    #include <jni.h>
    #include <ffmpeg/avcodec.h>
    #include <ffmpeg/avformat.h>
    
    JNIEXPORT jint JNICALL Java_com_example_ffmpeg_MainActivity_ffmpeg(JNIEnv *env, jobject obj) {
      av_register_all();
      AVFormatContext *fmt_ctx = NULL;
      AVCodecContext *dec_ctx = NULL;
      AVPacket pkt;
      int ret;
    
      // 打开输入文件
      if (avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL) < 0) {
        return -1;
      }
    
      // 查找解码器
      dec_ctx = avcodec_find_decoder(fmt_ctx->streams[0]->codecpar->codec_id);
      if (!dec_ctx) {
        return -1;
      }
    
      // 打开解码器
      if (avcodec_open2(dec_ctx, NULL, NULL) < 0) {
        return -1;
      }
    
      // 读取数据包并解码
      while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == 0) {
          ret = avcodec_send_packet(dec_ctx, &pkt);
          if (ret < 0) {
            return -1;
          }
    
          while (ret >= 0) {
            AVFrame *frame = av_frame_alloc();
            ret = avcodec_receive_frame(dec_ctx, frame);
            if (ret < 0) {
              av_frame_free(&frame);
              break;
            }
    
            // 对帧进行处理
    
            av_frame_free(&frame);
          }
        }
        av_packet_unref(&pkt);
      }
    
      // 关闭解码器
      avcodec_close(dec_ctx);
    
      // 关闭输入文件
      avformat_close_input(&fmt_ctx);
    
      return 0;
    }
    
    
    
  4. 在 Android 项目中使用 ffmpeg

    import android.os.Bundle;
    import android.app.Activity;
    
    public class MainActivity extends Activity {
      static {
        System.loadLibrary("ffmpeg");
      }
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        ffmpeg();
      }
    
      private native int ffmpeg();
    }
    

现在,你就可以在 Android 项目中使用 ffmpeg 了!

结语

通过这趟 ffmpeg 交叉编译之旅,你不仅掌握了在 Linux 下编译 ffmpeg 的技巧,还学会了如何将其交叉编译并引入 Android 平台。有了 ffmpeg 的助力,你的 Android 应用也能拥有强大的音视频处理能力,为用户带来更加丰富的多媒体体验。