中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

如果做網(wǎng)站賺錢優(yōu)化關鍵詞的步驟

如果做網(wǎng)站賺錢,優(yōu)化關鍵詞的步驟,常用網(wǎng)站有哪些,亦莊網(wǎng)站開發(fā)公司文章目錄 FFmpeg視頻處理工具使用總結環(huán)境配置主函數(shù)與參數(shù)處理打開輸入文件獲取流信息分配輸出文件上下文猜測輸出文件格式創(chuàng)建視頻流并設置參數(shù)打開輸出文件并寫入頭信息讀取、轉換并寫入幀數(shù)據(jù)寫入尾信息并釋放資源運行程序注意事項源代碼 FFmpeg視頻處理工具使用總結 環(huán)境…

文章目錄

  • FFmpeg視頻處理工具使用總結
    • 環(huán)境配置
    • 主函數(shù)與參數(shù)處理
    • 打開輸入文件
    • 獲取流信息
    • 分配輸出文件上下文
    • 猜測輸出文件格式
    • 創(chuàng)建視頻流并設置參數(shù)
    • 打開輸出文件并寫入頭信息
    • 讀取、轉換并寫入幀數(shù)據(jù)
    • 寫入尾信息并釋放資源
    • 運行程序
    • 注意事項
    • 源代碼

FFmpeg視頻處理工具使用總結

環(huán)境配置

  • 在C++程序中使用FFmpeg之前,需要包含相應的頭文件,并根據(jù)是否使用C++編譯器,可能需要添加extern "C"塊。在C++中,當包含C語言的頭文件時,需要使用extern "C"來告訴編譯器這是一個C語言的函數(shù),避免C++的名稱修飾導致鏈接錯誤。這個例子中,包含了FFmpeg庫的頭文件,用于處理多媒體文件。
  • 在C++中,當包含C語言的頭文件時,需要使用extern "C"來告訴編譯器這是一個C語言的函數(shù),避免C++的名稱修飾導致鏈接錯誤。
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus
}
#endif

主函數(shù)與參數(shù)處理

程序入口點是main函數(shù),它處理命令行參數(shù)并設置日志級別。

  • 檢查傳入的參數(shù)個數(shù)是否大于等于3,如果參數(shù)個數(shù)小于3,就輸出錯誤信息并退出程序。

  • 將第一個參數(shù)賦值給變量src,將第二個參數(shù)賦值給變量dst,這樣就得到了輸入文件路徑和輸出文件路徑。

  • 調用av_log_set_level函數(shù)設置日志級別為AV_LOG_DEBUG,這樣在程序執(zhí)行過程中會打印出調試級別的日志信息。

int main(int argc, char *argv[]) {// 參數(shù)檢查if (argc < 3) {av_log(nullptr, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);exit(-1);}// 輸入輸出文件路徑char *src = argv[1];char *dst = argv[2];// 設置日志級別av_log_set_level(AV_LOG_DEBUG);
}

打開輸入文件

使用avformat_open_input打開輸入文件,并檢查返回值。avformat_open_input是libavformat庫中的一個函數(shù),用于打開一個輸入文件并初始化輸入上下文。
輸入?yún)?shù)如下:

  1. AVFormatContext **ps:指向要初始化的AVFormatContext指針的指針。函數(shù)將分配一個AVFormatContext結構并將其指針保存在該參數(shù)指向的地址中。
  2. const char *url:輸入文件的URL或文件名。
  3. AVInputFormat *fmt:強制指定要使用的輸入格式。如果為NULL,則函數(shù)將根據(jù)輸入文件的擴展名自動選擇適當?shù)母袷健?/li>
  4. AVDictionary **options:一個指向AVDictionary結構指針的指針,用于設置差異化選項??梢允褂迷搮?shù)來設置例如輸入緩沖區(qū)大小、超時值等選項。
  5. int (*interrupt_callback)(void):設置中斷回調函數(shù)。如果輸入操作需要中斷,則調用此回調函數(shù)。如果為NULL,則不設置中斷回調。

函數(shù)執(zhí)行成功后,ps將指向已初始化的AVFormatContext結構,可以使用該結構來進行后續(xù)的輸入操作。執(zhí)行失敗時,ps將保持不變,而函數(shù)將返回一個負值以表示錯誤原因。

int ret = avformat_open_input(&pFormatCtx, src, nullptr, nullptr);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Could not open input file: %s\n", src);exit(-1);
}

獲取流信息

調用av_find_best_stream找到最佳的視頻流。
av_find_best_stream是FFmpeg庫中的一個函數(shù),用于查找最佳的流索引。它的定義如下:

int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, int wanted_stream_nb, int related_stream, AVCodec **decoder_ret, int flags);

參數(shù)說明如下:

  1. ic:指向AVFormatContext的指針,表示輸入的封裝格式上下文。
  2. type:表示所需流的媒體類型,可以是AVMEDIA_TYPE_AUDIO、AVMEDIA_TYPE_VIDEOAVMEDIA_TYPE_SUBTITLE。
  3. wanted_stream_nb:表示所需流的索引號。
  4. related_stream:表示關聯(lián)的流的索引號。通常設置為負值,表示沒有關聯(lián)的流。
  5. decoder_ret:指向AVCodec指針的指針,用于返回找到的解碼器。
  6. flags:表示查找流的標志位,可以是AVFMT_FLAG_NOFILE、AVFMT_FLAG_GENPTS等。

函數(shù)返回值為找到的流的索引號,如果未找到則返回負值錯誤代碼。

這個函數(shù)的主要功能是根據(jù)指定的媒體類型和索引號,在輸入的封裝格式上下文中查找最佳的流索引。它會根據(jù)一些條件(如流的媒體類型、時間基等)進行評估,然后返回找到的最佳流索引,并通過decoder_ret參數(shù)返回對應的解碼器。av_find_best_stream是FFmpeg庫中的一個函數(shù),用于查找最佳的流索引。它的定義如下:

ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Failed to retrieve input stream information\n");goto _ERROR;
}

分配輸出文件上下文

使用avformat_alloc_context分配輸出文件的格式上下文。

avformat_alloc_context是FFmpeg中的一個函數(shù),用于分配一個AVFormatContext結構體,并初始化其成員變量。

輸入?yún)?shù)為void。avformat_alloc_context是FFmpeg中的一個函數(shù),用于分配一個AVFormatContext結構體,并初始化其成員變量。

輸入?yún)?shù)為void。

oFormatCtx = avformat_alloc_context();
if (oFormatCtx == nullptr) {av_log(nullptr, AV_LOG_ERROR, "Failed to allocate output context\n");goto _ERROR;
}

猜測輸出文件格式

使用av_guess_format猜測輸出文件的格式。
av_guess_format是FFmpeg庫中的一個函數(shù),用于猜測輸入?yún)?shù)的格式。它的輸入?yún)?shù)包括:

  1. const char *short_name:輸入?yún)?shù)的短名稱。這是一個字符串,通常是文件的擴展名或格式的簡稱。
  2. const char *filename:輸入?yún)?shù)的文件名。這是一個字符串,指定要處理的文件路徑。
  3. const char *mime_type:輸入?yún)?shù)的MIME類型。這是一個字符串,指定要處理的媒體類型。

這些輸入?yún)?shù)可根據(jù)實際需求來選擇設置,也可以通過設置為NULL來忽略某些參數(shù)。根據(jù)提供的輸入?yún)?shù),av_guess_format函數(shù)會嘗試猜測并返回最有可能的格式。

注意:在使用av_guess_format函數(shù)時,應確保FFmpeg庫已正確初始化,并且所需的輸入?yún)?shù)有效且符合可接受的格式。av_guess_format是FFmpeg庫中的一個函數(shù),用于猜測輸入?yún)?shù)的格式。它的輸入?yún)?shù)包括:

  1. const char *short_name:輸入?yún)?shù)的短名稱。這是一個字符串,通常是文件的擴展名或格式的簡稱。
  2. const char *filename:輸入?yún)?shù)的文件名。這是一個字符串,指定要處理的文件路徑。
  3. const char *mime_type:輸入?yún)?shù)的MIME類型。這是一個字符串,指定要處理的媒體類型。

這些輸入?yún)?shù)可根據(jù)實際需求來選擇設置,也可以通過設置為NULL來忽略某些參數(shù)。根據(jù)提供的輸入?yún)?shù),av_guess_format函數(shù)會嘗試猜測并返回最有可能的格式。

注意:在使用av_guess_format函數(shù)時,應確保FFmpeg庫已正確初始化,并且所需的輸入?yún)?shù)有效且符合可接受的格式。

outFmt = av_guess_format(nullptr, dst, nullptr);
if (outFmt == nullptr) {av_log(nullptr, AV_LOG_ERROR, "Failed to guess output format\n");goto _ERROR;
}
oFormatCtx->oformat = outFmt;

創(chuàng)建視頻流并設置參數(shù)

為輸出文件創(chuàng)建視頻流,并復制輸入視頻流的參數(shù)。

outStream = avformat_new_stream(oFormatCtx, nullptr);
avcodec_parameters_copy(outStream->codecpar, pFormatCtx->streams[ret]->codecpar);
outStream->codecpar->codec_tag = 0;

打開輸出文件并寫入頭信息

使用avio_open2打開輸出文件,并使用avformat_write_header寫入文件頭信息。
avio_open2 是用于打開一個輸入輸出數(shù)據(jù)流的函數(shù),它的輸入?yún)?shù)包括:

  • AVIOContext **s:指向用于輸入輸出的 AVIOContext 結構體的指針。
  • const char *filename:輸入輸出的文件名或者URL地址,使用 “r” 模式打開用于輸入,使用 “w” 模式打開用于輸出。
  • int flags:打開文件的參數(shù),可以是 AVIO_FLAG_READ 表示輸入流、AVIO_FLAG_WRITE 表示輸出流、AVIO_FLAG_READ_WRITE 表示輸入輸出流。
  • const AVIOInterruptCB *int_cb:輸入輸出中斷回調函數(shù)的指針。
  • AVDictionary **options:用于傳遞其他選項的字典指針??梢栽O置 NULL 以忽略其他選項。

avformat_write_header 是用于寫入文件頭信息的函數(shù),它的輸入?yún)?shù)包括:

  • AVFormatContext *s:指向 AVFormatContext 結構體的指針,表示待寫入文件的格式上下文。
  • AVDictionary **options:用于傳遞其他選項的字典指針??梢栽O置 NULL 以忽略其他選項。

這些函數(shù)用于打開輸入輸出數(shù)據(jù)流和寫入文件頭信息時,需要通過傳入一些參數(shù)來配置打開的流和文件的屬性和選項。avio_open2 是用于打開一個輸入輸出數(shù)據(jù)流的函數(shù),它的輸入?yún)?shù)包括:

ret = avio_open2(&oFormatCtx->pb, dst, AVIO_FLAG_WRITE, nullptr, nullptr);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Failed to open output file: %s\n", dst);goto _ERROR;
}
ret = avformat_write_header(oFormatCtx, nullptr);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Failed to write output file header\n");goto _ERROR;
}

讀取、轉換并寫入幀數(shù)據(jù)

讀取輸入文件的視頻幀,轉換時間戳,并使用av_interleaved_write_frame寫入輸出文件。
av_interleaved_write_frame函數(shù)是FFmpeg庫中的一個函數(shù),用于將音視頻數(shù)據(jù)包寫入容器文件。

函數(shù)的參數(shù)如下:

  1. AVFormatContext *s: AVFormatContext結構體指針,表示容器格式上下文,用于管理容器格式相關的信息。

  2. AVPacket *pkt: AVPacket結構體指針,表示音視頻數(shù)據(jù)包,包含音視頻數(shù)據(jù)以及相關的參數(shù)信息。

函數(shù)的返回值為整形,表示函數(shù)的執(zhí)行結果。如果返回值為0,則表示成功寫入數(shù)據(jù)包;如果返回值為負值,則表示寫入失敗。

注意:在調用av_interleaved_write_frame函數(shù)之前,需要先調用avformat_write_header函數(shù)來寫入容器文件的頭部信息;在所有音視頻數(shù)據(jù)包寫入完成后,還需要調用av_write_trailer函數(shù)來寫入容器文件的尾部信息。

此外,av_interleaved_write_frame函數(shù)只能用于寫入已經交錯存儲的音視頻數(shù)據(jù)包,如果數(shù)據(jù)包未經過交錯處理,則需要使用av_write_frame函數(shù)來分別寫入音頻數(shù)據(jù)包和視頻數(shù)據(jù)包。av_interleaved_write_frame函數(shù)是FFmpeg庫中的一個函數(shù),用于將音視頻數(shù)據(jù)包寫入容器文件。

while (av_read_frame(pFormatCtx, &pkt) >= 0) {if (pkt.stream_index == ret) {// 轉換時間戳等pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base);// 寫入幀數(shù)據(jù)av_interleaved_write_frame(oFormatCtx, &pkt);}av_packet_unref(&pkt);
}

寫入尾信息并釋放資源

使用av_write_trailer寫入文件尾信息,并釋放所有資源。
函數(shù)av_write_trailer的參數(shù)是AVFormatContext。

AVFormatContext是一個存儲了整個音視頻文件信息的結構體,包含了音視頻流、容器格式信息以及封裝器相關的信息。

av_write_trailer函數(shù)的功能是將容器頭信息寫入到輸出文件中,并完成文件封裝的最后步驟。具體而言,它會將封裝器中剩余的音視頻數(shù)據(jù)寫入到輸出文件中,并更新容器頭的相關信息,如文件大小、時長等。

在調用av_write_trailer函數(shù)之前,需要保證所有的音視頻數(shù)據(jù)已經被寫入到容器中,否則可能會導致文件不完整或者損壞。

調用av_write_trailer函數(shù)之后,應釋放AVFormatContext相關的資源,包括關閉文件和釋放相關的內存。

示例代碼如下:

AVFormatContext* outputContext = nullptr;
// 初始化outputContext的代碼
// ...
// 寫入所有音視頻數(shù)據(jù)到容器
// ...
av_write_trailer(outputContext);
// 釋放相關資源
avformat_close_input(&outputContext);
avformat_free_context(outputContext);

函數(shù)av_write_trailer的參數(shù)是AVFormatContext。

AVFormatContext是一個存儲了整個音視頻文件信息的結構體,包含了音視頻流、容器格式信息以及封裝器相關的信息。

av_write_trailer函數(shù)的功能是將容器頭信息寫入到輸出文件中,并完成文件封裝的最后步驟。具體而言,它會將封裝器中剩余的音視頻數(shù)據(jù)寫入到輸出文件中,并更新容器頭的相關信息,如文件大小、時長等。

在調用av_write_trailer函數(shù)之前,需要保證所有的音視頻數(shù)據(jù)已經被寫入到容器中,否則可能會導致文件不完整或者損壞。

調用av_write_trailer函數(shù)之后,應釋放AVFormatContext相關的資源,包括關閉文件和釋放相關的內存。

示例代碼如下:

AVFormatContext* outputContext = nullptr;
// 初始化outputContext的代碼
// ...
// 寫入所有音視頻數(shù)據(jù)到容器
// ...
av_write_trailer(outputContext);
// 釋放相關資源
avformat_close_input(&outputContext);
avformat_free_context(outputContext);
av_write_trailer(oFormatCtx);_ERROR:
// 清理資源
if (oFormatCtx && oFormatCtx->pb) {avio_close(oFormatCtx->pb);oFormatCtx->pb = nullptr;
}
if (oFormatCtx) {avformat_free_context(oFormatCtx);oFormatCtx = nullptr;
}
if (pFormatCtx) {avformat_free_context(pFormatCtx);pFormatCtx = nullptr;
}

運行程序

程序需要傳入兩個參數(shù):輸入文件路徑和輸出文件路徑。例如:

./my_ffmpeg_tool input.mp4 output.mkv

確保替換為您的實際文件名和所需的輸出格式。

注意事項

  • 確保FFmpeg開發(fā)庫已正確安裝且可鏈接。
  • 檢查程序輸出的錯誤信息以進行調試。
  • 程序可能需要適當?shù)淖x取和寫入權限。

源代碼

  • cmake 源文件
cmake_minimum_required(VERSION 3.27)
project(FFmpeg_exercise)
set(CMAKE_CXX_STANDARD 14)# 定義FFmpeg的安裝路徑變量
set(FFMPEG_INSTALL_DIR "/usr/local/ffmpeg")# 將FFmpeg的頭文件目錄添加到包含路徑
include_directories(${FFMPEG_INSTALL_DIR}/include)# 定義FFmpeg庫的基礎名稱(根據(jù)你的需要調整)
set(FFMPEG_LIBS "avcodec;avformat;avutil") # 用分號分隔庫名# 尋找并鏈接FFmpeg庫
foreach(FFMPEG_LIB ${FFMPEG_LIBS})find_library(${FFMPEG_LIB}_LIBRARY NAMES ${FFMPEG_LIB}PATHS ${FFMPEG_INSTALL_DIR}/lib NO_DEFAULT_PATH)list(APPEND FFMPEG_LIBRARIES ${${FFMPEG_LIB}_LIBRARY})
endforeach()add_executable(FFmpeg_exercise# main.cpp# extra_audic.cppextra_video.cpp)
# 鏈接FFmpeg庫
target_link_libraries(FFmpeg_exercise ${FFMPEG_LIBRARIES})
  • cpp
//
// Created by 陳偉峰 on 2024/6/22.
//
#ifdef __cplusplus
extern "C" {
#endif
// 包含F(xiàn)Fmpeg的頭文件
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus}
#endif
#include <iostream>int main(int argc,char *argv[]){int ret {-1};int idx {-1};//1.處理一些參數(shù)char *src {nullptr};char *dst {nullptr};AVFormatContext *pFormatCtx {nullptr};AVFormatContext *oFormatCtx {nullptr};AVOutputFormat *outFmt {nullptr};AVStream *outStream {nullptr};AVStream *inSteam {nullptr};AVPacket pkt {nullptr};// 日志信息av_log_set_level(AV_LOG_DEBUG);if(argc<3){av_log(nullptr,AV_LOG_ERROR,"Usage:%s <input file> <output file>\n",argv[0]);exit(-1);}src = argv[1];dst = argv[2];// 2.打開多媒體輸入文件ret = avformat_open_input(&pFormatCtx,src,nullptr,nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Could not open input file:%s\n",src);exit(-1);}// 3.獲取多媒體文件信息ret = av_find_best_stream(pFormatCtx,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to retrieve input stream information\n");goto _ERROR;}// 打開目的多媒體文件oFormatCtx = avformat_alloc_context();if(oFormatCtx==nullptr){av_log(nullptr,AV_LOG_ERROR,"Failed to allocate output context\n");goto _ERROR;}outFmt = av_guess_format(nullptr,dst,nullptr);if(outFmt==nullptr){av_log(nullptr,AV_LOG_ERROR,"Failed to guess output format\n");goto _ERROR;}oFormatCtx->oformat = outFmt;// 為目的文件,創(chuàng)建一個新的視頻流outStream = avformat_new_stream(oFormatCtx,nullptr);// 設置視頻參數(shù)inSteam = pFormatCtx->streams[idx];avcodec_parameters_copy(outStream->codecpar,pFormatCtx->streams[ret]->codecpar);outStream->codecpar->codec_tag = 0;// 綁定ret = avio_open2(&oFormatCtx->pb,dst,AVIO_FLAG_WRITE, nullptr, nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to open output file:%s\n",dst);goto _ERROR;}// 寫入頭信息ret = avformat_write_header(oFormatCtx,nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header\n");goto _ERROR;}// 寫多媒體文件到目的文件ret = avformat_write_header(oFormatCtx,nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header:%s\n", av_err2str(ret));goto _ERROR;}while(av_read_frame(pFormatCtx,&pkt)>=0) {if (pkt.stream_index == idx) {pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base,(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base,(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base);pkt.stream_index = 0;pkt.pos = -1;av_interleaved_write_frame(oFormatCtx, &pkt);}av_packet_unref(&pkt);}// 寫入尾信息av_write_trailer(oFormatCtx);_ERROR:if(oFormatCtx->pb){avio_close(oFormatCtx->pb);oFormatCtx->pb = nullptr;}if(oFormatCtx){avformat_free_context(oFormatCtx);oFormatCtx = nullptr;}if(pFormatCtx){avformat_free_context(pFormatCtx);pFormatCtx = nullptr;}return 0;
}
  • 執(zhí)行
./main demo.mp4 demo2.h264
  • 運行
ffplay demo2.h264

image-20240622143747704

http://www.risenshineclean.com/news/56938.html

相關文章:

  • html怎么寫廣州網(wǎng)站優(yōu)化服務商
  • 怎么去跟客戶談網(wǎng)站建設四川seo優(yōu)化
  • 網(wǎng)站建設題庫核心關鍵詞舉例
  • 怎么建設h5網(wǎng)站怎樣做關鍵詞排名優(yōu)化
  • 怎么推廣產品最有效短視頻關鍵詞seo優(yōu)化
  • wordpress無法連接遠程mysqlseo推廣人員
  • 真正能賺錢的網(wǎng)站app推廣平臺放單平臺
  • 工信部企業(yè)網(wǎng)站認證搜索引擎有哪些平臺
  • 怎么做企業(yè)網(wǎng)站一級懸浮菜單一個萬能的營銷方案
  • 河南做網(wǎng)站聯(lián)系電話輿情網(wǎng)站直接打開的軟件
  • 廣東手機網(wǎng)站建設價格百度優(yōu)化
  • 做網(wǎng)站是什么工作天津網(wǎng)絡關鍵詞排名
  • 北京住房建設部網(wǎng)站南寧網(wǎng)站推廣大全
  • 新疆做網(wǎng)站哪家公司好廣東培訓seo
  • 平臺網(wǎng)站兼職做sap關鍵詞優(yōu)化推廣排名多少錢
  • 投票活動網(wǎng)站怎么做seo學徒招聘
  • 廣告牌的樣式大全福清市百度seo
  • 天津營銷網(wǎng)站建設公司哪家好虎撲體育網(wǎng)體育
  • 499元做網(wǎng)站微信營銷技巧
  • 珠海市網(wǎng)站建設開發(fā)公司海南百度推廣公司
  • 網(wǎng)站建設的欄目百度推廣一個月費用
  • 畢業(yè)設計網(wǎng)站做啥長沙建設網(wǎng)站制作
  • 如何建立一個網(wǎng)站放視頻適合小學生的新聞事件
  • 做二手網(wǎng)站有哪些2021百度熱搜年度榜
  • 佛山高端網(wǎng)站建設比較火的推廣軟件
  • 專業(yè)網(wǎng)站制作技術程序員培訓機構哪家好
  • 海安建設局網(wǎng)站刷評論網(wǎng)站推廣
  • 寧波趨勢信息科技有限公司網(wǎng)站seo排名優(yōu)化工具在線
  • 微信小程序萬能開掛器seo營銷推廣服務公司
  • wordpress不跳轉網(wǎng)站快速排名優(yōu)化價格