為Ubuntu設計快速縮略圖服務

jopen 9年前發布 | 16K 次閱讀 Ubuntu

最近,James HenstridgeXavi Garcia MenaMichi Henning 為 Ubuntu 和 Ubuntu Touch 實現了一個快速、可伸縮的縮略圖服務

簡介

手機和桌面應用都有很多場景需要使用縮略圖服務。同時,有許多媒體類型需要生成縮略圖,比如圖片、音樂、視頻等。為每種媒體類型設計獨立的 API 會增加開發成本,且生成這些縮略圖也需要消耗大量 CPU 資源,網絡傳輸縮略圖會消耗不少帶寬。本文主要介紹一種通用的縮略圖服務,它為開發者屏蔽了上述這些復雜內容,通過緩存等措施大大提升了縮略圖服務的性 能。

系統架構

為Ubuntu設計快速縮略圖服務

外部 API

縮略圖服務對外提供了三種 API。

  • QML API:通過注冊為 QQuickAsyncImageProvider 的提供者,使得調用者能夠通過傳入特定的 URI 和參數,獲取特定大小的本地或者遠程縮略圖文件
  • Qt API:提供了三個函數獲取特定類型的縮略圖

    </li>

  • QSharedPointer getThumbnail (QString const& filePath, QSize const& requestedSize);
  • QSharedPointer getAlbumArt (QString const& artist, QString const& album, QSize const& requestedSize);
  • QSharedPointer getArtistArt (QString const& artist, QString const& album, QSize const& requestedSize);
  • </ul>

    其中 getThumbnail 函數從本地媒體文件提取縮略圖,getAlbumArt 和 getArtistArt 函數從遠程圖片服務器獲取。這幾個函數返回的 Request 對象,提供 downloadFinished 信號,調用者可以連接該信號異步獲取縮略圖數據。

    • DBus API:縮略圖服務通過 DBus 注冊了兩個接口,分別為 com.canonical.ThumbnailerAdmin 和 com.canonical.Thumbnailer。前者提供了對緩存的操作和緩存狀態查詢,后者提供了 GetAlbumArt、GetArtistArt 和 GetThumbnail 三個函數,對應 Qt API 中的三個函數,獲取不同類型的縮略圖。

      </li> </ul>

      同時,縮略圖服務還提供了命令行工具thumbnailer-admin,是得能夠通過命令行操作上述兩個 DBus 接口。

      為了節省資源,DBus 接口由 DBus 服務啟動,在 30 秒空閑后關閉。

      圖片提取模塊

      圖片提取模塊包括圖中的音頻、視頻提取器,下載器和圖片提取器。

      音頻、視頻提取器使用 GStreamer 來解碼音頻和視頻文件。由于 GStreamer 自身的穩定性問題,部分解碼器可能會導致程序掛起失去響應,因此將和 GStreamer 交互部分單獨封裝成獨立的可執行程序vs-thumb。主服務通過管道的形式和它交互,很好的避免了因為解碼器崩潰導致的穩定性問題。

      下載器提供 download_album 和 download_artist 兩個異步函數,通過 Qt 的 QNetworkAccessManager 組件從 dash.ubuntu.com 下載圖片。

      圖片提取器使用圖片轉換模塊從本地圖片中提取縮略圖圖片。

      圖片縮放和轉換模塊

      圖片縮放和轉換模塊主要負責將圖片轉換和縮放成 JPEG 格式的最終圖片文件。該模塊使用 Gdk-Pixbuf 庫進行轉換。

      針對 JPEG 圖片,圖片縮放模塊會通過 libexif 庫試圖讀取圖片的 EXIF 信息。如果圖片的 EXIF 信息包含縮略圖,且該縮略圖的大小不小于目標縮略圖大小,則圖片縮放模塊會使用 EXIF 中的縮略圖進行縮放,以提高性能。

      磁盤緩存模塊

      磁盤緩存包括三部分,全尺寸圖片緩存、縮略圖緩存、失敗緩存。

      • 全尺寸緩存:主要保存從遠程圖片服務器獲取的圖片和從音頻、視頻文件中提取的圖片。由于這些來源的圖片獲取成本比較高,這些圖片以原始尺寸進行保 存。默認該緩存大小為 50MB,采用最近最少使用方式進行替換,可以通過修改 data/com.canonical.Unity.Thumbnailer.gschema.xml 文件中的 full-size-cache-size 節點數據來重新設置緩存大小。
      • 縮略圖緩存:保存為調用者生成的指定尺寸的縮略圖。該緩存大小默認為 100MB,同樣可以通過修改 thumbnail-cache-size 節點數據來重新設置縮略圖緩存大小。
      • 失敗緩存:保存由于異常導致縮略圖提取失敗的項。對于遠程文件,可能是因為無法獲取遠程文件(文件不存在、授權失敗等);對于本地文件,可能是因 為文件損壞或者音頻文件不包含插圖等。失敗緩存主要用于減少對已知錯誤的重復嘗試,對于該緩存中的內容,采用最近最少使用和指定過期時間的方式控制緩存失 效。
      • </ul>

        由于使用了三個緩存,縮略圖服務在返回指定大小縮略圖時的查找流程大致為:

        1. 檢查縮略圖緩存中是否已經存在指定大小的圖片。如果存在則直接返回。
        2. 檢查全尺寸緩存中是否有該圖片的全尺寸副本。如果存在則使用全尺寸圖片進行縮放,將縮放完成的縮略圖添加到縮略圖緩存后返回。
        3. 檢查失敗緩存中是否有對應的項,如果有則直接返回錯誤。
        4. 嘗試從遠程下載或者從原始文件提取縮略圖。如果失敗,則加入到失敗緩存中,并返回錯誤。
        5. 如果原始文件是從遠程下載,或者從音頻、視頻流中提取,將源文件加入到全尺寸緩存中。
        6. 縮放圖片文件到指定大小,加入到縮略圖緩存中,并返回。
        7. </ol>

          性能提升

          縮略圖服務的主要耗時在基于網絡的下載和基于 CPU 的圖片提取。因此對性能的提升,主要考慮在網絡 IO 和 CPU 利用率上。為了避免這兩個耗時的操作阻塞其他請求,特別是能夠可以從緩存模塊中快速響應的請求,下載和圖片抽取被放在獨立的事件循環中,利用 Qt 的信號和槽機制,將耗時請求異步化。

          對于緩存的測試,使用配置為 Intel Ivy Bridge i7-3770k 3.5 GHz 處理器和 256GB 固態硬盤的機器,測試數據為使用 60 字節長度字符串作為鍵,使用平均大小為 20KB 的隨機二進制數據作為值,緩存大小為 100MB。

          緩存寫入時間為大約 2.8 秒,然后測試場景為 80% 的緩存命中率,當緩存未命中時,在緩存中插入新的數據,觸發緩存按照最近最少使用模式進行數據替換。在 10 萬次循環中,緩存每秒返回約 4800 個“快照”,聚合讀寫吞吐率在每秒 93MB。如果將緩存命中率提升到 90%,每秒返回的記錄數接近翻倍,達到了每秒 7100 條記錄。[1]

          總結

          縮略圖服務中的每個模塊都有清晰的接口定義。支持新的媒體類型或者新的遠程圖片服務擴展非常容易,不會影響到現有代碼。

          為了盡可能的利用硬件資源,縮略圖服務在針對長時間操作的異步接口使用了多線程的方式,提高系統 IO 利用率。

          縮略圖服務目前使用在 Ubuntu Touch 系統上,為圖庫、相機、音樂和其他使用媒體縮略圖的應用提供縮略圖服務。

          來自: InfoQ
           本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
           轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
           本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!