成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

鴻蒙開源第三方組件-VideoCache視頻緩存組件

開源
文章由鴻蒙社區產出,想要了解更多內容請前往:51CTO和華為官方戰略合作共建的鴻蒙技術社區https://harmonyos.51cto.com

[[389195]]

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 前言

基于安卓平臺的視頻緩存組件VideoCache( https://github.com/danikula/AndroidVideoCache),實現了鴻蒙化遷移和重構,代碼已經開源到(https://gitee.com/isrc_ohos/android-video-cache_ohos),歡迎各位下載使用并提出寶貴意見!

背景

用戶在網速波動較大的環境下瀏覽視頻時,經常會遇到由于網速較慢引起的持續加載或播放失敗的情況。VideoCache組件實現了視頻緩存功能,播放視頻的同時,對視頻源進行緩存。出現網速較慢的情況時,手機讀取提前緩存好的視頻數據,可以保證視頻的正常播放,給予用戶更流暢的觀看體驗。

組件效果圖展示

1、主菜單界面: 視頻播放

安裝軟件后,只需要在鴻蒙設備上單擊HarmonyVideoCache軟件圖標,打開軟件即可進入主菜單界面,進入主菜單界面后會自動開始播放視頻,如下圖所示。

圖 1 視頻播放的主菜單界面

2、驗證緩存

等待視頻播放完成后,可以手動關閉手機的數據連接和WIFI連接。

圖 2 關閉網絡連接

在關閉了網絡連接之后,回到VideoCache應用中,點擊播放按鈕, 會發現視頻是可以通過本地緩存重新播放的。注意到圖1和圖3的區別,在圖1中任務欄可以看到有WIFI連接顯示,圖3 中沒有WIFI連接。

圖 3 緩存播放視頻

Sample解析

如圖4所示,該組件在本地與遠程服務器之間建立了代理服務器。當本地發送視頻網絡請求至代理服務器時,代理服務器與遠程服務器之間通過代理Socket連接,并將遠程服務器的視頻數據回寫到代理服務器的緩存中,本地播放視頻時從代理服務器的緩存中讀取數據(圖4援引自https://www.jianshu.com/p/4745de02dcdc)。下面詳細介紹視頻緩存的步驟。

圖4 VideoCache組件的視頻緩存原理

1、實例化HttpProxyCacheServer類的對象

HttpProxyCacheServer類可用于處理來自視頻播放器的播放請求,當本地有緩存時,向視頻播放器返回一個本地IP地址(LocalURL:以127.0.0.1開頭),用于視頻的播放。

  1. private HttpProxyCacheServer mCacheServerProxy=null
  2. public void onStart(Intent intent) { 
  3.         ... 
  4.         if (mCacheServerProxy == null) { 
  5.             Context context = this; 
  6.         //實例化HttpProxyCacheServer對象 
  7.             mCacheServerProxy = new HttpProxyCacheServer(context); 
  8.         }  
  9.        ...     

2、定義緩存監聽器CacheListener

CacheListener 用于監聽文件緩存的進度,方便開發者通過判斷緩存進度,執行各類操作。

onCacheAvailable()方法是設置CacheListener 監聽器時需要重寫的方法,此方法的參數中:cacheFile表示緩存文件的地址;url表示網絡視頻的URL;percentsAvailable表示緩存進度,取值為1~100,取值為100時表示全部視頻緩存完成。

基于percentAvailable變量,大多數視頻播放器有以下設計:設置一個變量用于保存當前的視頻播放進度。在緩存監聽器CacheListener 中,比較當前緩存進度與當前播放進度的差值,如果超出了預設值,可以執行特定操作以暫停緩存,直至二者的差值小于預設值,重新啟動緩存。

  1. private CacheListener mCacheListener = new CacheListener() { 
  2.     @Override 
  3.     public void onCacheAvailable(File cacheFile, String url, int percentsAvailable) { 
  4.     //打印實時緩存進度 
  5.     HiLog.info(new HiLogLabel(3,0,"cache"),"Saving……,percent:"+String.valueOf(percentsAvailable)); 
  6.     //當進度達到100時,可進行一些特殊操作,此處僅以log打印為例 
  7.     if (percentsAvailable == 100 && !cacheFile.getPath().endsWith(".download")) { 
  8.             HiLog.info(new HiLogLabel(3,0,"cache"),"Download already!"); 
  9.         } 
  10.     } 
  11. }; 

3. 獲取LocalURL

將網絡視頻的URL與步驟2中的監聽器對象mCacheListener傳入HttpProxyCacheServer類的注冊方法中,即可對緩存進行監聽。后通過 HttpProxyCacheServer類的getProxyUrl()方法獲取網絡視頻URL對應的LocalUrl。

  1. //注冊下載緩存監聽 
  2.  mCacheServerProxy.registerCacheListener(mCacheListener,URL); 
  3. //獲取LocalURL 
  4. localUrl = mCacheServerProxy.getProxyUrl(URL); 

4、 使用LocalUrl作為視頻來源進行播放,緩存功能即可實現。

Library解析

整個library分為五個部分:file、headers、slice、sourcestorage以及22個類文件,如圖2所示。

圖5 library的組成結構

一、file

在file文件夾下的類主要涉及文件緩存相關的功能:

圖6 file文件夾的組成結構

1、FileCache類

類中規定了緩存文件的命名格式(后加.download)和存儲的路徑,完成了緩存文件的創建。

  1. //定義緩存文件的后綴格式 
  2. private static final String TEMP_POSTFIX = ".download"
  3. public FileCache(File file, DiskUsage diskUsage) throws ProxyCacheException { 
  4.         ... 
  5.         File directory = file.getParentFile(); 
  6.         Files.makeDir(directory); 
  7.         boolean completed = file.exists(); 
  8.         //文件的保存格式:根目錄文件+文件名+之前定義的文件后綴格式 
  9.         this.file = completed ? file : new File(file.getParentFile(), file.getName() + TEMP_POSTFIX); 
  10.         //文件權限設置。緩存完成,文件只能讀取;未緩存完成,文件可讀可寫。 
  11.         this.dataFile = new RandomAccessFile(this.file, completed ? "r" : "rw"); 
  12.     } catch (IOException e) { 
  13.         throw new ProxyCacheException("Error using file " + file + " as disc cache", e); 
  14.     } 

2、Files類

此類是對JAVA中原有的File類的封裝,原File類僅可處理一個文件,Files類可同時對多個文件進行處理。

如下代碼中,getLruListFiles()方法的參數是一個directory,在方法中對directory(文件夾路徑)下的所有文件進行拆分,返回了一個File參數類型的List列表,后續可對列表中的各個File文件進行處理。

  1. static List<File> getLruListFiles(File directory) { 
  2.     //通過list對Files內的文件進行處理 
  3.     List<File> result = new LinkedList<>(); 
  4.     File[] files = directory.listFiles(); 
  5.     //為各file建立LastModifiedComparator 
  6.     //LastModifiedComparator可用于根據文件的上次修改的日期文件進行排序 
  7.     if (files != null) { 
  8.         result = Arrays.asList(files); 
  9.         Collections.sort(result, new LastModifiedComparator()); 
  10.     } 
  11.     return result; 

3、LruDiskUsage類

此類主要用于控制緩存文件的大小,它與Videocache平行開了一個線程,實時記錄緩存文件的數量、大小、存儲空間等,超過預設的閾值時,執行特定的優化操作。

  1. private void trim(List<File> files) { 
  2.     long totalSize = countTotalSize(files);  //緩存文件的總大小 
  3.     int totalCount = files.size();            //緩存文件的總數量 
  4.     for (File file : files) { 
  5.         //未超過緩存文件的(總大小 & 總數量)的閾值時,接收緩存 
  6.         boolean accepted = accept(file, totalSize, totalCount); 
  7.         if (!accepted) { 
  8.       long fileSize = file.length(); // 單一文件的大小 
  9.             boolean deleted = file.delete();  //文件是否為預備刪除的文件 
  10.       //如果是準備刪除的文件 
  11.             if (deleted) { 
  12.                 totalCount--;  // 緩存文件的總數量-1 
  13.                 totalSize -= fileSize;  //緩存文件的總大小 - 預備刪除的單一文件的大小 
  14.                 LOG.info("Cache file " + file +  
  15.                     " is deleted because it exceeds cache limit"); 
  16.             } else { 
  17.                 LOG.error("Error deleting file " + file + " for trimming cache"); 
  18.             } 
  19.         } 
  20.     } 

4、 Md5FileNameGenerator類

此類實現了為輸入文件路徑,生成對應的MD5值的功能。MD5值是一種被"壓縮"的保密格式,可以確保信息完整傳輸。

  1. public class Md5FileNameGenerator implements FileNameGenerator { 
  2.     private static final int MAX_EXTENSION_LENGTH = 4; 
  3.     @Override 
  4.     public String generate(String url) { 
  5.         //獲取文件名的后綴 
  6.         String extension = getExtension(url);  
  7.         //獲取MD5值 
  8.         String name = ProxyCacheUtils.computeMD5(url); 
  9.         Boolean isEmpty = false
  10.         //文件后綴名為空時,設置isEmpty 標志位為true 
  11.         if (extension == null || extension.length() == 0)  
  12.             isEmpty = true
  13.         return isEmpty ? name : name + "." + extension; 
  14.     } 

5、TotalCountLruDiskUsage類、TotalSizeLruDiskUsage類和UnlimitedDiskUsage類

LruDiskUsage類是標題中前兩個類的父類,同時控制緩存文件的大小和數量,需要判斷當前緩存文件的(總大小 & 總數量)未超過閾值時,才會緩存新的文件。 TotalCountLruDiskUsage類和TotalSizeLruDiskUsage類分別只對緩存文件總數量或者緩存文件總大小進行限制,滿足一個條件便可以緩存新的文件。

TotalCountLruDiskUsage類和TotalSizeLruDiskUsage類各有兩個方法:一個方法用于設定緩存文件的閾值;一個方法用于判斷當前緩存數據是否超過了設定的閾值。

當不需要進行磁盤的緩存限制時使用UnlimitedDiskUsage類,其本身是一個空的類,不對緩存文件的數量和大小做任何限制。

  1. //控制緩存文件的總數量 
  2. public class TotalCountLruDiskUsage extends LruDiskUsage { 
  3.     private final int maxCount; 
  4.     //設置緩存文件的總數量的閾值 
  5.     public TotalCountLruDiskUsage(int maxCount) { 
  6.         if (maxCount <= 0) { 
  7.             throw new IllegalArgumentException("Max count must be positive number!"); 
  8.         } 
  9.         this.maxCount = maxCount; 
  10.     } 
  11.  
  12.     //當前緩存文件的總數量小于設定的閾值時,新文件accept 
  13.     @Override 
  14.     protected boolean accept(File file, long totalSize, int totalCount) { 
  15.         return totalCount <= maxCount; 
  16.     } 
  17.  
  18. //控制制緩存文件的總大小 
  19. public class TotalSizeLruDiskUsage extends LruDiskUsage { 
  20.     private final long maxSize; 
  21.     //設置制緩存文件的總大小的閾值 
  22.     public TotalSizeLruDiskUsage(long maxSize) { 
  23.         if (maxSize <= 0) { 
  24.             throw new IllegalArgumentException("Max size must be positive number!"); 
  25.         } 
  26.         this.maxSize = maxSize; 
  27.     } 
  28.  
  29.     //當前緩存文件的總大小小于設定的閾值時,新文件accept 
  30.     @Override 
  31.     protected boolean accept(File file, long totalSize, int totalCount) { 
  32.         return totalSize <= maxSize; 
  33.     } 

二、headers

文件中涉及到的功能不多,僅有一個接口文件和一個能實現URL和文件路徑hashmap匹配功能的類文件,上述功能在HttpProxyCacheServer類中被調用。

圖7 headers文件夾的組成結構

三、slice

鴻蒙程序的slice控件用于三方件遷移中的可視化調試,在這里我們對其不作進一步的分析。

圖8 slice文件夾的組成結構

四、sourcestorage

sourcestorage用于在數據庫中存儲SourInfo。SourInfo可用于存儲http請求源的一些信息,如URL,數據長度Length,請求資源的類型MIME等。sourcestorage中的類主要在上述的HttpProxyCacheServer類中被調用。

圖9 sourcestorage文件夾的組成結構

DatabaseSourceInfoStorage類用于做數據庫的初始化工作,數據庫里面存的字段主要是URL、Length、MIME,SourceInfo類是對這3個字段的封裝。類中包含了三個接口:get()、 put()、release(),可供外部調用,三個接口都是對SourceInfo的操作,主要用來查找和保存緩存的信息。

其余三個類是根據DatabaseSourceInfoStorage類進行的工廠模式的生成,如果對這部分不明白的同學可以在網上搜索“設計模式-工廠模式”進行學習。

  1. class DatabaseSourceInfoStorage extends DatabaseHelper implements SourceInfoStorage { 
  2.     //數據庫中存儲SourInfo:URL、Length、MIME 
  3.     private static final String TABLE = "SourceInfo"
  4.     private static final String COLUMN_ID = "_id"
  5.     private static final String COLUMN_URL = "url"
  6.     private static final String COLUMN_LENGTH = "length"
  7.     private static finavl String COLUMN_MIME = "mime"
  8.     private static final String[] ALL_COLUMNS = new String[]{COLUMN_ID, COLUMN_URL, 
  9.                                                          COLUMN_LENGTH, COLUMN_MIME}; 
  10.     //創建數據庫的SQL 
  11.     private static final String CREATE_SQL = 
  12.             "CREATE TABLE " + TABLE + " (" + 
  13.                     COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + 
  14.                     COLUMN_URL + " TEXT NOT NULL," + 
  15.                     COLUMN_MIME + " TEXT," + 
  16.                     COLUMN_LENGTH + " INTEGER" + 
  17.                     ");"
  18.  
  19.     private final RdbStore myRdbStore; 
  20.     //連接的數據庫名字 
  21.     private final StoreConfig config =  
  22.                              StoreConfig.newDefaultConfig("AndroidVideoCache.db"); 
  23.  
  24. //數據庫get指令,通過URL獲取SourceInfo  
  25. public SourceInfo get(String url) { 
  26.     checkNotNull(url); 
  27.     ResultSet cursor = null
  28.     try{ 
  29.         RdbPredicates predicates = new RdbPredicates(TABLE); 
  30.         predicates.equalTo(COLUMN_URL, url); 
  31.         cursor = this.myRdbStore.query(predicates, null); 
  32.         return cursor == null || !cursor.goToFirstRow() ? null : convert(cursor); 
  33.     } finally { 
  34.         if (cursor != null) { 
  35.             cursor.close(); 
  36.         } 
  37.     } 
  38. //數據庫put指令,將url和SourceInfo在數據庫中登記綁定  
  39. public void put(String url, SourceInfo sourceInfo) { 
  40.     checkAllNotNull(url, sourceInfo); 
  41.     SourceInfo sourceInfoFromDb = get(url); 
  42.     boolean exist = sourceInfoFromDb != null
  43.     RdbPredicates predicates = new RdbPredicates(TABLE); 
  44.     if (exist) { 
  45.         predicates.contains(COLUMN_URL, url); 
  46.         this.myRdbStore.update(convert(sourceInfo), predicates); 
  47.     } else { 
  48.         this.myRdbStore.insert(TABLEconvert(sourceInfo)); 
  49.     } 
  50. //release指令:釋放數據庫控制流 
  51. @Override 
  52. public void release() { 
  53.     this.myRdbStore.close(); 

五、主功能文件

這部分文件主要用于整合上述四個部分的功能,向外部提供VideoCache接口。

主要功能類如下圖所示,他們的外部調用方法在Sample中已經詳細說明,主要使用到的就是HttpProxyCacheServer類,下面對其內部實現進行詳細的講解。

圖10主要功能類主文件

1、構造函數

在構造函數中主要進行了全局變量的初始化和對PROXY_HOST(VideoCache代理接口,也就是LocalURL所屬的代理接口)進行訪問,判斷是否可以直接ping通。

  1. private HttpProxyCacheServer(Config config) { 
  2.     this.config = checkNotNull(config); 
  3.     try { 
  4.     //初始化各種全局變量 
  5.         InetAddress inetAddress = InetAddress.getByName(PROXY_HOST); 
  6.         this.serverSocket = new ServerSocket(0, 8, inetAddress); 
  7.         this.port = serverSocket.getLocalPort(); 
  8.         IgnoreHostProxySelector.install(PROXY_HOST, port); 
  9.         CountDownLatch startSignal = new CountDownLatch(1); 
  10.         this.waitConnectionThread = new Thread(new WaitRequestsRunnable(startSignal)); 
  11.         this.waitConnectionThread.start(); 
  12.         startSignal.await(); // freeze thread, wait for server starts 
  13.     //獲取對PROXY_HOST& port的ping,判斷是否可以ping通 
  14.         this.pinger = new Pinger(PROXY_HOST, port); 
  15.         LOG.info("Proxy cache server started. Is it alive? " + isAlive()); 
  16.     } catch (IOException | InterruptedException e) { 
  17.         socketProcessor.shutdown(); 
  18.         throw new IllegalStateException("Error starting local proxy server", e); 
  19.     } 

2、registerCacheListener函數

這個函數主要實現的功能是對URL進行注冊監聽。

  1. public void registerCacheListener(CacheListener cacheListener, String url) { 
  2.     checkAllNotNull(cacheListener, url); 
  3.     synchronized (clientsLock) { 
  4.         try { 
  5.       //對url獲取Clients,并為其注冊CacheListener 
  6.             getClients(url).registerCacheListener(cacheListener); 
  7.         } catch (ProxyCacheException e) { 
  8.             LOG.warn("Error registering cache listener", e); 
  9.         } 
  10.     } 

3、getProxyUrl函數

該函數實現了將(已經注冊過的)URL轉化為cached LocalURL的功能。

  1. public String getProxyUrl(String url) { 
  2.     return getProxyUrl(url, true); 
  3.  
  4. public String getProxyUrl(String url, boolean allowCachedFileUri) { 
  5.     if (allowCachedFileUri && isCached(url)) { 
  6.         File cacheFile = getCacheFile(url); 
  7.         touchFileSafely(cacheFile); 
  8.         return Uri.getUriFromFile(cacheFile).toString(); 
  9.     } 
  10.     return isAlive() ? appendToProxyUrl(url) : url; 

當傳入一個網絡視頻的URL時,該方法會對該URL進行判斷,如果可以在代理服務器上進行緩存,則提供正確的LocalURL返回值,否則返回原URL。

項目貢獻人

呂澤 鄭森文 朱偉 陳美汝 張馨心

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2021-04-29 14:32:24

鴻蒙HarmonyOS應用

2021-03-10 15:03:40

鴻蒙HarmonyOS應用

2021-08-03 10:07:41

鴻蒙HarmonyOS應用

2021-03-03 09:42:26

鴻蒙HarmonyOS圖片裁剪

2021-03-01 14:00:11

鴻蒙HarmonyOS應用

2021-11-17 15:37:43

鴻蒙HarmonyOS應用

2021-08-26 16:07:46

鴻蒙HarmonyOS應用

2021-07-06 18:21:31

鴻蒙HarmonyOS應用

2021-04-08 14:57:52

鴻蒙HarmonyOS應用

2021-08-30 17:55:58

鴻蒙HarmonyOS應用

2021-08-05 15:06:30

鴻蒙HarmonyOS應用

2021-04-20 15:06:42

鴻蒙HarmonyOS應用

2021-01-27 10:04:46

鴻蒙HarmonyOS動畫

2021-08-10 15:23:08

鴻蒙HarmonyOS應用

2021-10-19 10:04:51

鴻蒙HarmonyOS應用

2021-07-20 15:20:40

鴻蒙HarmonyOS應用

2021-04-15 17:47:38

鴻蒙HarmonyOS應用

2021-03-12 16:35:33

鴻蒙HarmonyOS應用

2021-06-17 14:56:00

鴻蒙HarmonyOS應用

2021-11-02 14:54:21

鴻蒙HarmonyOS應用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91精品国产综合久久久久久丝袜 | 9999国产精品欧美久久久久久 | 五月激情婷婷网 | 国产人久久人人人人爽 | 精品伊人 | 国产精品久久久久久久久久久久午夜片 | 成年人国产在线观看 | 免费成人在线网 | 国产在线精品一区二区三区 | 成人精品久久久 | av无遮挡| 黄色网址免费在线观看 | 精品成人69xx.xyz | 精品av | 成人在线免费观看视频 | 91精品国产欧美一区二区成人 | 国产精品一区二区三区免费观看 | 日本一区二区三区精品视频 | 精品视频在线免费观看 | 欧美精品一区二区在线观看 | 欧美久久久网站 | 综合亚洲视频 | 久久精品国产免费高清 | 国产一区二区三区免费 | 久久色视频 | 午夜在线 | 九九热这里只有精品在线观看 | 亚洲欧洲av在线 | 福利视频网 | 91一区| 亚洲精品一区二区三区免 | 欧美日韩国产精品激情在线播放 | 一级高清视频 | 自拍偷拍在线视频 | 一区二区三区四区在线视频 | 久久精品中文字幕 | 久久久久久久久99精品 | 国产99久久 | 久久精品二区亚洲w码 | 欧美国产一区二区三区 | 视频一区二区中文字幕 |