音视频实践学习

  • android全平台编译ffmpeg以及x264与fdk-aac实践
  • ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器
  • android全平台编译ffmpeg合并为单个库实践
  • android-studio使用cmake编译ffmpeg实践
  • android全平台编译ffmpeg视频解码器实践
  • android全平台编译ffmpeg支持命令行实践
  • android全平台编译ffmpeg视频推流实践
  • android平台下音频编码之编译LAME库转码PCM为MP3
  • ubuntu平台下编译vlc-android视频播放器实践
  • 图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别
  • 图解RGB565、RGB555、RGB16、RGB24、RGB32、ARGB32等格式的区别
  • YUV420P、YUV420SP、NV12、NV21和RGB互相转换并存储为JPEG以及PNG图片
  • android全平台编译libyuv库实现YUV和RGB的转换

本例基于 android全平台编译ffmpeg合并为单个库实践 进行的

目录

  • 环境准备
  • 新建cmd工程
  • 修改源文件
  • 运行输出

环境准备

操作系统 ubuntu 16.05

编译准备好libffmpeg库和需要include头文件,我们还需要抽取ffmpeg-3.3.8中的部分头文件和源文件

笔者整理了一个copy_ffmpeg_files.sh脚本

FFMPEG_DIR=ffmpeg-3.3.8mkdir includemkdir include/compatmkdir include/libavcodecmkdir include/libavformatmkdir include/libavutilmkdir include/libavdevicemkdir include/libpostproccp $FFMPEG_DIR/compat/va_copy.h include/compat/va_copy.hcp $FFMPEG_DIR/libavcodec/mathops.h include/libavcodec/mathops.hcp $FFMPEG_DIR/libavdevice/avdevice.h include/libavdevice/avdevice.hcp $FFMPEG_DIR/libavdevice/version.h include/libavdevice/version.hcp $FFMPEG_DIR/libavformat/ffm.h include/libavformat/ffm.hcp $FFMPEG_DIR/libavformat/network.h include/libavformat/network.hcp $FFMPEG_DIR/libavformat/os_support.h include/libavformat/os_support.hcp $FFMPEG_DIR/libavformat/url.h include/libavformat/url.hcp $FFMPEG_DIR/libavutil/libm.h include/libavutil/libm.hcp $FFMPEG_DIR/libavutil/internal.h include/libavutil/internal.hcp $FFMPEG_DIR/libavutil/reverse.h include/libavutil/reverse.hcp $FFMPEG_DIR/libavutil/timer.h include/libavutil/timer.hcp $FFMPEG_DIR/libpostproc/postprocess.h include/libpostproc/postprocess.hcp $FFMPEG_DIR/libpostproc/version.h include/libpostproc/version.h#cppmkdir cppcp $FFMPEG_DIR/cmdutils.c cpp/cmdutils.ccp $FFMPEG_DIR/cmdutils.h cpp/cmdutils.hcp $FFMPEG_DIR/cmdutils_common_opts.h cpp/cmdutils_common_opts.h#cp $FFMPEG_DIR/config.h cpp/config.hcp $FFMPEG_DIR/ffmpeg.h cpp/ffmpeg.hcp $FFMPEG_DIR/ffmpeg.c cpp/ffmpeg_mod.ccp $FFMPEG_DIR/ffmpeg_filter.c cpp/ffmpeg_filter.ccp $FFMPEG_DIR/ffmpeg_opt.c cpp/ffmpeg_opt.c
  • 文件目录结构如下:

将生成之后的include文件夹覆盖到项目中的include目录
本例中即覆盖到ffmpeg-single组件下的libs/armeabi-v7ainclude目录

新建ffmpeg-single-cmd工程

将生成的cpp目录复制到src/main目录下

  • 新建FFmpegCmd类
public class FFmpegCmd {    static {        System.loadLibrary("ffmpeg");        System.loadLibrary("ffmpeg-cmd");    }    public native int exec(int argc, String[] argv);}
  • 新建ffmpeg_cmd.c文件
#include <jni.h>#include <stdio.h>#include <time.h>#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libavfilter/avfilter.h"#include "libavutil/log.h"#ifdef ANDROID#include <android/log.h>#define LOG_TAG    "HelloFFmpeg"#define LOGE(format, ...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, format, ##__VA_ARGS__)#define LOGI(format, ...)  __android_log_print(ANDROID_LOG_INFO,  LOG_TAG, format, ##__VA_ARGS__)#else#define LOGE(format, ...)  printf(LOG_TAG format "\n", ##__VA_ARGS__)#define LOGI(format, ...)  printf(LOG_TAG format "\n", ##__VA_ARGS__)#endifint exec(int argc, char **argv);void custom_log(void *ptr, int level, const char *fmt, va_list vl) {    FILE *fp=fopen("/storage/emulated/0/Android/data/com.onzhou.ffmpeg.cmd/files/av_log.txt""a+");    if(fp){        vfprintf(fp,fmt,vl);        fflush(fp);        fclose(fp);    }}JNIEXPORT jint JNICALL Java_com_onzhou_ffmpeg_cmd_FFmpegCmd_exec        (JNIEnv *env, jobject obj, jint cmdnum, jobjectArray cmdline) {    av_log_set_callback(custom_log);    int argc = cmdnum;    char **argv = (char **) malloc(sizeof(char *) * argc);    int i = 0;    for (i = 0; i < argc; i++) {        jstring string = (*env)->GetObjectArrayElement(env, cmdline, i);        const char *tmp = (*env)->GetStringUTFChars(env, string, 0);        argv[i] = (char *) malloc(sizeof(char) * 1024);        strcpy(argv[i], tmp);    }    exec(argc, argv);    for (i = 0; i < argc; i++) {        free(argv[i]);    }    free(argv);    return 0;}
  • 新建ffmpeg_cmd.h头文件
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_onzhou_ffmpeg_cmd_FFmpegCmd */#ifndef _Included_com_onzhou_ffmpeg_cmd_FFmpegCmd#define _Included_com_onzhou_ffmpeg_cmd_FFmpegCmd#ifdef __cplusplusextern "C" {#endif/* * Class:     com_onzhou_ffmpeg_cmd_FFmpegCmd * Method:    exec * Signature: (I[Ljava/lang/String;)V */JNIEXPORT jint JNICALL Java_com_onzhou_ffmpeg_cmd_FFmpegCmd_exec        (JNIEnv *, jobject, jint, jobjectArray);#ifdef __cplusplus}#endif#endif

build.gradle中的配置不多说了,可以参考之前的实践配置

  • 配置CMakeLists.txt文件
cmake_minimum_required(VERSION 3.4.1)add_library(ffmpeg-cmd           SHARED           src/main/cpp/ffmpeg_cmd.c           src/main/cpp/cmdutils.c           src/main/cpp/ffmpeg_filter.c           src/main/cpp/ffmpeg_opt.c           src/main/cpp/ffmpeg_mod.c)find_library(log-lib            log)#获取上级目录get_filename_component(PARENT_DIR ${CMAKE_SOURCE_DIR} PATH)set(LIBRARY_DIR ${PARENT_DIR}/ffmpeg-single)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")set(CMAKE_VERBOSE_MAKEFILE on)add_library(ffmpeg-single           SHARED           IMPORTED)set_target_properties(ffmpeg-single                    PROPERTIES IMPORTED_LOCATION                    ${LIBRARY_DIR}/libs/${ANDROID_ABI}/libffmpeg.so                    )#头文件include_directories(${LIBRARY_DIR}/libs/${ANDROID_ABI}/include src/main/cpp)target_link_libraries(ffmpeg-cmd ffmpeg-single ${log-lib})

修改源文件

  • 修改cmdutils.c文件
void exit_program(int ret){    if (program_exit)        program_exit(ret);    exit(ret);}

#改为

int exit_program(int ret){    if (program_exit)        program_exit(ret);    //exit(ret);    return ret;}
  • 修改cmdutils.h头文件
void exit_program(int ret) av_noreturn;

#改为

int exit_program(int ret) av_noreturn;
  • 修改ffmpeg_mod.c文件
int main(int argc, char **argv)

#改为

int exec(int argc, char **argv)

return main_return_code;之前加上如下代码:

nb_filtergraphs = 0;progress_avio = NULL;input_streams = NULL;nb_input_streams = 0;input_files = NULL;nb_input_files = 0;output_streams = NULL;nb_output_streams = 0;output_files = NULL;nb_output_files = 0;
  • 测试执行命令行进行转码
public void onCmdClick(View view) {    if (fFmpegCmd == null) {        fFmpegCmd = new FFmpegCmd();    }    btnTransfer.setEnabled(false);    File outputFile = new File(getExternalFilesDir(null)"output.mkv");    if (outputFile.exists()) {        outputFile.delete();    }    Schedulers.newThread().scheduleDirect(new Runnable() {        @Override        public void run() {            String filePath = getExternalFilesDir(null).getAbsolutePath();            String cmdline = String.format("ffmpeg -i %s/input.mp4 %s/output.mkv", filePath, filePath);            String[] argv = cmdline.split(" ");            Integer argc = argv.length;            fFmpegCmd.exec(argc, argv);        }    });}

运行输出

项目地址
https://github.com/byhook/ffmpeg4android

参考雷神:
https://blog.csdn.net/leixiaohua1020/article/details/47056365

更多相关文章

  1. NDK版本与Android固件要求对应表
  2. Android(安卓)平台简介
  3. Android的交叉编译工具
  4. Android(安卓)C/C++开发指南
  5. Visual Studio 跨平台开发实战(4) - Xamarin Android(安卓)基本
  6. Android编译系统分析
  7. 编译Android内核 For nexus 5 以及绕过Android的反调试
  8. android中编译资源文件的相关问题
  9. Android(安卓)Studio报错:Ignoring unknown package filter 'bui

随机推荐

  1. android PhoneGap 的入门例子
  2. Ubuntu下连接Android设备
  3. 开发Android第四步,Android(安卓)NDK 及 a
  4. android 最全的shape属性
  5. android SQLite的使用
  6. View组件之各xml属性
  7. Android环境搭建
  8. Android(安卓)图片侧滑展示RecyclerView
  9. android的TableLayout布局界面元素填满整
  10. Android系列教程之十:Intents and Intent