Archive:Dev:File and Content Interfaces
![]() |
![]() |
![]() |
As part of the present database redesign, I decided to examine more of a "top down" view of the world, and from there extrapolate what the database should look like. What would the ideal interfaces between the file and content management parts of XBMC, and the rest of the application, look like? There are some primary requirements for these interfaces:
- They should hide the implementation; e.g., clients (other parts of the code) shouldn't need to know a database is involved.
- They should be convenient to C++ developers first, not to the underlying implementation.
- They should not make it difficult for multiple varied implementations to exist.
These interfaces should be generally applicable to content in general but will be discussed with respect to videos (movies, TV show episodes, and music videos) in this outline.
The most important view of videos is as content, not as files, thus consideration starts there.
As content, there are a few primary ("static" or well-known) collections; every imported (scanned) video must belong to one of them; these are "Movies", "TV Shows", and "Music Videos". These can appear as static menu items. When selected, they have to be able to fetch a list of their contents, thus the first interface of interest is:
Collection *GetCollection(const string &sName, unsigned idParent = 0); Collection *GetCollection(unsigned id); Collection // pseudo-code – these will have accessors as necessary { uint id; uint idParent; // 0 if top-level string sName; // possibly localized string sDescription; iterator<Collection> GetChildren() const; iterator<Content> GetContent(SortOrder so = soName) const; }
Well-known collections may have well-known IDs, or just be fetched by name (since the parent and the name will be unique, implying that top-level names are also unique).
Collections do not necessarily need to live in a database table. For now, they're just an interface to something that can contain content and other collections. A virtual "Genre" collection could exist whose children are collections that are names of genres, which contain content belonging to that genre, generated by (if the present database schema were used) queries to the genre, genrelinkmovie, and movie tables. Also, each current plugin can be represented as a collection object, probably a child of a well-known "Plug-ins" top-level node. A content item belongs to one primary collection, and may also belong to multiple secondary collections (it can also be helpful to think of them as classifications).
A content item (recall this particular document is slanted towards video content) has the following interface; first we describe images, which are linked from content:
Image { uint id; uint nWidth; // 0 if unknown uint nHeight; // " File GetPreview(); File GetImage(); }
Content { uint id; uint idCollection; // primary collection; every content item must have one string sName; string sPlot; string sPlotSummary; string sTagline; int nVotes; float flScore; date dtReleased; int nRuntime; string sRating; string sOriginalTitle; // non-localized string sTrailerUrl; int nSeasion; // only valid for TV shows int nEpisode; // only valid for TV shows date dtAdded; iterator<Image> GetImages(ImgType imgt = imgtThumb | imgtFanart); bool SetPrimaryImage(Image img); bool Refresh(); // refresh data from online source File GetMedia(); // fetch seekable steam object for playing }
These somewhat reflect the tables in the Database Schema 4.0a page, but not entirely. For example, refreshing content data from online – Content::Refresh – would need some information to know where to re-fetch the data from, but that information (onlineSource in the content table) is not part of the public API. The object stores the URL of the original scrape, and uses it when a refresh is requested.
Types were genericized. It's safe to assume that ‘string' means ‘CStdString' in Kodi context, and date could be internally a integer Unix-style time representation, exposed as a date object. Furthermore, the idea is that the object either exposes accessors and mutators (date Content::GetDate() const, etc.) or a general accessor that returns a const struct (perhaps a CVideoInfoTag).
There is also no mention of a file. In the general sense, a file is a seekable "stream"; content items must have a file, or stream, or source from which they can be played: but some streams might exist only on-demand (items from a web page), and some stacked content items may have multiple on-disk files. Content::GetMedia should provide a single stream that can be accessed by the media player, even though it might encapsulate multiple on-disk files. (The idea is somewhat like the current FileItem, but with a lot less baggage.)
The file interface:
Path { uint id; // 0 if top-level string sPath; iterator<Path|File> GetContent(); }
File { Path path; string sName; uint cbSize; bool Seek(uint ibOffset); uint Read(void *pv, uint cb); }
Sometimes it may be necessary to break the abstraction and actually copy the file to disk, if a media player needs a disk file to read from; methods could be added to materialize the file (using the real file if it is one, or a temporary file otherwise).
it might be overridden by a class for video files, which would provide more information about the video and its streams (in the sense of encoded data streams, i.e., the present streamdetails table).
- This document is incomplete; further work to come.