Media Thumbnails

From BlackBerryDev

Jump to: navigation, search

Sometimes, your application may need thumbnails for media files stored on the device. This is a less common need with the FilePicker API that has built-in thumbnail support in 6.0, we still need to support older OSes and additional use cases. The BlackBerry OS does use a variety of methods to actually generate and cache its own thumbnails in the background. While officially undocumented, these cache files can usually be accessed by your application. This page will attempt to describe the cache files that have been discovered.

SQLite DB files

These have been found on OS 6 and OS 7, in the following locations:

file:///SDCard/BlackBerry/system/media/
file:///store/system/media/
    musicart.dat
    podcastart.dat
    videoart.dat

The schema for these files is fairly straightforward, and appears to have remained the same from OS 6 onward. As an example, here's the schema for videoart.dat:

CREATE TABLE Video_Art (
    id INTEGER PRIMARY KEY,
    source INTEGER,
    thumbnail BLOB,
    video_name TEXT,
    time_stamp INTEGER,
    source_time_stamp INTEGER);
CREATE TABLE Video_Art_Availability (
    id INTEGER PRIMARY KEY,
    available INTEGER);
CREATE TABLE Video_Art_Collides (
    id INTEGER,
    source,
    thumbnail BLOB,
    video_name TEXT PRIMARY KEY,
    time_stamp INTEGER,
    source_time_stamp INTEGER,
    available INTEGER);
CREATE TABLE Video_Art_Version (
    version INTEGER PRIMARY KEY,
    thumbnail_width INTEGER,
    thumbnail_height INTEGER,
    jpeg_encoding_quality INTEGER);
CREATE INDEX Video_Art_Collides_ID_Index ON Video_Art_Collides(id ASC);

Most of these tables seem to be blank, except for Video_Art and Video_Art_Availability. The most interesting table is Video_Art, whose columns have been seen to contain the following:

  • id - Number that appears to be used a s across-reference with the other tables
  • source - Not sure of meaning, was "2" in the files inspected
  • thumbnail - JPEG data that can be read out and parsed with EncodedImage.createEncodedImage()
  • video_name - Full file URL to the media file
  • time_stamp - Last modified timestamp of the media file
  • source_time_stamp - Duration of the video; divide by 100 to get seconds

Here is a very simple sample method to read a thumbnail from the database:

public static EncodedImage getThumbnailImage(String fileUrl) {
    EncodedImage image;
    try {
        URI uri = URI.create("file:///SDCard/BlackBerry/system/media/videoart.dat");
        Database db = DatabaseFactory.open(uri, true);
        Statement statement = db.createStatement(
            "SELECT thumbnail FROM Video_Art WHERE video_name = '" + fileUrl + "'");
        statement.prepare();
        Cursor cursor = statement.getCursor();
        while (cursor.next()) {
            Row row = cursor.getRow();
            byte[] blob = row.getBlobBytes(0);
            image = EncodedImage.createEncodedImage(blob, 0, blob.length);
            break;
        }
        cursor.close();
        statement.close();
    } catch (Exception e) {
        System.err.println("Error: " + e.toString());
    }
    return image;
}

BBThumbs.dat

This file has been found on most of BlackBerry OS versions, often in the same directory as the media files it describes. It is discussed in various blog posts and forum threads, such as this forum thread. Unfortunately, most of these posts take a rather crude brute-force approach to looking for image data within the file. Thankfully, I've actually managed to completely analyze and document this format, and now fully understand its structure and most of its contents.

On OS 5 and up, these files only appear to contain media metadata. On older OSes, they far more lazily created (often only when the media viewer is opened), and also contains picture thumbnails. However, understanding this format is still useful if you want to create a video or audio browser that can efficiently display file information. Thankfully, the contents of these files do appear to be created with the data formats of DataOutputStream, so you can quite easily build a parser using the methods from DataInputStream.

The actual structure of the files begin with a standard series of header bytes, followed by per-file entries that are simply appended as the OS parses new media files. It is best to parse the file linearly, until reaching the end of the file. The format is as follows:

  • Header: 0x24, 0x05, 0x20, 0x03, 0x08
    • Read with read(byte[5])
    • Always appears to be the same byte sequence
  • Entry
    • Start byte: 0x01 (readByte())
    • Filename (readUTF())
    • Last modified timestamp (readLong())
    • Time adjustment (readInt())
    • Entry data size (readInt())
    • Entry data (can read to a byte[] and parse separately, just to be safe)
      • Field
        • Field ID (readInt)
        • Field length (readInt())
        • Field data (as many bytes as specified above)
      • Next field
      • . . .
      • Footer: 0xFF, 0x00, 0x00, 0x00
  • Next entry
  • . . .
  • End-of-file


Within this structure, the following fields have been identified:

ID Type Description
0x00 byte[] Thumbnail (EncodedImage)
0x01 String Title
0x02 long Duration
0x03 String Artists
0x04 String Album name
0x05 String Genre
0x06 String Track
0x09 int Image width
0x0A int Image height
0x10 int Thumbnail width
0x11 int Thumbnail height
0x0F int Media type (0 = Image, 2 = Audio, 3 = Video)
0x14 int Locale (Interpret with Locale.get(value))
0x15 int Does album art exist in the media file? (0 = false, 1 = true)
0x16 String Part of set

Note: Not all fields may be present for each entry

thumbs??x??.dat, thumbs??x??.key

These files are kept in the same directories as the SQLite databases mentioned above, and appear to exist on OS 5 and up. They are a completely binary format, which I haven't yet been able to figure out. What I do know is this:

  • The key file is very small, and contains offsets to records in the dat file.
  • The dat file is a sparse file, likely zero-padded in fixed size increments.
  • These files were likely written by some native thread, and do not have any evidence of Java's DataOutputStream formats in their design.
  • Each record in the dat file appears to have the following structure:
    • Header (5 bytes)
    • Path name length (integer, 4 bytes)
    • File name length (integer, 4 bytes)
    • Size of image data (integer, 4 bytes)
    • Unknown data (13 bytes)
    • File path and name, as a single string (length is a combination of the two above values)
    • JPEG data (length as above)
Personal tools