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

平面设计公司起名爱站网seo

平面设计公司起名,爱站网seo,服务周到的上海网站建设公,广州专业建网站公司目录 前言 一、环境 二、创建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/641948/

相关文章:

  • 网站开发方式有哪四种搜索引擎优化课程总结
  • 申请做网站、论坛版主app推广接单
  • 青海网站建设广州seo优化推广
  • 物流公司网站制作模板上海网站关键词排名
  • 广西建设人才网搜索引擎优化的目标
  • 比汉斯设计网站素材图片搜索识图入口
  • php网站架设教程英雄联盟韩国
  • 做毕设好的网站百度客服电话24小时
  • 上海手机网站建设电话咨询seo综合查询系统
  • wordpress 4.6 中文版沈阳seo
  • 文件管理软件天津搜索引擎优化
  • 九亭网站建设全国疫情高峰时间表最新
  • 青岛网站建设公司武汉seo收费
  • mvc网站建设的实验报告怎么做优化
  • 有官网建手机网站千锋教育培训多少钱费用
  • b2c交易模式的网站有哪些百度营销客户端
  • flash 学习网站重庆网站seo多少钱
  • 年终总结ppt模板免费下载网站小红书seo排名规则
  • 自己架设网站口碑营销的产品有哪些
  • 湖北省网站备案最快几天天津百度推广排名优化
  • app在线开发制作平台seo网络优化前景怎么样
  • 商务网站的基本情况网站建设工作总结
  • 山西建设厅网站网络销售怎么聊客户
  • 软装素材网站有哪些seo网络排名优化哪家好
  • 邯郸市做网站建设网络口碑营销案例分析
  • 罗湖网站建设联系电话西安核心关键词排名
  • 如何编写网站电脑清理软件十大排名
  • 怎么给企业制作网站seo关键词排名优化哪好
  • 高仿服装网站建设西安百度关键词推广
  • 网站单页面怎么做的百度seo站长工具