国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
從零開始仿寫一個(gè)抖音App

不知不覺已經(jīng)到了2019年,本系列的文章也更新到了8篇。很慶幸筆者能堅(jiān)持下來,從我司的代碼中學(xué)習(xí)到了很多東西。當(dāng)然更慶幸的是收獲了眾多讀者的鼓勵(lì)和支持。從本篇文章開始,我們將接觸短視頻 app 中比較核心的功能——視頻編輯,筆者在我司的日常工作中,也經(jīng)常對(duì)這個(gè)模塊進(jìn)行開發(fā),可以說對(duì)這部分功能比較熟悉了。所以最近的幾篇文章,我會(huì)從零開始完善一個(gè)視頻編輯 sdk 的各種功能,最后集成到我們之前的 MyTiktok 項(xiàng)目中。注:本文以 android 平臺(tái)為例子,ios 因?yàn)椴粫?huì),所以暫時(shí)不涉及。

本文分為以下章節(jié),讀者可按需閱讀:

  • 1.項(xiàng)目建立——新建一個(gè)跨平臺(tái)視頻編輯項(xiàng)目

  • 2.基礎(chǔ) lib 集成——將 ffmpeg、protobuf 這些必須使用的三方庫集成到項(xiàng)目中

  • 3.基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)——定義和講解一些視頻編輯流程中需要使用到的數(shù)據(jù)結(jié)構(gòu)

一、項(xiàng)目建立

1.方法論

我想看本文的人有很大一部分都是 android 工程師,所以在講干貨之前,我需要講一講方法論

  • 1.當(dāng)我們在使用 IDE 開發(fā) App 的時(shí)候,我們在干什么?

    • 1.創(chuàng)建一個(gè)文件夾,模仿 AS 生成的項(xiàng)目,向文件夾里面加文件

    • 2.在 gradle 文件中添加依賴庫,然后寫代碼。使用命令行來 sync gradle。

    • 3.命令行運(yùn)行 gradle 來打包 APK,運(yùn)行 App

    • 1.首先我們會(huì)使用 AS 來新建一個(gè)項(xiàng)目,項(xiàng)目會(huì)有很多可選的參數(shù)。

    • 2.在項(xiàng)目的 gradle 文件中添加依賴庫,然后寫代碼

    • 3.打包成 APK,運(yùn)行 App

    • 1.Android 工程師平時(shí)使用 Android Studio 來開發(fā) App,ios 工程師使用 XCode。那么我們平時(shí)在使用 IDE 的時(shí)候,我們到底在干什么呢?

    • 2.這里我以 Android 來舉例子:

    • 3.上面就是我們平時(shí)開發(fā)的流程了,那么我們能不使用 IDE 來開發(fā)一個(gè) App 嗎?理論上來說是可以的,有下面這些步驟。

    • 4.其實(shí)我們不需要 AS 就能進(jìn)行 Android 開發(fā)(當(dāng)然沒有人那么傻)。我們需要的只是一個(gè)項(xiàng)目管理的工具——gradle。放在不同的開發(fā)者那里,只是項(xiàng)目管理的工具不同:寫 java 的用 maven、寫 python 的用 conda/pip、寫前端的用 npm、寫 c/c++ 的用 CMake。

    • 5.所以當(dāng)一個(gè)項(xiàng)目中既要寫 c++ 又要寫 android 還要寫 ios 的時(shí)候,我們只需要三個(gè)項(xiàng)目管理工具就行了,IDE 對(duì)我們來說只是一個(gè)文件編輯器+文件搜索器+文件瀏覽器。

    • 6.以上就是我作為一個(gè) android 工程師,在使用了各種不同語言構(gòu)建不同項(xiàng)目之后思維上的轉(zhuǎn)變。當(dāng)你能看清和思考一個(gè)東西的本質(zhì)的時(shí)候你能走的更遠(yuǎn)。

2.項(xiàng)目搭建

那么廢話不多說,就開始搭建我們的項(xiàng)目吧注意:目前 MyTiktokVideoEditor 已經(jīng)上傳到了 github 上面了,建議結(jié)合項(xiàng)目食用,

  • 1.首先我們新建一個(gè)文件夾,然后進(jìn)入文件夾中。在其中創(chuàng)建下面這些東西,如圖1。里面的東西我一個(gè)個(gè)來講解

    • 1.首先 LICENSSE 和 README.md 就不用說了。

    • 2.android:下面是一個(gè)完整的 android 工程,android 工程的內(nèi)部也會(huì)引用到外部的文件,這個(gè)后面再說。

    • 3.ios:下會(huì)是一個(gè)完整的 ios 工程,當(dāng)然我目前還不會(huì) ios,所以先略過

    • 4.buildtools:里面會(huì)存放一些項(xiàng)目運(yùn)行時(shí)的腳本,比如我們在 上一篇文章 中用到的編譯 FFmpeg 的腳本等等

    • 5.docs:內(nèi)部存放一些項(xiàng)目文檔

    • 6.sharedcode:里面存放 android 和 ios 共享的代碼,如 c/c++ 代碼等等,還有就是 protobuf 生成的代碼。

    • 7.sharedproto:里面存放 android、ios、c++ 三端共享的 protobuf 代碼,可以使用 buildtools 里面的腳本一鍵生成三端的代碼

    • 8.third_part:可以以 git submodule 的形式,引用其他的三方庫的源代碼與 android 和 ios 項(xiàng)目一起編譯,目前是空的。

  • 2.介紹好了項(xiàng)目構(gòu)成,我們開始配置 android 項(xiàng)目吧。

    • 1.首先 externalNativeBuild.cmake 里面配置了一些參數(shù),這里只要知道我們使用的是 c++11 就好了

    • 2.externalNativeBuild.ndk 里面我們只生成一種 so 文件就是 armeabi,本來是應(yīng)該使用 arm64-v8a,這樣才是最佳適配,現(xiàn)在就先湊合著用吧

    • 3.再看外面的 externalNativeBuild.cmake,這里設(shè)置了 CMake 的路徑,注意這里是以當(dāng)前 gradle 文件為初始路徑的。

    • 1.多了 jni.editorsdk 目錄,這個(gè)目錄用來存放 jni 文件,相當(dāng)于是 c/c++ 和 java 的中間層。

    • 2.然后是 CMakeLists.txt 文件,其用于管理 android 項(xiàng)目需要引入的 c/c++ 代碼。

    • 1.首先,我們需要使用 AS 來創(chuàng)建一個(gè)支持 C++ 的工程,注意目錄需要選在上面提到的 android 目錄下面。

    • 2.創(chuàng)建好了之后,我們需要?jiǎng)?chuàng)建一個(gè) android library 作為視頻編輯 sdk 的載體。這個(gè) module 將會(huì)整合所有的,共享 cpp 代碼、.so 文件、.a 文件,然后通過 java 代碼被外部調(diào)用。在項(xiàng)目中我將這個(gè) module 命名為了 mttvideoeditorsdk

    • 3.至于 app module 可以引用 mttvideoeditorsdk module 便于平時(shí)調(diào)試 sdk。

    • 4.我們再來看 mttvideoeditorsdk 的結(jié)構(gòu)如圖2,其實(shí)比較簡單

    • 5.我們再來看看 gradle 文件是怎么配置的如圖3。

二、基礎(chǔ) lib 集成

上面講了如何搭建項(xiàng)目,這一章就來講講如何集成一些基礎(chǔ)庫吧。

首先我們都知道,在 android 中我們可以使用 gradle 向遠(yuǎn)程中央倉庫拉取我們需要的庫。像 java 的 maven、js 的 npm、ios 的 pods都有這個(gè)能力。但是在 c/c++ 上的項(xiàng)目管理工具 CMake 就沒有這個(gè)能力,它只能在本地搜索和集成你已經(jīng)安裝好的庫或者源碼,而且 c/c++ 又不具有跨平臺(tái)能力。所以最終就導(dǎo)致了我們?nèi)绻胧褂?ffmpeg、protobuf 這樣大型的開源項(xiàng)目都需要自己去 clone 源碼然后自己編譯出不同平臺(tái)的庫。

1.FFmpeg 集成

  • 1.說到 FFmpeg 的集成,其實(shí)我在這里,已經(jīng)提到過一些了。我這里就簡單講講。

  • 2.首先我們需要編譯 FFmpeg 的代碼獲取 so 庫和 頭文件,我的這個(gè)項(xiàng)目與上次不同,現(xiàn)在已經(jīng)能編譯出一個(gè)單獨(dú)的 libffmpeg.so 的文件了,大家可以之前拿過來用。

  • 3.然后我們在 android 項(xiàng)目下面新建一個(gè)目錄用來儲(chǔ)存這些東西,如圖4。

  • 4.最后我們看代碼塊1,這里都有注釋比較簡單,就是將 libffmpeg.so 和他的頭文件鏈接到整個(gè)項(xiàng)目中

----代碼塊1,本文發(fā)自簡書、掘金:何時(shí)夕-----cmake_minimum_required(VERSION 3.4.1)# 當(dāng)前文件存在的目錄set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})# MyTiktokVideoEditor 的根目錄set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)# ffmpeg 的目錄set(FFMPEG_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../android_ffmpeg)# protobuf 頭文件與靜態(tài)庫的目錄set(PROTOBUF_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../android_protobuf)# android 專用 c++ 代碼的目錄set(EDITORSDK_JNI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/editorsdk)# c++ 共享代碼的目錄set(SHARED_CODE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../sharedcode)# c++ 的版本set(CMAKE_CXX_STANDARD 11)# 找到 android ndk 的 log 庫find_library(log-lib log)# 將 libffmpeg.so 添加到 libffmpeg 這個(gè) 動(dòng)態(tài) library中add_library(libffmpeg SHARED IMPORTED)set_target_properties(libffmpeg PROPERTIES IMPORTED_LOCATION        ${FFMPEG_LIB_DIR}/armeabi/libffmpeg.so)# 將 libprotobuf.a 添加到 libprotobuf-lite 這個(gè) 靜態(tài) library 中add_library(libprotobuf-lite STATIC IMPORTED)set_target_properties(libprotobuf-lite PROPERTIES IMPORTED_LOCATION        ${PROTOBUF_LIB_DIR}/armeabi/libprotobuf-lite.a)aux_source_directory(${SOURCE_DIR} SOURCE_DIR_ROOT)# 將所有自己寫的 c++ 代碼添加到 mttvideoeditorsdkjni 這個(gè) 動(dòng)態(tài) library 中l(wèi)ist(APPEND SOURCE_DIR_ROOT        ${EDITORSDK_JNI_DIR}/native-lib.cc        ${EDITORSDK_JNI_DIR}/ffmpeg_sample_six.cpp)list(APPEND SOURCE_DIR_ROOT        ${SHARED_CODE_DIR}/editorsdk/base/av_utils.cc        ${SHARED_CODE_DIR}/editorsdk/generated_protobuf/editor_model.pb.cc)add_library(mttvideoeditorsdkjni            SHARED            ${SOURCE_DIR_ROOT})# 將所有頭文件添加到一個(gè)列表中,在最后一起鏈接list(APPEND SOURCE_DIR_INCLUDE        ${SHARED_CODE_DIR}/editorsdk/base/av_utils.h        ${SHARED_CODE_DIR}/editorsdk/base/blocking_queue.h        ${SHARED_CODE_DIR}/editorsdk/generated_protobuf/editor_model.pb.h        ${PROTOBUF_LIB_DIR}/include # 將 protobuf 的頭文件放入一個(gè)列表中        ${FFMPEG_LIB_DIR}/include) # 將 ffmpeg 的頭文件放入一個(gè)列表中target_include_directories(mttvideoeditorsdkjni PRIVATE ${SOURCE_DIR_INCLUDE}) # 連接列表中所有的頭文件list(APPEND LINK_LIBRARIES        mttvideoeditorsdkjni        -landroid        libprotobuf-lite        libffmpeg) # 將所有的庫添加到一個(gè)列表中,最后一起鏈接target_compile_options(mttvideoeditorsdkjni PUBLIC -D_LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS -Wthread-safety -Werror -Wall -Wno-documentation -Wno-shorten-64-to-32 -Wno-nullability-completeness)target_link_libraries(${LINK_LIBRARIES} ${log-lib}) # 鏈接所有庫復(fù)制代碼

2.protobuf 集成

  • 1.先上腳本看代碼塊2,里面主要是 clone protobuf 的源碼,然后編譯,然后根據(jù)我們前面建立項(xiàng)目的時(shí)候 sharedproto 文件夾里面的 proto 文件來生成 java c++ 的代碼,最后移動(dòng)到 android 項(xiàng)目和 sharedcode 文件夾下。每次更新了 proto 文件就可以運(yùn)行一下這個(gè)腳本。

  • 2.當(dāng)然還得將 protobuf c++ 的庫集成到項(xiàng)目中,如圖5我們新建一個(gè) android_protobuf 的目錄,然后將剛剛編譯生成的 .a 文件與頭文件拷貝到里面去,這里與 ffmpeg 的集成類似。不同的地方在于,protobuf 生成的是 .a 文件,這里需要將其作為靜態(tài)鏈接庫,添加到項(xiàng)目中。詳細(xì)的在代碼塊1中已經(jīng)說明了。

----代碼塊2,本文發(fā)自簡書、掘金:何時(shí)夕-----#!/bin/bashshow_msg() {  echo -e "\033[36m$1\033[0m"}show_err() {  echo -e "\033[31m$1\033[0m"}# protobuf 的版本v3_0_0="v3.0.0"# 當(dāng)前的目錄script_path=$(cd `dirname $0`; pwd)# protoc 是 protobuf 編譯之后生成的可執(zhí)行文件,可以用來根據(jù) proto 文件生成 java、c++等等代碼protoc_path=$script_path/tools/protoc# protobuf 的源碼地址protoc_src=$script_path/protobuf# 生成的 java 文件需要移動(dòng)到的位置java_target_path="$script_path/../android/mttvideoeditorsdk/src/main"# 生成的 c++ 文件需要移動(dòng)的位置cpp_target_path="$script_path/../sharedcode/editorsdk/generated_protobuf"# 本方法用于執(zhí)行 protobuf 源碼的腳本進(jìn)行編譯build_protobuf() {  mkdir -p $protoc_src/host  mkdir -p $protoc_path/$1  cd $protoc_src/host  ../configure --prefix=$protoc_path/$1 && make -j8 && make install  if test $? != 0; then    show_err "Build protobuf failed"    exit 1  fi  cd $script_path  rm -rf $protoc_src/host}# 本方法用于 clone protobuf 的源碼,然后 checkout 到3.0.0的版本,然后調(diào)用 build_protobuf 進(jìn)行編譯build() {  git clone https://github.com/google/protobuf.git  show_msg "Building android protobuff source code"  cd protobuf  git checkout $v3_0_0  git cherry-pick bba446b  # fix issue https://github.com/google/protobuf/issues/2063  ./autogen.sh  build_protobuf $v3_0_0  show_msg "Build protobuf complete"  cd $script_path  rm -rf protobuf}# 如果 protoc 不存在,那么就去 clone protobuf 的源碼,然后編譯if [ ! -x "$protoc_path/$v3_0_0/bin/protoc" ]; then  buildfi# 刪除之前已經(jīng)生成的 java c++ 文件rm $java_target_path/java/com/whensunset/mttvideoeditorsdk/model/protobuf/*.javarm $cpp_target_path/*.pb.cc $cpp_target_path/*.pb.hcd $script_path/../sharedprotomkdir -p java cpp# 用 protoc 生成 java c++ 文件$protoc_path/$v3_0_0/bin/protoc *.proto --java_out=java --cpp_out=cpp# 將生成的 java c++ 文件移動(dòng)到對(duì)應(yīng)的文件夾下cp -r java $java_target_pathmkdir -p $cpp_target_pathcp cpp/* $cpp_target_pathrm -rf java cpp復(fù)制代碼

三、基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

最后一章我們來定義一下在一個(gè)視頻編輯過程中,需要用到的數(shù)據(jù)結(jié)構(gòu)。

  • 1.大家可以看見在 sharedproto 文件夾下面有個(gè) editor_model.proto 文件,里面定義了一些我們在未來整個(gè)視頻編輯功能開發(fā)過程中需要用到的數(shù)據(jù)結(jié)構(gòu),如代碼塊3

  • 2.前面的幾行初始化代碼就不講了,我就按照定義的一個(gè)個(gè)數(shù)據(jù)結(jié)構(gòu)來進(jìn)行講解

    • 1.TimeRange:這個(gè)顧名思義,用于保存一段時(shí)間,單位是秒。是最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),比如特效出現(xiàn)的時(shí)間段、視頻被剪裁的段落、貼紙出現(xiàn)的時(shí)間段等等都需要用到它。

    • 2.MediaStreamHolder:我們都知道(如果不知道可以去看看我之前的文章),F(xiàn)Fmpeg 解封裝了一個(gè)視頻文件之后會(huì)得到好幾個(gè)不同的 stream,每一個(gè) stream 可能是一個(gè)視頻數(shù)據(jù)流可能是一個(gè)音頻數(shù)據(jù)流,而這個(gè)數(shù)據(jù)結(jié)構(gòu)就是為了儲(chǔ)存視頻數(shù)據(jù)流的信息。

    • 3.FileHolder:我們解析了一個(gè)多媒體文件的時(shí)候,也需要把這個(gè)文件的一些信息存下來,比如:文件的后綴名、文件中每個(gè) stream 的信息、文件中最優(yōu)的視頻流和音頻流的 index等等。這個(gè)時(shí)候就要用到這個(gè)數(shù)據(jù)結(jié)構(gòu)了。

    • 4.Color、AssetType:兩個(gè)工具數(shù)據(jù)結(jié)構(gòu)

    • 5.VideoAsset:表示一個(gè)視頻素材,里面除了有個(gè) FileHolder 來儲(chǔ)存視頻被解析后的信息,還有視頻被剪裁的時(shí)間段、視頻的音量、視頻的速度之類的信息。

    • 6.AudioAsset:與 VideoAsset 類似,表示一個(gè)音頻素材。

    • 7.VideoWorkspace:表示一次視頻編輯的數(shù)據(jù)結(jié)構(gòu),里面有復(fù)數(shù)個(gè)視頻素材和音頻素材,以及一些其他參數(shù)。

    • 8.VideoEncoderType:表示當(dāng)前視頻編輯的過程中,視頻用到的編解碼方式。目前只有使用 FFmpeg 編解碼與使用 android 的 mediaCodec 編解碼這兩種方式。

    • 9.這里的數(shù)據(jù)結(jié)構(gòu)隨著 sdk 開發(fā)的進(jìn)行會(huì)不斷的增加和修改,目前這里定義的只是最的簡單版本,大家有想法可以在評(píng)論區(qū)和我交流。

syntax = "proto3";package sharedcode;option optimize_for = LITE_RUNTIME;option java_package = "com.whensunset.mttvideoeditorsdk.model.protobuf";// 用于保存一段時(shí)間,單位是秒message TimeRange {    double start = 1;    double duration = 2;    uint64 id = 3;}// 一個(gè)多媒體文件的一個(gè)多媒體數(shù)據(jù)流的信息message MediaStreamHolder {    // 視頻的長和寬    int32 width = 1;    int32 height = 2;    // 編解碼器的名稱    string codec_type = 3;    // 視頻的旋轉(zhuǎn)角度    int32 rotation = 4;    // 視頻像素的格式    int32 pix_format = 5;    // 視頻的色彩空間,rgb、yuv 等等    int32 color_space = 6;    // 視頻的色彩范圍    int32 color_range = 7;    // 視頻的 bit 流    int64 bit_rate = 8;}// 儲(chǔ)存一個(gè)多媒體文件的信息,減少反復(fù)解析的性能消耗message FileHolder {    string path = 1;    // 文件的后綴名    string format_name = 2;    int32 probe_score = 3;    // 文件中的多媒體數(shù)據(jù)流的數(shù)量    int32 num_streams = 4;    // 文件中的多媒體數(shù)據(jù)流的信息列表    repeated MediaStreamHolder streams = 5;    // 文件中多媒體信息流中最優(yōu)的視頻流    int32 video_strema_index = 6;    // 文件中多媒體信息流中最優(yōu)的音頻流    int32 audio_strema_index = 7;    string video_comment = 8;}message Color {    float red = 1;    float green = 2;    float blue = 3;    float alpha = 4;}// 素材的種類enum AssetType {    ASSET_TYPE_VIDEO = 0;    ASSET_TYPE_AUDIO = 1;}// 表示一個(gè)視頻素材message VideoAsset {    // 相同表示當(dāng)前素材是同樣的    uint64 asset_id = 1;    string asset_path = 2;    FileHolder asset_video_file_hodler = 3;    // 當(dāng)前素材被剪裁的時(shí)間區(qū)域    repeated TimeRange clipped_time_range = 4;    // 視頻的速度    double speed = 5;    // 視頻聲音大小    double volume = 6;    bool is_reversed = 7;}// 表示一個(gè)音頻的素材message AudioAsset {    uint64 asset_id = 1;    string asset_path = 2;    FileHolder asset_audio_file_holder = 3;    repeated TimeRange clipped_time_range = 4;    double speed = 5;    double volume = 6;    bool is_repeat = 7;}// 表示一次視頻編輯的流程message VideoWorkspace {    int64 work_space_id = 1;    repeated VideoAsset video_asset = 2;    repeated AudioAsset audio_asset = 3;    repeated TimeRange clipped_ranges = 4;    int32 workspace_output_width = 5;    int32 workspace_output_height = 6;    VideoEncoderType video_encoder_type = 7;}// 當(dāng)前視頻編輯流程使用的編解碼方式enum VideoEncoderType {    VIDEO_ENCODER_TYPE_FFMPEG_MJPEG = 0;    VIDEO_ENCODER_TYPE_MEDIACODEC = 1;}復(fù)制代碼

四、結(jié)束

不知不覺又水了一篇文章^_^,最近的兩篇文章都是代碼多而文字少。不知道大家是不是喜歡這種方式呢?(感覺以前廢話太多了,哈哈)大家有什么建議或者意見希望能在評(píng)論區(qū)提出來。如果文章問題可以指出是哪里,方便我進(jìn)行修改(手動(dòng)@上篇文章中說我文章有錯(cuò)別字的哥們)。最近點(diǎn)贊關(guān)注有點(diǎn)少啊,希望大家看完能隨手點(diǎn)個(gè)贊和關(guān)注,謝謝啦!

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
使用CMake來進(jìn)行Android NDK開發(fā)
基于ffmpeg的Android 2.2播放器開源代碼
Androidstudio cmake 使用第三方庫的使用
使用Vitamio打造自己的Android萬能播放器(1)——準(zhǔn)備
用FFmpeg快速切割視頻(免轉(zhuǎn)碼)
在linux中安裝opencv 2.1-正常使用視頻文件
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服