当前位置: 首页 > news >正文

<网站建设与运营》海南百度总代理

<网站建设与运营》,海南百度总代理,网站建设的网站定位,互联网创业项目名称目录 前言 一、环境 二、创建APP 三. 添加FFmpeg库文件到app中 1. 复制ffmpeg头文件和so库到app中 2. 修改CMakeLists.txt文件内容. 3. 修改ffmpeglib.cpp 文件内容 4. 修改NativeLib.kt 文件添加方法和加载库 5. 调用 四. 增加解析视频文件信息功能 总结 前言 前面…

目录

前言

一、环境

二、创建APP

三. 添加FFmpeg库文件到app中

1. 复制ffmpeg头文件和so库到app中

2. 修改CMakeLists.txt文件内容.

3. 修改ffmpeglib.cpp 文件内容

4. 修改NativeLib.kt 文件添加方法和加载库

5. 调用

四. 增加解析视频文件信息功能

总结


前言

        前面有一篇记录了windows上👉 编译Android平台使用的FFmpeg库。想知道的同学可以去看一下😄。这一篇记录一下在android app上怎么使用这些库。


一、环境

  1. 安装Android studio, 方法就不介绍了,网上太多安装的方法了。
  2. 安装NDK和cmake,直接使用SDK monitor安装。 看过我的编译ffmpeg库的知道用的ndk 版本是:
    25.1.8937393

cmake版本:3.22.1

二、创建APP

android studio 创建module

创建成功后,目录结构跟下面差不多,只是没有assets和cpp这两个文件夹和NatvieLib文件。后面会说这两个文件夹和文件是干嘛的

 

三. 添加FFmpeg库文件到app中

1. 复制ffmpeg头文件和so库到app中

使用过NDK项目的都知道cpp这个是放CMakeLists.txt和所有的cpp文件的。

cpp这个文件夹下面创建一个ffmpeg文件夹用来放ffmpeg的头文件和so库文件。因为只编译了一个arm64-v8a 架构,所在在lib这个文件夹下面创建一个arm64-v8a用于放so库。目录结构如下图:

2. 修改CMakeLists.txt文件内容.

修改CMakeLists.txt文件内容编译ffmpeglib.cpp文件。

CMakeLists.txt文件内容如下,都添加注释了,不多说了。有不太清楚的可以自己创建一个Native library module,比对一下看看

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("ffmpeglib")#设定ffmpeg的头文件和so库文件到一个变量中
set(FFMPEG_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/../cpp/ffmpeg/include)
set(FFMPEG_LIB_DIR ${CMAKE_SOURCE_DIR}/../cpp/ffmpeg/lib/${ANDROID_ABI})# 输出调试信息,用于查看路径是否正确
message(STATUS "FFMPEG_INCLUDE_DIR: ${FFMPEG_INCLUDE_DIR}")
message(STATUS "FFMPEG_LIB_DIR: ${FFMPEG_LIB_DIR}")# 检查库文件是否存在
file(GLOB FFMPEG_LIB_FILES "${FFMPEG_LIB_DIR}/*.so")
if(NOT FFMPEG_LIB_FILES)message(FATAL_ERROR "No FFmpeg library files found in ${FFMPEG_LIB_DIR}. Please check the paths and ensure the libraries exist.")
endif()# 包含FFmpeg头文件,只有包含头文件后,在cpp中才能正确引用头文件
include_directories(${FFMPEG_INCLUDE_DIR})# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED# List C/C++ source files with relative paths to this CMakeLists.txt.ffmpeglib.cpp)# 显式指定库文件路径
set(avformat_LIBRARY ${FFMPEG_LIB_DIR}/libavformat.so)
set(avcodec_LIBRARY ${FFMPEG_LIB_DIR}/libavcodec.so)
set(avutil_LIBRARY ${FFMPEG_LIB_DIR}/libavutil.so)
set(swresample_LIBRARY ${FFMPEG_LIB_DIR}/libswresample.so)
set(swscale_LIBRARY ${FFMPEG_LIB_DIR}/libswscale.so)
set(avdevice_LIBRARY ${FFMPEG_LIB_DIR}/libavdevice.so)
set(avfilter_LIBRARY ${FFMPEG_LIB_DIR}/libavfilter.so)# 检测so库文件,输出找到的库文件路径, c++引用so库是不用带lib前缀和.so扩展名的
foreach (LIB avformat avcodec avutil swresample swscale avdevice avfilter)if(EXISTS ${${LIB}_LIBRARY})message(STATUS "${LIB}_LIBRARY: ${${LIB}_LIBRARY}")else()message(FATAL_ERROR "${LIB}_LIBRARY not found at ${${LIB}_LIBRARY}. Please check the paths and ensure the libraries exist.")endif()
endforeach()#链接库文件
target_link_libraries(${CMAKE_PROJECT_NAME}${avutil_LIBRARY}${swresample_LIBRARY}${swscale_LIBRARY}${avcodec_LIBRARY}${avdevice_LIBRARY}${avfilter_LIBRARY}${avformat_LIBRARY}# List libraries link to the target libraryc++_sharedandroidlog)

3. 修改ffmpeglib.cpp 文件内容

添加一个initFfmpeg 方法用来初始化ffmpeg

extern "C" JNIEXPORT void JNICALL
Java_com_bob_ffmpegdemo_NativeLib_initFfmpeg(JNIEnv *env, jobject /* this */) {// 初始化 FFmpegavformat_network_init();// 打印 FFmpeg 版本信息到日志const char *version = avformat_configuration();LOGD("FFmpeg version: %s", version);
}

4. 修改NativeLib.kt 文件添加方法和加载库

package com.bob.ffmpegdemoclass NativeLib {/*** A native method that is implemented by the 'ffmpglib' native library,* which is packaged with this application.*/external fun stringFromJNI(): Stringexternal fun initFfmpeg()companion object {// Used to load the 'ffmpeglib' library on application startup.init {System.loadLibrary("ffmpeglib")}}
}

5. 调用

可以在Activity文件中直接调用NativeLab这个类中和方法

    override fun onResume() {super.onResume()testFfmpeg()}private fun testFfmpeg() {val nativeLib = NativeLib()Log.d(TAG, "-------- ${nativeLib.stringFromJNI()}")nativeLib.initFfmpeg()}

直接运行app, 成功会输出下面的内容

四. 增加解析视频文件信息功能

通过前面三节内容后,ffmpeg的库就添加到app中了,但是只是输出了ffmpeg 编译的信息。不知道ffmpeg的功能是否能用。这节增加解析视频文件的功能

  •  直接在ffmpeglib.cpp文件中添加testOpenVideo方法解析视频
extern "C" JNIEXPORT jstring JNICALL
Java_com_bob_ffmpegdemo_NativeLib_testOpenVideo(JNIEnv *env, jobject /* this */, jstring filePath) {const char *path = env->GetStringUTFChars(filePath, NULL);// 添加 'file://' 前缀以确保正确解析路径std::string full_path = "file://" + std::string(path);LOGD("Attempting to open video file: %s", full_path.c_str());AVFormatContext *pFormatCtx = nullptr;int ret = avformat_open_input(&pFormatCtx, full_path.c_str(), NULL, NULL);if (ret < 0) {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, sizeof(errbuf));LOGE("Failed to open video file: %s", errbuf);env->ReleaseStringUTFChars(filePath, path);return env->NewStringUTF("Failed to open video file.");}if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {LOGE("Failed to retrieve stream information.");avformat_close_input(&pFormatCtx);env->ReleaseStringUTFChars(filePath, path);return env->NewStringUTF("Failed to retrieve stream information.");}// 使用正确的函数名 av_dump_formatav_dump_format(pFormatCtx, 0, full_path.c_str(), 0); // 打印格式信息到标准输出// 计算持续时间和比特率int64_t duration = pFormatCtx->duration != AV_NOPTS_VALUE ?av_rescale_q(pFormatCtx->duration, AV_TIME_BASE_Q, {1, 1000}) : -1; // 转换为毫秒int64_t bitrate = pFormatCtx->bit_rate / 1000;// 解析流信息并处理无音频流的情况bool hasAudioStream = false;for (unsigned int i = 0; i < pFormatCtx->nb_streams; ++i) {AVStream *stream = pFormatCtx->streams[i];AVCodecParameters *codecpar = stream->codecpar;if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {LOGD("Video Stream: Codec %s, Resolution %dx%d",avcodec_get_name(codecpar->codec_id),codecpar->width, codecpar->height);} else if (codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {hasAudioStream = true;// 如果 channel_layout 存在,则使用它;否则提供一个默认值int channels = 2; // 默认立体声音频#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 9, 100)if (codecpar->channel_layout) {channels = av_get_channel_layout_nb_channels(codecpar->channel_layout);}#endifLOGD("Audio Stream: Codec %s, Sample Rate %d Hz, Channels %d",avcodec_get_name(codecpar->codec_id),codecpar->sample_rate,channels);}}if (!hasAudioStream) {LOGD("No audio streams found in the video file.");}char info[1024];snprintf(info, sizeof(info), "Duration: %lld ms, Bitrate: %lld kbps",static_cast<long long>(duration),static_cast<long long>(bitrate));avformat_close_input(&pFormatCtx);env->ReleaseStringUTFChars(filePath, path);return env->NewStringUTF(info);
}

因为使用的是我自己录制的mp4文件,没有声音的。所以添加了hasAudioStream的判断

  •  修改NativeLib.kt 文件

增加: 

external fun testOpenVideo(path:String): String
  •  方法调用
        val outputDir = getExternalFilesDir(null)val outputFile = File(outputDir, FILENAME)if (!outputFile.exists()) {Log.e(TAG, "File does not exist at path: ${outputFile.absolutePath}")return} else if (!outputFile.canRead()) {Log.e(TAG, "File is not readable at path: ${outputFile.absolutePath}")return}val result = nativeLib.testOpenVideo(outputFile.absolutePath)Log.d(TAG, "-------- $result")

运行成功后

 


上面贴的CMakeLists.txt的内容已经是完整的。下面贴一下ffmpeglib.cpp, NativeLib.kt 和 MainActivity.kt 完整代码。

ffmpeglib.cpp

#include <jni.h>
#include <string>
#include <android/log.h>extern "C" {
#include "ffmpeg/include/libavformat/avformat.h"
}#define LOG_TAG "NativeLib"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)extern "C" JNIEXPORT jstring JNICALL
Java_com_bob_ffmpegdemo_NativeLib_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from FFmpeg";return env->NewStringUTF(hello.c_str());
}extern "C" JNIEXPORT void JNICALL
Java_com_bob_ffmpegdemo_NativeLib_initFfmpeg(JNIEnv *env, jobject /* this */) {// 初始化 FFmpegavformat_network_init();// 打印 FFmpeg 版本信息到日志const char *version = avformat_configuration();LOGD("FFmpeg version: %s", version);
}extern "C" JNIEXPORT jstring JNICALL
Java_com_bob_ffmpegdemo_NativeLib_testOpenVideo(JNIEnv *env, jobject /* this */, jstring filePath) {const char *path = env->GetStringUTFChars(filePath, NULL);// 添加 'file://' 前缀以确保正确解析路径std::string full_path = "file://" + std::string(path);LOGD("Attempting to open video file: %s", full_path.c_str());AVFormatContext *pFormatCtx = nullptr;int ret = avformat_open_input(&pFormatCtx, full_path.c_str(), NULL, NULL);if (ret < 0) {char errbuf[AV_ERROR_MAX_STRING_SIZE];av_strerror(ret, errbuf, sizeof(errbuf));LOGE("Failed to open video file: %s", errbuf);env->ReleaseStringUTFChars(filePath, path);return env->NewStringUTF("Failed to open video file.");}if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {LOGE("Failed to retrieve stream information.");avformat_close_input(&pFormatCtx);env->ReleaseStringUTFChars(filePath, path);return env->NewStringUTF("Failed to retrieve stream information.");}// 使用正确的函数名 av_dump_formatav_dump_format(pFormatCtx, 0, full_path.c_str(), 0); // 打印格式信息到标准输出// 计算持续时间和比特率int64_t duration = pFormatCtx->duration != AV_NOPTS_VALUE ?av_rescale_q(pFormatCtx->duration, AV_TIME_BASE_Q, {1, 1000}) : -1; // 转换为毫秒int64_t bitrate = pFormatCtx->bit_rate / 1000;// 解析流信息并处理无音频流的情况bool hasAudioStream = false;for (unsigned int i = 0; i < pFormatCtx->nb_streams; ++i) {AVStream *stream = pFormatCtx->streams[i];AVCodecParameters *codecpar = stream->codecpar;if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {LOGD("Video Stream: Codec %s, Resolution %dx%d",avcodec_get_name(codecpar->codec_id),codecpar->width, codecpar->height);} else if (codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {hasAudioStream = true;// 如果 channel_layout 存在,则使用它;否则提供一个默认值int channels = 2; // 默认立体声音频#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 9, 100)if (codecpar->channel_layout) {channels = av_get_channel_layout_nb_channels(codecpar->channel_layout);}#endifLOGD("Audio Stream: Codec %s, Sample Rate %d Hz, Channels %d",avcodec_get_name(codecpar->codec_id),codecpar->sample_rate,channels);}}if (!hasAudioStream) {LOGD("No audio streams found in the video file.");}char info[1024];snprintf(info, sizeof(info), "Duration: %lld ms, Bitrate: %lld kbps",static_cast<long long>(duration),static_cast<long long>(bitrate));avformat_close_input(&pFormatCtx);env->ReleaseStringUTFChars(filePath, path);return env->NewStringUTF(info);
}

NativeLib.kt

package com.bob.ffmpegdemoclass NativeLib {/*** A native method that is implemented by the 'ffmpglib' native library,* which is packaged with this application.*/external fun stringFromJNI(): Stringexternal fun initFfmpeg()external fun testOpenVideo(path:String): Stringcompanion object {// Used to load the 'ffmpeglib' library on application startup.init {System.loadLibrary("ffmpeglib")}}
}

 MainActivity.kt

package com.bob.ffmpegdemoimport android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.bob.ffmpegdemo.databinding.ActivityMainBinding
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStreamclass MainActivity : AppCompatActivity() {companion object {const val FILENAME = "abc.mp4"const val TAG = "TAG"}private val binding: ActivityMainBinding by lazy {ActivityMainBinding.inflate(layoutInflater)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)enableEdgeToEdge()setContentView(binding.root)ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)insets}copyAssetToFile()}private fun copyAssetToFile() {val dir = getExternalFilesDir(null)// Step 1: Create a file object in that directoryval outFile = File(dir, FILENAME)// Step 2: Copy the asset file to the external files directorytry {val `in`: InputStream = assets.open(FILENAME)val out: OutputStream = FileOutputStream(outFile)val buffer = ByteArray(1024)var read: Intwhile ((`in`.read(buffer).also { read = it }) != -1) {out.write(buffer, 0, read)}`in`.close()out.flush()out.close()Log.d(TAG, "Successfully copied $FILENAME to external files directory.")} catch (e: IOException) {Log.e(TAG, "Failed to copy asset file: " + e.message)}}override fun onResume() {super.onResume()testFfmpeg()}private fun testFfmpeg() {val nativeLib = NativeLib()Log.d(TAG, "-------- ${nativeLib.stringFromJNI()}")nativeLib.initFfmpeg()val outputDir = getExternalFilesDir(null)val outputFile = File(outputDir, FILENAME)if (!outputFile.exists()) {Log.e(TAG, "File does not exist at path: ${outputFile.absolutePath}")return} else if (!outputFile.canRead()) {Log.e(TAG, "File is not readable at path: ${outputFile.absolutePath}")return}val result = nativeLib.testOpenVideo(outputFile.absolutePath)Log.d(TAG, "-------- $result")}
}

总结

以上就是今天要讲的内容。

http://www.hkea.cn/news/276721/

相关文章:

  • wordpress安装到网站吗泰安seo
  • 长春网站开发培训价格google play三件套
  • 做生存分析的网站有哪些国外新闻最新消息
  • 济南网站优化收费百度互联网营销
  • bootstrap响应网站模板下载发帖推广百度首页
  • 动态网站上的查询怎么做新媒体运营培训学校
  • 网站开发人员必备技能百度优化推广
  • 花都 网站建设百度推广怎么添加关键词
  • 开发公司成本部职责岗位职责和流程苏州网站建设优化
  • 湛江网站制作系统seo排名需要多少钱
  • 城乡现代社区建设seo关键词推广案例
  • 旅游网站开发外文文献关键洞察力
  • 大学生asp网站开发的实训周长沙百度快速优化
  • 黑龙江省建设网站百度投流运营
  • 网站关键词太多好不好兰州seo整站优化服务商
  • 义乌网站设计网店推广策划方案
  • 无锡网站优化工作室网站关键词排名优化推广软件
  • 长沙做网站的公司亚马逊seo什么意思
  • 仪征建设银行官方网站怎么优化一个网站
  • 那个网站可以查询美做空基金宁波网站推广平台效果好
  • 杨凌企业网站建设天津seo优化
  • 建设网站的工具免费b站在线观看人数在哪儿
  • 毕业设计餐饮网站建设国内前10电商代运营公司
  • 日本b2b网站市场调研的步骤
  • 强企网做网站网店推广有哪些
  • 博物馆网站建设策划书公司如何在百度宣传
  • 做cpa广告网站教程百度sem推广具体做什么
  • 免费网站建站WWW222国际军事最新消息今天
  • 做网站软件miscrosoft云服务器
  • 如何做盗版小说网站最经典的营销案例