This is subpage of MCF-specification.
Progress: 93%
Track-types | ||
---|---|---|
ID | Name | Description |
0x00 | Control | Control-codes for menus and other stuff |
0x01 | Video | Rectangle-shaped non-transparent pictures aka video |
0x02 | Audio | Anything you can hear |
0x03 | AV | Audio and video in same track, used by DV |
0x04 | Multi-track audio | More than one audio-track in one stream |
0x10 | Titles | Overlay-pictures, displayed over video |
0x11 | Subtitles | Text-subtitles. One track contains one language and only one track can be active (player-side configuration) |
0xFF | Custom | For really custom extensions, try to avoid using this |
Most offsets are relative to the start of the Track Entry.
Work in progress.
Used for DVD-like menusystems, switching tracks automatically, etc.. This can be abused, so there should be an option in all players for disabling control-codes. Your UI must be more or less multitasking - control-track might get stuck in an infinite loop, but this must not affect player's user-interface. Content in MCF-files should never steal focus from other parts of the UI, or other applications, either. Menues can be used with three buttons - up, down and enter. Addiotionally we support left/right, or alternatively some kind of pointing-device (mouse).
Oh, if you feel that you can't support menues in your player, feel free to drop the feature - no support is better than half support. Other controls of TOP-atom shouldn't be too difficult to implement.
Menu can display two alpha-equiped PNGs simultaneusly, blended with each other and then blended with other tracks (usually video, sometimes subtitles). The blending order depends on the order of Track Entries - Tracks with smaller Track Numbers are bottom.
Unlike elsewhere, here we have hierarchical structure. This allows interleaving PNG-images with commands, looping structures, etc. It also wastes some space, but because control-blocks are rare, this is acceptable. Developers familiar with QuickTime will feel like home when working with these :) ..
Structure of an atom | ||
---|---|---|
Offset | Player | Description |
0x00 | must | Size of data in this atom (uint32) |
0x04 | must | Command (4 octets) |
0x08- | must | Data |
Control-block may contain one or more TOP-atoms. Keep reading more atoms you reach the size of the block. If a command is unknown, the atom should be skipped (and if there is no else-command right after the failing atom, a warning passed to the user). Currently we don't have any commands reserved for user-extensions - and we probably won't ever have.
When there are atoms inside an atom, keep reading those sub-atoms until you reach the size of data in current atom.
Atoms which are too big the fit in the space reserved for them should result to giving an error and aborting. 0-sized atoms are OK - they just don't contain any data.
Command instructs the parser of what data the atom contains - it can be pure data for the command, or a set of atoms, or both.
Commands for TOP-atom | ||
---|---|---|
Command | Name | Data contents |
"Jump" | Seek to timecode | Timecode (uint32) |
"IfEd" | If edition | Edition number (uint8) TOP-atom(s) |
"ChEd" | Change edition | Edition number (uint8) |
"Enab" | Enable track | Track number (uint8) Sub-track (0 = all) (uint8) |
"Disa" | Disable track | Track number (uint8) Sub-track (0 = all) (uint8) |
"Quit" | Quit playing | Should stop the movie; player may or may not terminate itself |
"Menu" | Define a menu | MENU-atom(s) |
"AltO" | Alternative option | TOP-atom(s) |
"Link" | Use another TOP-atom | Position (relative to start of this block) of the TOP-atom to use (uint32) |
If edition: only executes its TOP-atom(s) if the edition given as parameter is selected. Used for jumping, so that edits can be non-linear in the original material.
Alternative option: if command supplied for previous atom wasn't supported, execute this one instead. Currently the only sensible use for this is after a TOP-atom using Menu-command - to define a jump to start of the actual movie, skipping menu-graphics.
If you switch tracks, disable the old track first and then enable the new one. Sub-tracks are only used for audio-tracks containing multiple languages, but this might change in future. For tracks without sub-tracks, set it to 0.
It is recommended to do all Jumping at silent fade-downs (when the screen is black and there is no audio), so that the pause caused by seeking isn't too noticeable. Good players should be able to cache, so that there is no pause, but you can't rely on that.
Link-command can be used for moving back from deeper menu-levels.
Commands for MENU-atom | ||
---|---|---|
Command | Name | Data contents |
"Stop" | Pause | - |
"Loop" | Loop | Time (duration), in milliseconds (uint8) |
"Pict" | Display picture | Size (including titles-header) (uint32) Flags (bits 7-5 defined below, 4-0 from titles-header) Size of titles-header (consult titles-track specs for correct value) (uint16) Block of type 0x10 (titles) |
"Tout" | Timeout | Timeout, in milliseconds (uint32) TOP-atom(s) (what to do when timeout occurs) |
"Area" | Define entry of menu | AREA-atom(s) |
Pause-command pauses playback (a still-screen menu). Loop is alternative - it continues playback normally, but loops back to the block right after this control-block, when the time passes. Blocks with timecode exactly at the end of a loop won't be played. Blocks with the same timecode as this block-entry, but AFTER this block, will get played in a loop. If neither of those commands (pause or loop) is defined, playback continues normally to the end of movie or some other event. If user hasn't touched any controls for timeout milliseconds, the menu is disabled and player seeks to the position defined. Defining both pause and loop is illegal and should lead to a warning and discarding this control-block.
AREA-atom defines a single menu-entry (area it uses on screen, mouseover-pics, what to do when it gets selected, ..).
Commands for AREA-atom | ||
---|---|---|
Command | Name | Data contents |
"Shap" | Define area | SHAPE-atom(s) |
"Left" | - | Number of the AREA to left from this one (uint8) |
"Hili" | Hilight | HILI-atom(s) |
"Acti" | Action on select | TOP-atom(s) |
Areas are given sequential numbers, starting from 1, in defining-order. Each control-block has distinct numbering. Left-command is used for defining where to jump when left cursor-key is pressed while hilight is on this area.
Shapes are defined to allow making selections with mouse or other pointing-devices. Shapes aren't drawn on screen.
Commands for SHAPE-atom | ||
---|---|---|
Command | Name | Data contents |
"Rect" | Rectangular | X1, Y1, X2, Y2 (uint16, uint16, uint16, uint16) |
"Poly" | Polygon | X1, Y1; X2, Y2; .. (number of points determined by the size of atom) (uint16, uint16) |
"Circ" | Circle | X and Y of center (uint16, uint16) Radius (uint16) |
Coordinates are "percentages" of canvas height and width - 0 = left/top, 0xFFFF = right/bottom. Radius is percentage of canvas diameter (0xFFFF = sqrt(width^2 + height^2)).
Hilight activates when mouse is over the area defined by SHAPE-atoms, or when cursor-keys are used to select the item.
Commands for HILI-atom | ||
---|---|---|
Command | Name | Data contents |
"Pict" | Display picture | Size (including titles-header) (uint32) Size of titles-header (consult titles-track specs for correct value) (uint16) Flags (bits 7-3 defined below, 4-0 from titles-header) Block of type 0x10 (titles) |
"Soun" | Play a sound | Not implemented yet |
"Link" | Use media from another HILI | Position of the HILI-atom to use, relative to start of this control-block (uint32) |
When hilight is moved out, the picture used for hilighting must be cleared (but menu-picture, if any, should stay).
Flags in Block Header | ||
---|---|---|
Bit | Player | Description |
7 | must | Top - for HILI-atom's Pict-command (not meaningful for MENU-atom's Pict-command) |
6-5 | - | Reserved, set to 0 |
4-0 | - | From titles-track |
If top-flag is enabled, the image is painted on top of the menu-image (if any). Otherwise it goes under the menu-image.
There is a HTML-diagram (a draft) of a menusystem: complex menu
Work in progress: this is likely to change!
Track-type specific setting in Track Entry @0x180 | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Offset | Player | Description | ||||||||||||||||||
0x180 | - |
| ||||||||||||||||||
0x181 | - | Reserved (set to 0x00) | ||||||||||||||||||
0x182 | must | X-dimension (uint16) If unknown, should be set to 0 | ||||||||||||||||||
0x184 | must | Y-dimension (uint16) If unknown, should be set to 0 | ||||||||||||||||||
0x186 | must |
Aspect-ratio, X:1000 (uint16) =width of the video-window if the height is 1000 units. Examples:
| ||||||||||||||||||
0x188 | must | FourCC (for compatibility, check AVI-specs for more info, 0x00000000 if not available) | ||||||||||||||||||
0x18C | feat. | Colorspace (4 octets, same as in AVI) | ||||||||||||||||||
0x190 | feat. | GUID subtype, used by M$ DirectShow codecs (16 octets, fill with 0x00 if not available) | ||||||||||||||||||
0x1A0 | must | Gamma value (uint8) | ||||||||||||||||||
0x1A1- | - | Reserved (fill with 0x00) |
Dimensions (0x182-0x186) (most people call it resolution) are not always present: there can vector/wave formats, where compression doesn't work in per-pixel basis, so the actual decompression resolution must be negotiated with the codec. For interlaced video: field, not full frame, dimensions are used.
Constant framerate value should only be used for converting MCF to AVI or other non-variable framerate format. The format it is stored here might change (if you want it to change, please let me know). One converting to AVI should check that CFR-flag is set and that the "nanoseconds per frame"-value is valid. Anyway, when writing MCF, please include this field with any CBR-material. Dropped frames are allowed and converter should use timecodes to find out when one occurs.
Gamma-field contains the actual gamma-value multiplied by 100; 100 means 1.00 gamma, 45 means 0.45 gamma. Video encoded on PC usually has a gamma of 0.45 (CRT-monitors usually have a gamma of 2.2). Note: 0.45*2.2=1. Gamma correction is done seperately for each channel of R/G/B. The formula is: output = input^(file_gamma * display_gamma). Display-gamma is player-side option. On PC you should default to 2.2, but let user configure it. If file_gamma * display_gamma is very close to 1.0, you can optimize by not doing gamma-correction. More info about gamma here: http://libpng.org/pub/png/spec/PNG-GammaAppendix.html
We don't have color-correction yet - if you think that it should already be defined (it should be fast enough to calculate for each pixel!), drop an e-mail with your suggestions. Optional way would be letting hardware (display-card) do the correction.
For interlaced video: If bit 6 in FLAGS of a Block Header is set, the block contains EVEN scanlines (odd scanlines otherwise).
Some formats (Vorbis, for example) can contain up to 256 channels in one stream. One audio-track of MCF contains one stream, but may contain many languages, each with many channels (2 for stereo, ..). We require that each language has same number of channels and same properties (samplerate, bitdepth, ..) for each channel.
Track-type specific setting in Track Entry @0x180 | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Offset | Player | Description | |||||||||||||||
0x180 | must | Samplerate, in mHz (uint32, 0=unknown/variable) | |||||||||||||||
0x184 | must | Bitdepth (uint8) (not required for all audio-formats) | |||||||||||||||
0x185 | - |
| |||||||||||||||
0x186 | must | Number of subtracks (languages) in this track (uint8) | |||||||||||||||
0x187 | must | Number of PCM audio channels per subtrack (uint8) | |||||||||||||||
0x188 | must | AVI-compatibility: wFormatTag (from waveformatex) (0x0000 if not available) (uint16) | |||||||||||||||
0x190 | must | Channel positioning (uint32) | |||||||||||||||
0x190- | - | Reserved (fill with 0x00) |
Set the number of PCM-channels to 0, if not applicable. Number of subtracks cannot be 0. If you only have one, set it to 1. If you are uncertain about something, ask it on the MCF-Devel mailing-list (at SourceForge).
If secondary track flag is set, selecting this track shouldn't deselect any primary-track, but mix sounds of those together.
Each language must be described in Codec Header, in a chunk called SubTrack Entry. The actual Codec Header, if any, comes right after these subTrack Entries.
SubTrack Entry (80 octets) | ||
---|---|---|
Offset | Player | Description |
0x00 | must | Name (language) of the subtrack (64 octets) |
0x40 | info | ISRC-code (http://www.riaa.org/Audio-Standards-3.cfm) (fill with 0x00 if not available) (12 octets ASCII) |
0x4C- | - | Reserved (fill with 0x00) |
The normal situation is that you have one subtrack, with two channels.
I need help with this one. Any volunteers? It should be able to contain DV and other formats, which might or might not contain headers in the stream. As stated before, this track contains audio and video compressed together (ie. we can't just demux it nicely).
Overlay-pictures (PNG) over video. Pictures can have alpha-channel. Try NOT to use this for subtitles.
I am not going to allow any other formats than PNG for this because it is the best alternative for titles and good enough even for photos and it is free. After all, it is much easier to only support one format. Later, when there is another good format (free, lossy, with alpha-support) around, we'll support it too.
Set 0x010 in Track Entry (compression format) to "PNG". Players must ignore titles-tracks with any other values in that field.
Track-type specific settings in Track Entry @0x180 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Offset | Player | Description | ||||||||||||
0x180 | must | Size of titles-header (set to 16) (uint16) | ||||||||||||
0x182 | must | Canvas X-size (uint16) | ||||||||||||
0x184 | must | Canvas Y-size (uint16) | ||||||||||||
0x186 | - |
| ||||||||||||
0x187- | - | Reserved (fill with 0x00) |
Canvas size only applies when there is no video enabled - if there is video, the canvas will be automatically set to match video. Size is given in pixels, but players and users can override this; only proportions (aspect-ratio) survive. One example of this would be user switching to full-screen: if canvas X-size was 200 and Y-size 100, there will be black bars over and under the canvas (unless she has a monitor with 2:1 aspect-ratio), but it is still sized to full-screen. If no size is defined here (which is the normal case), and there is no video, players should default to 1.778:1 canvas of any size (player-developers do the decision).
Titles Header | ||
---|---|---|
Offset | Player | Description |
0x00 | must | X1, Y1 (uint16, uint16) |
0x04 | must | X2, Y2 (uint16, uint16) |
0x08 | must | Fade-in time in milliseconds (uint16) |
0x0A | must | Fade-out time in milliseconds (uint16) |
0x0C | must | Flags |
The actual image (with PNG-headers) is at size_of_titles-header (ie. right after titles-header).
Fade-in and fade-out adjust transparency linearly from full to none and vice-versa. Set to 0, if not used. Duration is determined by gap-start value at the end of Block. If the Block doesn't start a gap, infinite duration is assumed and fade-out cannot be used.
Coordinates are percentage (per-uint16-age, actually) of canvas - 0=left/top, 0xFFFF=right/bottom. Canvas is normally same size as the video (not same size as the player window).
Flags in Titles Header | ||
---|---|---|
Bit | Player | Description |
4-3 | - | Reserved, set to 0 |
2 | feat. | Try to avoid scaling |
1 | feat. | Nearest neighbor scaling, instead of highest possible quality (bicubic) |
0 | feat. | Free positioning - instead of obeying X1 and Y1, player can freely position this image |
Nearest neighbor flag should only be used for images which look better that way, not for reducing CPU-load (which should be in player-side configuration instead, if applicable on the target-platform).
If you have a nice, absolutely sharp, image, which you want to display without scaling, enable "no scaling"-flag, but remember that the size of the image (compared to canvas) might vary. When the flag is enabled, player must calculate requested size (x2-x1, and convert it to number of pixels). n = (req_size + image_width/2)/image_width; n is integer and result of that calculation is always rounded down. Now, if n is 0, scale the image normally to exactly fit requested size. In other case (n >= 1), scale the image by n (each pixel gets duplicated to n2 pixels). NOTE: we only use X-size for computing n; we assume that Y-size is to be scaled with the same factor.
When doing free positioning, player should try to position over some empty space around the canvas and, if that is not possible, obey X1 and Y1. Preferrably players should, when deciding where exactly to put that image, try to get it as close to the coordinates as possible. In the sample-image we have "MCF"-logo in the normal position (on the canvas) and in free position, right outside the canvas. Notice that outside the canvas it is still horizontally aligned to where it would normally be. If it was in the lower part of the canvas instead, free positioning should move it to the black bar below the canvas.
Notes on using this for subtitles: Subtitles for average movie take around 1.4 Mo per language, when done with PNGs (3 colors: transparent, black and white). Same subtitles, when done correctly, in text-form, only take around 80 Ko per language. Also, when using images for subtitles, font, colors, etc. can't be changed by user. It is also worth noting that text-subtitles are much higher quality (anti-aliased scalable vector-fonts (true-type) versus bitmaps). So, don't use graphics for subtitles, okay?
If you still are going to use graphics, make sure you set Subtitles flag, so that players know to treat it as subtitles.
Set 0x010 in Track Entry (compression format) to "INTERNAL". We might also support some kind of compression for this, in which case 0x010 reflects the compression used.
Track-type specific settings in Track Entry @0x180 | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Offset | Player | Description | |||||||||||||||
0x180 | - |
| |||||||||||||||
0x181 | must | Character-set (currently 0=UTF8) (uint8) | |||||||||||||||
0x182 | must | Size of the subtitle-header, to allow extensions in future (currently 4) (uint16) | |||||||||||||||
0x184 | feat. | Color #1 (default) (RGB/8-8-8) | |||||||||||||||
0x187 | feat. | Color #2 (RGB/8-8-8) | |||||||||||||||
0x18A | feat. | Color #3 (RGB/8-8-8) | |||||||||||||||
0x18D | feat. | Color #4 (RGB/8-8-8) | |||||||||||||||
0x190- | - | Reserved (fill with 0x00) |
If a color is set to 0x000000, player default should be used instead. Don't define colors here unless you really want to override users'/players' settings. Note: players should allow overriding colors defined here.
Following is what each subtitle-block contains:
Subtitle Header | ||
---|---|---|
Offset | Player | Description |
0x00 | must | Flags (1 octet) |
Right after the header comes the actual subtitle.
Subtitles stay on screen until the next subtitle comes or file ends, unless a gap is defined (Block Header).
Subtitle should be top-aligned to the bottom of video, if possible (ie. watching wide-screen video on non-ws-monitor). If that is not possible, it should be bottom-aligned to bottom of video, unless bit 6 is enabled, in which case it should be top-aligned to top. User-configuration should be allowed to override this, of course.
Flags in Subtitle Header | ||
---|---|---|
Bit | Player | Description |
7 | feat. | Black non-transparent background |
6 | feat. | Top-align: important stuff in the lower part of video |
5 | feat. | Hearing-impaired only (don't display this subtitle for normally hearing people) |
4-0 | - | Reserved, set to 0 |
Normal word-wrapping is performed (except if the subtitle-track is preformatted). Only use non-transparent background when you need to (when there is something bright, which makes reading the subtitle difficult).
NOTE: if subtitle is not positioned on the canvas (ie. it is positioned in the black space below the canvas), top-align-flag can be disregarded.
Effects such as letter-borders and shadows are player-side stuff.
In the subtitle we have control-codes, which start with 0x00 (uint8). UTF8 doesn't use zeroes anywhere: all zeroes are our codes, not UTF8. After the zero there is another uint8, which is the actual command.
Control Codes | ||
---|---|---|
Code | Preferred color | Description |
0x00 | - | Longer command |
0x01 | #DDDDDD | Switch back to default color |
0x02 | #AAAAFF | Switch to 2nd color |
0x03 | #AAFFAA | Switch to 3rd color |
0x04 | #FFAAAA | Switch to 4th color |
0x05 | - | Enable bold text (usually subtitles are already bold, but this makes it very bold) |
0x06 | - | Enable underline |
0x07 | - | Enable italics |
0x08 | - | Disable underline/bold/italics (reset back to normal text, but doesn't reset color) |
0x0A | - | Force linefeed here |
Longer code is two zeroes followed by the number of octets (size) used by parameters, and then one octet for the code + size octets of something.
Long Control Codes | ||
---|---|---|
Full Code | Description | |
0x00 0x00 0x01 0x4B uint8:time | - | Karaoke timing. |
Players must be able to skip all unknown codes quietly. Example: "Normal subtitle", 0x00, 0x00, 0x07, 0x01, "Example", "Normal subtitle continues". There 0x01 is the action, 0x07 the size of parameters for that action and "Example" (7 octets) the parameter.
If player finds unknown codes, those must be ignored silently. All attributes (colors, bold, etc) reset to defaults on every subtitle.
Only use linefeeds when needed (ie. you want a new line at precise position, not when you want to cut a long line). Automatical word-wrapping will do better job. Don't ever use single attribute for all text of all subtitles.. In example, if you happen to like red color, just configure your player to use red for color 1, instead of using color 4 in your subtitles. If you think that others will also like red with the movie you are encoding, define color #1 in Track Entry to the shade of red you prefer.
Misuse of attributes leads to users disabling attributes in their players (like many have disabled JavaScript in their browsers).
All karaoke timing is based on the total display time of the subtitle. Time (uint8) is a percentage: 255 denotes total display time (100%), 0 denotes no time (0%). The karaoke code affects all the text in front of it.
In the following example, I use syntax [K:time], for human-readability.
[K:15%]This part is read fast[K:35%], and this part is read slowly.[K:85%]
The first code has no charactes in front of it, so it only causes a pause of 15%. All text remains white (default color) during that time. The next code says 35%, which applies to the text in front of it ("This part is read fast"). So, during the time from 15% to 35%, player gradually paints the text red (color #4). When 35% of total time has passed, the first half of it is painted red, and the other half still is white. The last code says 85%. When 85% of time has passed, all text should be red. That leaves a 15% pause until total display time is reached, and the subtitle is removed.
If a player doesn't support karaoke, it will just skip these codes, just like it skips other unknown codes, and the text will stay white for the whole displaying time.
White and red are preferred player-side defaults; different colors can be defined in Track Entry.
This is the "clean" way to add something that doesn't exist in current specs into MCF. Hopefully no-one will ever use this, but "just in case". If a custom track is not recognized by the software reading it, it will be skipped (well, the player should still inform user about it).
This track-type has special uses for some of those fixed Track Entry fields:
Special uses for normal Track Entry fields (when track-type=0xFF) | ||
---|---|---|
Offset | Player | Description |
0x010 | must | 16 bytes to identify your track. "3DSMAX anim" would be one option. Anyway, select anything you think no-one else will use. There are no standards about these, but 16 bytes should be enough for everybody, right? |
0x030 | info | Human-readable description of what the track does (64 octets) |
0x070 | info | URL for plugin needed for this track or some info about it (64 octets) |
0x0B0 | info | Another URL, if available (64 octets) |
Because this is really special track, there are no restrictions or standards in usage of that track-type-specific area (which starts at 0x180 in Track Entry). Blocks can naturally contain any data too.
Anyway, try to avoid this at all cost. Instead, contact MCF developers; so that we can add the feature (if it really is usable for someone else too). Even if it isn't usable for others, but you are going to distribute software that uses this track type for something, please let us know about it!