722 lines
56 KiB
HTML
722 lines
56 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Be Newsletters - Volume 5: 2000</title><link rel="stylesheet" href="be_newsletter.css" type="text/css" media="all" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="./images/favicon.ico" /><!--[if IE]>
|
||
<link rel="stylesheet" type="text/css" href="be_newsletter_ie.css" />
|
||
<![endif]--><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Be Newsletters" /><link rel="up" href="volume5.html" title="Volume 5: 2000" /><link rel="prev" href="Issue5-3.html" title="Issue 5-3, January 19, 2000" /><link rel="next" href="Issue5-5.html" title="Issue 5-5, February 2, 2000" /></head><body><div id="header"><div id="headerT"><div id="headerTL"><a accesskey="p" href="Issue5-3.html" title="Issue 5-3, January 19, 2000"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a accesskey="u" href="volume5.html" title="Volume 5: 2000"><img src="./images/navigation/up.png" alt="Up" /></a> <a accesskey="n" href="Issue5-5.html" title="Issue 5-5, February 2, 2000"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="headerTR"><div id="navigpeople"><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div><div class="navigboxed" id="naviglang" title="English">en</div></div><div id="headerTC">Be Newsletters - Volume 5: 2000</div></div><div id="headerB">Prev: <a href="Issue5-3.html">Issue 5-3, January 19, 2000</a> Up: <a href="volume5.html">Volume 5: 2000</a> Next: <a href="Issue5-5.html">Issue 5-5, February 2, 2000</a></div><hr /></div><div class="article"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Issue5-4"></a>Issue 5-4, January 26, 2000</h2></div></div></div><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Engineering5-4"></a>Be Engineering Insights: An Overview of Media File Formats and Codecs</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Dominic</span> <span class="surname">Giampaolo</span></span></div></div></div><div class="blockquote"><table border="0" cellspacing="0" cellpadding="0" class="blockquote" summary="Block quote"><tr><td width="90%" valign="top"><p>
|
||
“<span class="quote">The wonderful thing about standards is that there are so many to choose
|
||
from.</span>”</p></td><td width="5%" valign="top"> </td></tr><tr><td width="100%" colspan="2" align="right" valign="top">—</td></tr></table></div><p>
|
||
I can't think of a better way to introduce an article about "standard"
|
||
media file formats. In this article I'd like to provide a pretty detailed
|
||
description of the different file formats and codecs available for
|
||
storing audio and video data. I'll start with a high-level view of what
|
||
is going on and then drill down to the details. My hope is that this will
|
||
help people better understand what is happening when they read or write a
|
||
media file.
|
||
</p><p>
|
||
Before we begin though, let me state that you don't strictly need to know
|
||
any of this information. The <code class="classname">BMediaFile</code> and
|
||
<code class="classname">BMediaTrack</code> objects handle
|
||
all the grungy details for you. However, if you do know how media file
|
||
formats work, it may help you understand why the APIs were designed the
|
||
way they were and why they behave in certain ways.
|
||
</p><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id438938"></a>File Formats First</h3></div></div></div><p>
|
||
The first thing to understand is the difference between a "file format"
|
||
and a "codec." A file format is nothing more than a container to store
|
||
data. A file format contains additional information about the movie (such
|
||
as its size, the frame rate, etc.) but the file format does not typically
|
||
specify that the audio or video must be encoded in a specific way. A
|
||
codec, on the other hand, is a way of encoding audio or video data. How a
|
||
piece of data is encoded is (typically) not dependent on the file format
|
||
it's stored in.
|
||
</p><p>
|
||
As an example, consider an <acronym class="acronym">AVI</acronym> file. An <acronym class="acronym">AVI</acronym> file can store audio and
|
||
video encoded with numerous different encoders. Another way to say it is
|
||
that an <acronym class="acronym">AVI</acronym> file is a way to store audio and video in a file, but you can
|
||
encode that audio/video data any way you wish. Encoding audio or video
|
||
data transforms it from a very high- bandwidth stream of raw data into a
|
||
stream of compressed data. While you could do anything with a stream of
|
||
compressed data, it is typically stored in a common file format such as
|
||
<acronym class="acronym">AVI</acronym> or QuickTime.
|
||
</p><p>
|
||
The following table lists the media file formats that BeOS supports:
|
||
</p><div class="informaltable"><table border="1"><colgroup><col align="right" /><col align="left" /></colgroup><thead><tr><th align="right">File Format Name</th><th align="left">Type of Data Supported</th></tr></thead><tbody><tr><td align="right"><acronym class="acronym">AVI</acronym></td><td align="left">audio, video</td></tr><tr><td align="right">QuickTime</td><td align="left">audio, video, misc.</td></tr><tr><td align="right"><acronym class="acronym">MPEG</acronym> system stream</td><td align="left">audio, video, misc.</td></tr><tr><td align="right">DV stream</td><td align="left">audio, video</td></tr><tr><td align="right">AIFF</td><td align="left">audio</td></tr><tr><td align="right">8SVX</td><td align="left">audio</td></tr><tr><td align="right"><acronym class="acronym">WAV</acronym></td><td align="left">audio</td></tr><tr><td align="right">AVR</td><td align="left">audio</td></tr><tr><td align="right">AU</td><td align="left">audio</td></tr></tbody></table></div><p>
|
||
There are many other file formats (such as FLI/FLC, ASF, etc.) but
|
||
currently the BeOS does not support them.
|
||
</p><p>
|
||
Each of the file formats listed in the table (except for <acronym class="acronym">MPEG</acronym>) has a
|
||
similar structure, although each one uses its own terminology to describe
|
||
the specifics. The basic idea is that a file is made up of "chunks" of
|
||
data and if you don't understand a chunk you can skip over it. The way
|
||
this is typically done is with a 4-byte identifier to describe the type
|
||
of chunk and a 4-byte (or sometimes 8-byte) size. A diagram helps to
|
||
illustrate:
|
||
</p><pre class="screen">
|
||
file offset data
|
||
------------+---------------------+
|
||
0 | 0x000012b8 |
|
||
------------+---------------------+
|
||
4 | 'moov' (0x6d6f6f76) |
|
||
----------------------------------+
|
||
</pre><p>
|
||
This represents the first 8 bytes of a QuickTime file. QuickTime stores
|
||
its chunks with the size first and then the identifier (and as one would
|
||
expect, <acronym class="acronym">AVI</acronym> does it the opposite way). The identifier is known as a
|
||
"four-character code" or "fourcc." A fourcc is often a mnemonic or clever
|
||
name that makes it easy to identify when looking at a hex-dump of a file.
|
||
In this example the ASCII characters 'moov' have the value <code class="literal">0x6d6f6f76</code>
|
||
when treated as a 4-byte integer (on a big-endian system).
|
||
</p><p>
|
||
The size of this "moov" chunk is <code class="literal">0x12b8</code> bytes long (4792 in decimal).
|
||
Because we know the size, even if we don't know anything about a moov
|
||
chunk we can correctly skip over it and parse the next item (of course,
|
||
if you skip the moov chunk you won't be able to do very much!).
|
||
</p><p>
|
||
The concept of a chunk'ed file with an identifier and size for each chunk
|
||
is a simple but good way to store data that needs to be parsed by many
|
||
different types of programs. Having well-identified chunks and the
|
||
ability to skip over them if they are unknown makes for a robust file
|
||
format.
|
||
</p><p>
|
||
In addition to a linear series of chunks in a file, both QuickTime and
|
||
<acronym class="acronym">AVI</acronym> allow a chunk to contain other nested chunks. That is, certain chunk
|
||
identifiers indicate that the chunk is a container that has other chunks
|
||
within it. The size of a container chunk is the sum of all the chunks
|
||
inside it. For example, an <acronym class="acronym">AVI</acronym> file may contain a 'LIST' chunk that
|
||
contains other chunks. The size of the LIST chunk would allow you to skip
|
||
over it if you wanted. An example in a QuickTime file would be the 'trak'
|
||
chunk, which contains many other chunks that describe the media track.
|
||
</p><p>
|
||
To get a better feel for the layout of a file format I suggest that you
|
||
fire up DiskProbe and scan through some media files. You'll quickly see
|
||
how they're laid out. It's also helpful to have the file format spec
|
||
handy for serious perusal (a good source of specs is
|
||
<a class="ulink" href="http://www.wotsit.org/">http://www.wotsit.org/</a>, or just fire off a search on
|
||
<a class="ulink" href="http://www.google.com/">http://www.google.com/</a>).
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id439213"></a>The Other File Format (Mpeg)</h3></div></div></div><p>
|
||
The <acronym class="acronym">MPEG</acronym> file format is actually not one but three formats. You can have
|
||
a raw video stream, a raw audio stream, or a "system" stream (which mixes
|
||
multiple channels of audio and video together). The <acronym class="acronym">MPEG</acronym> file formats are
|
||
designed to be a continuous stream that you can start receiving and begin
|
||
decoding after you find a sync token. With streaming (or broadcasting if
|
||
you prefer) as a major design goal, <acronym class="acronym">MPEG</acronym> does not have many of the
|
||
features that other media file formats have.
|
||
</p><p>
|
||
The different <acronym class="acronym">MPEG</acronym> file formats all have some common deficiencies. The
|
||
first is that none of them have a good header identifier that is even
|
||
moderately unique. Instead, <acronym class="acronym">MPEG</acronym> files have header identifiers like <code class="literal">0x1ba</code>
|
||
(system stream), <code class="literal">0x1b3</code> (video stream), and <code class="literal">0xfff</code> (audio stream). These
|
||
values are atrocious identifiers because they are far too easy to
|
||
encounter in chunks of non-<acronym class="acronym">MPEG</acronym> data.
|
||
</p><p>
|
||
Next, the structure of <acronym class="acronym">MPEG</acronym> streams is tightly bit-packed and does not
|
||
lend itself well to easy parsing. For example, to extract the clock value
|
||
from a video stream, you have to do this:
|
||
</p><pre class="programlisting c">
|
||
<code class="varname">t</code> = ((((<span class="type">bigtime_t</span>)(<code class="varname">stream</code>[0] & 0x0e)) << 30) |
|
||
(((<span class="type">bigtime_t</span>)(<code class="varname">stream</code>[1] & 0xff)) << 22) |
|
||
(((<span class="type">bigtime_t</span>)(<code class="varname">stream</code>[2] & 0xfe)) << 15) |
|
||
(((<span class="type">bigtime_t</span>)(<code class="varname">stream</code>[3] & 0xff)) << 8) |
|
||
(((<span class="type">bigtime_t</span>)(<code class="varname">stream</code>[4] & 0xfe)) << 0));
|
||
</pre><p>
|
||
As Dave Bort would say: Crazy.
|
||
</p><p>
|
||
Another area that poses big problems when dealing with <acronym class="acronym">MPEG</acronym> is that a lot
|
||
of <acronym class="acronym">MPEG</acronym> data is not well formatted. There's what the spec says and then
|
||
there is what's done. This is the kind of problem you come to expect when
|
||
dealing with data files generated by lots of programs, but <acronym class="acronym">MPEG</acronym> seems to
|
||
have the problem in spades. The highly varied interpretations of what the
|
||
spec says make trying to parse <acronym class="acronym">MPEG</acronym> files an interesting job.
|
||
</p><p>
|
||
Getting beyond my childlike whining, <acronym class="acronym">MPEG</acronym> does have a notion of chunks of
|
||
data, although the size of each chunk is not usually specified as a
|
||
4-byte value in the stream of data. Instead, the size is either implied
|
||
or determined by continuing to read the data until you find the start of
|
||
the next chunk.
|
||
</p><p>
|
||
The inherent streaming nature of <acronym class="acronym">MPEG</acronym> means that there are no global
|
||
indices of file positions to frames or to where the sync points are in
|
||
the file. This complicates life for BeOS because a program often wants to
|
||
know how long a media file is so it can display a properly sized slider
|
||
or progress bar. To make that work, <code class="classname">BMediaFile</code>
|
||
pre-parses the <acronym class="acronym">MPEG</acronym> video
|
||
stream so that it knows where sync points are in the file and roughly how
|
||
many frames there are. The disadvantage of doing this is that it can take
|
||
a long time to read through all the data first before decoding any of the
|
||
frames. Our current approach of pre-parsing the entire <acronym class="acronym">MPEG</acronym> stream is not
|
||
something we're happy with and we plan to rewrite it.
|
||
</p><p>
|
||
From a media programmer's standpoint the important lesson here is that
|
||
the number of frames returned from
|
||
<code class="code"><code class="classname">BMediaTrack</code>-><code class="methodname">CountFrames()</code></code>
|
||
is only an approximate number.
|
||
<code class="code"><code class="classname">BMediaTrack</code>-><code class="methodname">Duration()</code></code>
|
||
is also only an approximate
|
||
value. This may be more or it may be less due to the imprecise nature of
|
||
file formats like <acronym class="acronym">MPEG</acronym>. Therefore, when you write a piece of code to
|
||
process all the frames in a file you should write the loop this way:
|
||
</p><pre class="programlisting c">
|
||
while(1) {
|
||
<span class="type">status_t</span> <code class="varname">err</code>;
|
||
<code class="varname">err</code> = <code class="varname">track</code>-><code class="methodname">ReadFrames</code>();
|
||
if (<code class="varname">err</code> == <code class="constant">B_LAST_BUFFER_ERROR</code>) <span class="comment">// all done!</span>
|
||
break;
|
||
else if (<code class="varname">err</code> == ...) <span class="comment">// handle other errors</span>
|
||
....
|
||
else if (<code class="varname">err</code> == <code class="constant">B_NO_ERROR</code>)
|
||
render the frames...
|
||
}
|
||
</pre><p>
|
||
or some variant of that approach (a good example is what the tcode
|
||
program does). You should NEVER code a for loop that counts up to the
|
||
number of frames returned by <code class="methodname">CountFrames()</code>.
|
||
</p><p>
|
||
Another interesting twist is that in QuickTime and some <acronym class="acronym">AVI</acronym> files a
|
||
single frame may be displayed for longer than the frame rate of the file.
|
||
That is, a single frame is displayed for several seconds instead of
|
||
repeating the frame's data in the file. Therefore, if you need to display
|
||
a scroll bar or slider, the <code class="methodname">Duration()</code> of the track is a better estimate
|
||
of how long it really is. The correct thing to do is to use <code class="methodname">Duration()</code> as
|
||
an estimate and dynamically adjust scrollbars and sliders until you get a
|
||
<code class="constant">B_LAST_BUFFER_ERROR</code>.
|
||
</p><p>
|
||
It's important to remember that <code class="methodname">CountFrames()</code>
|
||
and <code class="methodname">Duration()</code> are not
|
||
guaranteed to be precise and thus should NOT be used as an upper limit in
|
||
a <code class="code">for</code> or <code class="code">while</code> loop. This imprecision is certainly frustrating for
|
||
programmers but it's a fact of life that needs to be dealt with.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id437122"></a>From Chunks To Tracks</h3></div></div></div><p>
|
||
Now that we understand the concept of chunks, it's time to talk about
|
||
what's in some of those chunks. In QuickTime and <acronym class="acronym">AVI</acronym> there is a notion of
|
||
a media track that contains audio or video data. In a QuickTime file the
|
||
'trak' chunk indicates a media track. In <acronym class="acronym">AVI</acronym> there is the 'avih' chunk,
|
||
which contains global information about the entire movie, and the 'vids'
|
||
chunk that contains details about the video track.
|
||
</p><p>
|
||
The QuickTime file format is much more flexible than <acronym class="acronym">AVI</acronym> and allows any
|
||
number of tracks, each with its own frame rate and data type. QuickTime
|
||
tracks have extensive information about the presentation of the track's
|
||
contents. Video tracks even have a 3x3 transformation matrix that can be
|
||
applied to the video before compositing it into the final presentation!
|
||
</p><p>
|
||
Audio tracks in all file formats have the necessary information for
|
||
playing the audio: sample rate; size of the samples (8 or 16 bit); mono,
|
||
stereo, or multichannel, etc.
|
||
</p><p>
|
||
The track header also specifies how the track's data is encoded. For
|
||
example, Cinepak-encoded data is identified with a fourcc of "cvid."
|
||
Indeo-5 encoded data is identified with a fourcc of 'iv50'. You can find
|
||
a very complete list of fourcc codes from <acronym class="acronym">AVI</acronym> files at:
|
||
</p><p>
|
||
<a class="ulink" href="http://www.fourcc.org/">http://www.fourcc.org/</a>
|
||
</p><p>
|
||
Audio track information usually uses a single integer to identify which
|
||
codec to use. In a <acronym class="acronym">WAV</acronym> files for example, raw audio is indicated by the
|
||
integer value 1, and <acronym class="acronym">MS-ADPCM</acronym> (Microsoft's Adaptive Pulse Code
|
||
Modulation) is identified by a 2. <acronym class="acronym">AVI</acronym> uses the same identifiers as <acronym class="acronym">WAV</acronym>.
|
||
QuickTime uses its own set of fourcc's, of course.
|
||
</p><p>
|
||
Another good reference for <acronym class="acronym">AVI</acronym>/<acronym class="acronym">WAV</acronym> file codec id's is RFC-2361:
|
||
</p><p>
|
||
<a class="ulink" href="http://www.faqs.org/rfcs/rfc2361.html">http://www.faqs.org/rfcs/rfc2361.html</a>
|
||
</p><p>
|
||
In addition to the information about a track, a file format will also
|
||
have information about where in the file the data can be found. Typically
|
||
this takes the form of a table that indexes frames and file positions.
|
||
Using this information, you can extract the stream of data that makes up
|
||
a particular track. In the abstract, most media files look something like
|
||
this:
|
||
</p><pre class="screen">
|
||
+--------+------------+------------+-----+------------+------
|
||
| header | track 1 | track 2 | ... | track 1 | ...
|
||
| info | data chunk | data chunk | | data chunk |
|
||
+--------+------------+------------+-----+------------+------
|
||
</pre><p>
|
||
What you effectively have are interleaved chunks of data for each track.
|
||
In practice, you usually have a single audio track and a single video
|
||
track. Because the data rate of audio is far less than video, you often
|
||
have a single audio chunk followed by several video chunks, followed by
|
||
another audio chunk, etc.
|
||
</p><p>
|
||
If we were to split out the data chunks for each track and put them
|
||
together, we would have a contiguous stream of data for each track.
|
||
Again, it's important to remember that the file format doesn't care what
|
||
the data is in a track or how it's encoded, it only cares about the
|
||
ordering of the chunks of data and what frame (or frames) they correspond
|
||
to.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id437267"></a>From Tracks To Your Eyes And Ears</h3></div></div></div><p>
|
||
Now that we know what a track is, let's discuss how we get from the bits
|
||
of data that belong to a track to something that we see on screen (or
|
||
hear). If you're programming on BeOS you simply use the <code class="classname">BMediaTrack</code>
|
||
object to get access to the data that makes up a track. The <code class="classname">BMediaTrack</code>
|
||
object will let you access the decoded data for the track with
|
||
<code class="methodname">ReadFrames()</code>, or you can choose to get the encoded
|
||
data with <code class="methodname">ReadChunk()</code>.
|
||
</p><p>
|
||
What's going on behind the scenes is that when you want to decode a frame
|
||
from a media file, you have to first look up in the index where that
|
||
frame's data lives on disk. Once you know that, you can seek there, read
|
||
the encoded data into memory and hand it off to a decoder. This process
|
||
(and doing it efficiently) is the bulk of the work that <code class="classname">BMediaFile</code> and
|
||
<code class="classname">BMediaTrack</code> do.
|
||
</p><p>
|
||
The index that maps frames to on-disk locations can be very simple, as it
|
||
is in <acronym class="acronym">AVI</acronym>, or much more complex, as it is in QuickTime. In QuickTime each
|
||
frame can have a different duration, can appear anywhere in the file, and
|
||
QuickTime index/mapping tables support complex arrangements of the data
|
||
(presumably to allow it to be optimized for slow devices such as
|
||
cd-roms). In most cases the QuickTime approach is massive overkill. Aside
|
||
from the ability to change the duration of individual frames, the extra
|
||
functionality that QuickTime offers is almost never used.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id437333"></a>Decoders</h3></div></div></div><p>
|
||
Above we described conceptually how we get the encoded data out of a file
|
||
format. Once we've retrieved the encoded data for a particular frame, we
|
||
hand it off to a decoder. The decoder's job is to convert that encoded
|
||
video into a decoded format that the client (the person calling
|
||
<code class="code"><code class="classname">BMediaTrack</code>-><code class="methodname">ReadFrames()</code></code>)
|
||
can deal with. Most simple video compression
|
||
formats read the chunk, decode it into the output buffer, and are done.
|
||
More complex codecs have state information that they must maintain from
|
||
frame to frame. Indeo5 and <acronym class="acronym">MPEG</acronym> are two examples of encodings that
|
||
require lots of state information to be able to decode a frame.
|
||
</p><p>
|
||
Let's now delve into a few more details about different video and audio
|
||
codecs. This is the list of encoded media formats supported by the
|
||
upcoming BeOS Release 5. There are, of course, many more encodings out
|
||
there—these are just the ones we support:
|
||
</p><p>
|
||
</p><div class="informaltable"><table border="1"><colgroup><col align="right" /><col align="left" /></colgroup><thead><tr><th align="right">Encoded Video Format</th><th align="left">Comment</th></tr></thead><tbody><tr><td align="right">Cinepak</td><td align="left">expensive to encode; fast to decode</td></tr><tr><td align="right"><acronym class="acronym">PJPEG</acronym>/<acronym class="acronym">MJPEG</acronym></td><td align="left">decent quality; common hardware capture format</td></tr><tr><td align="right"><acronym class="acronym">MPEG</acronym>-1</td><td align="left">good quality; very widespread</td></tr><tr><td align="right">Indeo-5</td><td align="left">decent quality; can encode in real time</td></tr><tr><td align="right">DV</td><td align="left">constant bitrate; FireWire/i.Link video format</td></tr><tr><td align="right">Apple Video</td><td align="left">not widely used; low quality</td></tr><tr><td align="right">MS Video</td><td align="left">not widely used; low quality</td></tr><tr><td align="right">MS RLE</td><td align="left">not widely used; low quality</td></tr><tr><td align="right">raw</td><td align="left">heavy bandwidth requirements; perfect quality</td></tr></tbody></table></div><p>
|
||
</p><p>
|
||
</p><div class="informaltable"><table border="1"><colgroup><col align="right" /><col align="left" /></colgroup><thead><tr><th align="right">Encoded Audio Format</th><th align="left">Comment</th></tr></thead><tbody><tr><td align="right"><acronym class="acronym">MS-ADPCM</acronym></td><td align="left">compress 16-bit audio into 4-bit; good quality</td></tr><tr><td align="right">CCITT-ADPCM</td><td align="left">compress 16-bit audio into 4-bit; good quality</td></tr><tr><td align="right">ima4</td><td align="left">compress 16-bit audio into 4-bit; good quality</td></tr><tr><td align="right">ulaw</td><td align="left">compress 12-bit audio into 8-bit; OK quality</td></tr><tr><td align="right">raw</td><td align="left">perfect quality</td></tr><tr><td align="right">mpeg-1 layer 1,2,3</td><td align="left">great compression (10:1); insanely popular</td></tr></tbody></table></div><p>
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id437611"></a>Video Codec Background</h3></div></div></div><p>
|
||
Before we jump into the details of each video codec, let's step back for
|
||
a second and discuss some general terminology. A video codec encodes data
|
||
using an algorithm to transform an uncompressed frame or field of video.
|
||
The algorithm may operate on each frame independently or it may require
|
||
information about previous frames. If an encoder encodes each frame
|
||
independently, then when you want decode a frame you can do it without
|
||
having to look at any other frames. In this situation each frame is
|
||
treated as a keyframe (i.e., it can be decoded completely without
|
||
requiring other data) and, therefore, you can seek to any frame in the
|
||
file (aka: a perfectly seekable file).
|
||
</p><p>
|
||
If the encoding algorithm requires information about previous frames to
|
||
encode the current frame, then when decoding the data you must first
|
||
decode the prior frames leading up the frame you want. This type of
|
||
encoder will output a "keyframe" every so often as a sync point in the
|
||
file. Remember—a keyframe can be decoded independently of any other
|
||
frames. So for example, the output of an encoder could be this: 1
|
||
keyframe, 10 delta frames, 1 keyframe, 10 delta frames, etc. That means
|
||
that you can't seek to any arbitrary frame; you have to seek to a
|
||
keyframe and then play forward to reach the frame you want.
|
||
</p><p>
|
||
Most sophisticated encoding algorithms almost always have keyframes every
|
||
10-20 frames. The algorithms take advantage of the temporal cohesion
|
||
between each frame in video data. Keyframes are the reason that you can
|
||
not seek to an arbitrary position in most video files. <code class="classname">BMediaFile</code> has
|
||
support for seeking to the closest keyframe (ahead of or behind) to the
|
||
frame you wanted. This feature did not work very well in Release 4.5 but
|
||
will work much better in Release 5. If you require seeking to the exact
|
||
frame you requested, you need to iterate calling <code class="methodname">ReadFrames()</code> until you
|
||
get to the frame you want.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id437646"></a>Video Codec Descriptions</h3></div></div></div><p>
|
||
Video codecs each have different properties that make them more or less
|
||
suited to different tasks. Cinepak, for example, is definitely not a
|
||
real-time capture type of encoder. It can take several seconds to encode
|
||
a frame. A stream of Cinepak data always starts with a keyframe and is
|
||
followed by delta frames and then usually another keyframe (then the
|
||
cycle repeats). Some Cinepak-encoded videos only have a single keyframe,
|
||
as the first frame and everything else is just deltas. Decoding Cinepak
|
||
data, though, takes very little time, making it a good playback format
|
||
(for lower-end machines, etc.).
|
||
</p><p>
|
||
<acronym class="acronym">PJPEG</acronym> (aka Photo-<acronym class="acronym">JPEG</acronym>) encodes each frame as a <acronym class="acronym">JPEG</acronym> image. This works
|
||
reasonably well but does not take advantage of the temporal coherence in
|
||
video. You can find fast (real time, even) <acronym class="acronym">PJPEG</acronym> encoders (such as the
|
||
one that ships with personalStudio). <acronym class="acronym">MJPEG</acronym> is <acronym class="acronym">JPEG</acronym> encoding of fields of
|
||
video (remember though—frames are not the same as fields with video!).
|
||
<acronym class="acronym">PJPEG</acronym> is a good format for editing, because each frame is independent
|
||
(i.e., a keyframe) so perfect seeking is possible.
|
||
</p><p>
|
||
One (simplistic) way to describe <acronym class="acronym">MPEG</acronym>-1 is to think of it as <acronym class="acronym">PJPEG</acronym> frames
|
||
interspersed with deltas between the <acronym class="acronym">PJPEG</acronym> frames. <acronym class="acronym">MPEG</acronym>-1 encodes frames
|
||
into one of three types: I-frames, P-frames, or B-frames (there are also
|
||
D frames but these are extremely rare). I-frames are keyframes, P frames
|
||
are "predicted" frames, and B frames are bi-directional frames. You can
|
||
only seek to I-frames (and if an <acronym class="acronym">MPEG</acronym>-1 file had only I-frames it would
|
||
be roughly equivalent to a <acronym class="acronym">PJPEG</acronym> file).
|
||
</p><p>
|
||
Indeo-5 encoding is similar <acronym class="acronym">MPEG</acronym> in that it uses temporal cohesion to
|
||
improve the compression rate, but there isn't a lot of information about
|
||
the specifics of Indeo-5 encoding. Indeo-5 encoding can be done in real
|
||
time if you have the right encoder (not currently on BeOS). The quality
|
||
of Indeo-5 is decent, although not as good as a good <acronym class="acronym">MPEG</acronym>-1 encoder.
|
||
Indeo-5 is a good distribution format but not the best as an editing
|
||
format.
|
||
</p><p>
|
||
<acronym class="acronym">DV</acronym> (Digital Video) encoding is the encoding used by DV cameras (duh!)
|
||
that communicate with a computer over 1394 (aka Sony i.Link, aka
|
||
Firewire). <acronym class="acronym">DV</acronym> is a good encoding: it's high quality; has constant
|
||
bit-rate (about 4 megs/sec); and it can be decoded in real time in
|
||
software. <acronym class="acronym">DV</acronym> is also a good format for editing because every frame is
|
||
independent.
|
||
</p><p>
|
||
The Apple Video, MS Video, and MS <acronym class="acronym">RLE</acronym> formats are all old video encodings
|
||
that don't have good quality compared to the newer codecs. Essentially
|
||
they're all variants of run-length encoding.
|
||
</p><p>
|
||
Raw video isn't really an "encoding" but it is an option for storing
|
||
video if you have the disk bandwidth. Typically, you can capture raw
|
||
320x240 size video to a standard <acronym class="acronym">IDE</acronym> hard disk. Capturing 640x480 video
|
||
at 16 bits per pixel requires about 17.57 megabytes/second bandwidth.
|
||
That means that you need either a super-fast single drive or a striped
|
||
disk setup. You can store raw video in a variety of pixel formats
|
||
(<acronym class="acronym">RGB</acronym>-32, <acronym class="acronym">RGB</acronym>-16, <acronym class="acronym">YUV</acronym>-422,
|
||
etc.). Both <acronym class="acronym">AVI</acronym> and QuickTime support raw
|
||
video; <acronym class="acronym">MPEG</acronym> does not. Raw video is perfectly seekable and is the best
|
||
format for editing if you can handle it.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id437810"></a>Audio Codec Descriptions</h3></div></div></div><p>
|
||
The <acronym class="acronym">MS-ADPCM</acronym>, <acronym class="acronym">CCITT-ADPCM</acronym> and
|
||
<acronym class="acronym">ima4</acronym> encoders are all variants of Adaptive
|
||
Pulse Code Modulation encoding. Essentially, they encode 16-bit audio
|
||
into 4-bit chunks in a mostly lossless manner. The encoding process isn't
|
||
terribly CPU intensive and decoding is quite cheap. You probably wouldn't
|
||
want to use these formats for editing but for final distribution they
|
||
work well.
|
||
</p><p>
|
||
<acronym class="acronym">uLaw</acronym> encoding compresses 12-bit audio into an 8-bit quantity. The quality
|
||
is usually poor (phone-line quality) but the encode and decode are
|
||
extremely cheap. Old timers may remember the original SparcStation-1 had
|
||
a <code class="filename">/dev/audio</code> that spat out (and accepted) uLaw-encoded data. And before I
|
||
get flamed, yes, the NeXT Cube did it too. BeOS only supports decoding
|
||
this format.
|
||
</p><p>
|
||
<acronym class="acronym">MPEG</acronym>-1 audio is a sophisticated encoding scheme that uses psycho-acoustic
|
||
models, <acronym class="acronym" title="Discrete Cosine Transform"><a class="ulink" href="http://en.wikipedia.org/wiki/Discrete_cosine_transform">DCT</a></acronym>
|
||
transforms, and <a class="ulink" href="http://en.wikipedia.org/wiki/Huffman_coding">Huffman encoding</a>
|
||
to compress audio, typically
|
||
around 10 to 1. <acronym class="acronym">MPEG</acronym>-1 audio has three layers, called, appropriately
|
||
enough, layers 1, 2, and 3. <acronym class="acronym">MPEG</acronym>-1 layer 3 audio is commonly known as
|
||
MP3. There is also a layer 2.5 for low bit rates but it is not terribly
|
||
common. <acronym class="acronym">MPEG</acronym>-1 audio can be encoded with a wide variety of options
|
||
(different data rates, stereo/mono, different sample sizes and sample
|
||
rates). By far the most common form of <acronym class="acronym">MPEG</acronym>-1 audio data is 128kbs data
|
||
rate 44.1 khz stereo data (it's the format that 90% of your pirated mp3's
|
||
are in). <acronym class="acronym">MPEG</acronym>-1 audio is typically quite expensive to encode. Decoding
|
||
doesn't take a lot of CPU time relative to video but it's much more than
|
||
any of the other audio encodings. <acronym class="acronym">MPEG</acronym>-1 audio is a great format to
|
||
distribute audio in because of its wide acceptance and excellent
|
||
compression ratio.
|
||
</p><p>
|
||
As with video, raw audio provides perfect quality. Raw audio can be
|
||
stored in a variety of sample rates (11,000 hz, 22050 hz, 32000 hz, 44100
|
||
hz, 48000 hz) and in a variety of sample sizes (8-bit, 16-bit, or even
|
||
32-bit). Fortunately, raw audio doesn't have the bandwidth requirements
|
||
of video, so storing it on a standard hard disk is easy. Editing audio is
|
||
always best when done with raw audio.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id437927"></a>Wrapping Up</h3></div></div></div><p>
|
||
That about covers our tour of media file formats and codecs. I know that
|
||
this is a bit short but the subject really is vast and we don't have the
|
||
space to write all that should be written about it.
|
||
</p><p>
|
||
The two most important points that I hope people take away from this
|
||
article are these:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
<acronym class="acronym">MPEG</acronym> makes life difficult because it's difficult to know exactly how
|
||
many frames are in a file until you've read them all. Therefore, you
|
||
must code processing loops to end when they receive the error
|
||
<code class="constant">B_LAST_BUFFER_ERROR</code> (even if you're not planning to deal with <acronym class="acronym">MPEG</acronym>
|
||
files).
|
||
</p></li><li><p>
|
||
Most video formats (and some audio formats) use keyframes, which
|
||
makes seeking imprecise. When seeking is imprecise you may ask to seek
|
||
to frame 35 but only get frame 30.
|
||
</p></li></ul></div></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="DevWorkshop5-4"></a>Developers' Workshop: The BeOS—The Rescue OS</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Daniel</span> <span class="surname">Switkin</span></span></div></div></div><p>
|
||
I recently went hiking with my Nikon digital camera. After capturing a
|
||
few memorable shots, I headed home to examine my handiwork. I downloaded
|
||
the images to my hard drive and deleted them from the Compact Flash card.
|
||
I happened to be viewing one particular image in ArtPaint and in Retouch,
|
||
a photo manipulator I'm writing. I decided to scale it down to 640x480
|
||
from 1600x1200 to post it on the web. I then promptly overwrote my
|
||
original file by being too quick with my keyboard shortcuts.
|
||
</p><p>
|
||
So here's the setup: the image was gone from the camera, it was
|
||
overwritten on disk, undo was off in <span class="application">ArtPaint</span> (these are 8 meg images),
|
||
and my app doesn't have a save feature yet. The only place the original
|
||
image existed was in a <code class="classname">BBitmap</code> in Retouch. A good challenge. Not to be
|
||
thwarted, I did the following:
|
||
</p><pre class="programlisting cpp">
|
||
#include <OS.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <File.h>
|
||
|
||
#define <code class="constant">APP_SERVER_TEAM</code> 15
|
||
#define <code class="constant">APP_IN_TROUBLE</code> "Retouch"
|
||
|
||
<span class="type">int</span> main(<span class="type">int</span> <code class="parameter">argc</code>, <span class="type">char **</span><code class="parameter">argv</code>) {
|
||
<span class="type">int32</span> <code class="varname">cookie</code> = 0;
|
||
<span class="type">area_info</span> <code class="varname">info</code>;
|
||
|
||
while (get_next_area_info(<code class="constant">APP_SERVER_TEAM</code>, &<code class="varname">cookie</code>,
|
||
&<code class="varname">info</code>) == <code class="constant">B_OK</code>) {
|
||
|
||
if (strstr(<code class="varname">info</code>.<code class="varname">name</code>, <code class="constant">APP_IN_TROUBLE</code>) != <code class="constant">NULL</code>) {
|
||
printf("\nName is %s\nArea ID is %d\nSize is %d
|
||
or 0x%x\nAddress is 0x%x", info.name,
|
||
<code class="varname">info</code>.<code class="varname">area</code>, <code class="varname">info</code>.<code class="varname">size</code>, <code class="varname">info</code>.<code class="varname">size</code>,
|
||
<code class="varname">info</code>.<code class="varname">address</code>);
|
||
|
||
if (strstr(<code class="varname">info</code>.<code class="varname">name</code>, "RWHeap") == <code class="constant">NULL</code>)
|
||
continue;
|
||
|
||
printf("Found RWHeap for %s\n", <code class="constant">APP_IN_TROUBLE</code>);
|
||
|
||
<span class="type">int32</span> <code class="varname">address</code> = 0;
|
||
<span class="type">int32 *</span><code class="varname">address_pointer</code> = &address;
|
||
<span class="type">area_id</span> <code class="varname">cloned_area</code> = clone_area("Clone",
|
||
(void **)&<code class="varname">address_pointer</code>, <code class="constant">B_ANY_ADDRESS</code>,
|
||
<code class="constant">B_READ_AREA</code>, <code class="varname">info</code>.<code class="varname">area</code>);
|
||
|
||
if (<code class="varname">cloned_area</code> < 0) {
|
||
printf("Clone failed: %s\n",
|
||
strerror(<code class="varname">cloned_area</code>));
|
||
return 1;
|
||
}
|
||
|
||
<span class="type">area_info</span> <code class="varname">cloned_info</code>;
|
||
|
||
if (get_area_info(<code class="varname">cloned_area</code>, &<code class="varname">cloned_info</code>) !
|
||
= <code class="constant">B_OK</code>) {
|
||
printf("get_area_info failed\n");
|
||
return 1;
|
||
}
|
||
|
||
<code class="classname">BFile</code> <code class="varname">file</code>("/boot/home/src/Fun/rescue.rw",
|
||
<code class="constant">B_WRITE_ONLY</code> | <code class="constant">B_CREATE_FILE</code>);
|
||
|
||
if (<code class="varname">file</code>.<code class="methodname">InitCheck()</code> == <code class="constant">B_OK</code>) {
|
||
<span class="type">int32</span> <code class="varname">size</code> = <code class="varname">file</code>.<code class="methodname">Write</code>(<code class="varname">cloned_info</code>.<code class="varname">address</code>,
|
||
<code class="varname">cloned_info</code>.<code class="varname">size</code>);
|
||
printf("Wrote %d bytes out of %d bytes\n",
|
||
<code class="varname">size</code>, <code class="varname">cloned_info</code>.<code class="varname">size</code>);
|
||
} else printf("Could not create file\n");
|
||
|
||
delete_area(<code class="varname">cloned_area</code>);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
</pre><p>
|
||
This dumped the entire contents of the read-write area for Retouch out of
|
||
the App Server into a file. Running ps told me what team number to search
|
||
for. So now the raw data of my photograph was on disk, which is good, but
|
||
somewhere in a 46 megabyte file, which is bad. Hmmm.
|
||
</p><p>
|
||
I fired up Magnify, and found the RGB values of the first three pixels in
|
||
the top left corner. After converting these to hex, adding <code class="literal">0xff</code> for the
|
||
alpha channel, and writing them out as BGRA (the order of a <code class="constant">B_RGB32</code>
|
||
bitmap) I ran:
|
||
</p><pre class="screen">
|
||
hd rescue.rw | grep -1 "a3 a5 94 ff a3 a9 95 ff"
|
||
</pre><p>
|
||
to find every occurrence of the first two pixels. This only turned up a
|
||
few hits, and the third pixel narrowed it down to one location. I then
|
||
hacked up the following to write a Targa header, seek into the rescue.rw
|
||
file, and dump the image contents to my new image:
|
||
</p><pre class="programlisting cpp">
|
||
#include <File.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
#define <code class="constant">LOCATION</code> 0x01d4f368
|
||
#define <code class="constant">SIZE</code> 7680000
|
||
|
||
<span class="type">int</span> main(<span class="type">int</span> <code class="parameter">argc</code>, <span class="type">char **</span><code class="parameter">argv</code>) {
|
||
<code class="classname">BFile</code> <code class="varname">in</code>("/boot/home/src/Fun/rescue.rw", <code class="constant">B_READ_ONLY</code>);
|
||
if (<code class="varname">in</code>.<code class="methodname">InitCheck()</code> != <code class="constant">B_OK</code>) {
|
||
printf("Could not load file\n");
|
||
return 1;
|
||
}
|
||
|
||
<span class="type">unsigned char</span> <code class="varname">header</code>[18];
|
||
memset(<code class="varname">header</code>, 0, 18);
|
||
<code class="varname">header</code>[2] = 2;
|
||
<code class="varname">header</code>[12] = 1600 % 256;
|
||
<code class="varname">header</code>[13] = 1600 / 256;
|
||
<code class="varname">header</code>[14] = 1200 % 256;
|
||
<code class="varname">header</code>[15] = 1200 / 256;
|
||
<code class="varname">header</code>[16] = 32;
|
||
<code class="varname">header</code>[17] = 0x28;
|
||
|
||
<code class="classname">BFile</code> <code class="varname">out</code>("/boot/home/src/Fun/rescue.tga",
|
||
<code class="constant">B_WRITE_ONLY</code> | <code class="constant">B_CREATE_FILE</code>);
|
||
if (<code class="varname">out</code>.<code class="methodname">InitCheck()</code> != <code class="constant">B_OK</code> ||
|
||
<code class="varname">out</code>.<code class="methodname">Write</code>(<code class="varname">header</code>, 18) != 18) {
|
||
printf("Could not write file\n");
|
||
return 1;
|
||
}
|
||
if (<code class="varname">in</code>.<code class="methodname">Seek</code>(<code class="constant">LOCATION</code>, <code class="constant">SEEK_SET</code>) != <code class="constant">LOCATION</code>) {
|
||
printf("Could not seek to %d\n", <code class="constant">LOCATION</code>);
|
||
return 1;
|
||
}
|
||
|
||
<span class="type">int</span> <code class="varname">size</code> = 1 << 16;
|
||
<span class="type">char *</span><code class="varname">buffer</code> = (<span class="type">char *</span>)malloc(<code class="varname">size</code>);
|
||
if (<code class="varname">buffer</code> == <code class="constant">NULL</code>) {
|
||
printf("Could not allocate memory\n");
|
||
return 1;
|
||
}
|
||
|
||
<span class="type">int</span> <code class="varname">total_size</code> = <code class="constant">SIZE</code>;
|
||
while (<code class="varname">total_size</code> > <code class="varname">size</code>) {
|
||
<code class="varname">in</code>.<code class="methodname">Read</code>(<code class="varname">buffer</code>, <code class="varname">size</code>);
|
||
<code class="varname">out</code>.<code class="methodname">Write</code>(<code class="varname">buffer</code>, <code class="varname">size</code>);
|
||
<code class="varname">total_size</code> -= <code class="varname">size</code>;
|
||
}
|
||
|
||
if (<code class="varname">total_size</code> != 0) {
|
||
<code class="varname">in</code>.<code class="methodname">Read</code>(<code class="varname">buffer</code>, <code class="varname">total_size</code>);
|
||
<code class="varname">out</code>.<code class="methodname">Write</code>(<code class="varname">buffer</code>, <code class="varname">total_size</code>);
|
||
}
|
||
|
||
free(<code class="varname">buffer</code>);
|
||
return 0;
|
||
}
|
||
</pre><p>
|
||
Conveniently, true color Targa data is little endian, so I could dump the
|
||
data directly (this is also why taking a screenshot in BeOS writes a .tga
|
||
file).
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Gassee5-4"></a>What Now?</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Jean-Louis</span> <span class="surname">Gassée</span></span></div></div></div><p>
|
||
First, two words of apology. One for being unable to answer all the
|
||
e-mail I've received in recent days at my own jlg@be.com account, or
|
||
through the info@be.com feed—I get to keep an eye on the daily flow of
|
||
queries. I hope this column will help address most questions regarding
|
||
last week's announcement. Second, the timing and manner of disclosure.
|
||
The SEC frowns upon what is called "selective disclosure," a practice by
|
||
which a subset of "select" individuals get material information before
|
||
the market at large. In other words, we have to make sure we disseminate
|
||
material information via a medium that provides timely and reasonably
|
||
broad dissemination.
|
||
</p><p>
|
||
In our case, we use a press release on Business Wire. Perish the thought,
|
||
but should an enthusiastic CEO discuss product plans in too much detail
|
||
at some industry conference, a publicly traded company would have to rush
|
||
out a press release the same day in order to put all buyers and sellers
|
||
of its stock on the same footing.
|
||
</p><p>
|
||
But enough of that. Let's go right to the heart of the matter: Why are we
|
||
shifting resources to Internet appliances, and what does it mean for what
|
||
is commonly referred to as "the desktop?" Once upon a time, four or five
|
||
years ago, if memory serves, Vint Cerf, one of the true fathers of the
|
||
Internet, was on the cover of Boardwatch magazine. The
|
||
professorial-looking Mr. Cerf proudly modeled a t-shirt bearing a simple
|
||
motto: "IP on Everything". I remembered thinking, right, Coke, with a
|
||
capital C, has gone to his head, as in pinging the proverbial soft-drink
|
||
machine in a university dormitory. What's next? IP-enabled refrigerators?
|
||
</p><p>
|
||
Cut to January 2000 football commercials where the repairman comes to
|
||
your house for your refrigerator. But it's not on the fritz. Not yet,
|
||
goes the penetrating answer. The not-so-subtle subtext here is that we've
|
||
entered the "everything connected" era where, yes, your IP-enabled fridge
|
||
will report incipient trouble and get it fixed before the contents of the
|
||
freezer spoil.
|
||
</p><p>
|
||
We agree, this is the post-PC revolution, a new phase for our industry,
|
||
when all the objects in our daily lives will be connected to the
|
||
Internet, with or without wires. At each previous phase, mainframes to
|
||
minis, minis to personal computers, we've seen tremendous growth in the
|
||
number of people and devices. We'll see a similar phase change in the
|
||
post-PC era. Last spring, Michael Dell saw two billion devices connected
|
||
to the Net by 2002 or 2003, with PCs accounting for 700 million of the
|
||
number. Since then, most industry analysts have upped the forecast and
|
||
agreed that Vint Cerf's "IP on Everything" vision was becoming a market
|
||
reality. "Everything" should probably refer to objects ranging from
|
||
watches to TVs, from cars to video recorders, and from stereos on Net
|
||
steroids to refrigerators, security systems, wireless tablets, PDAs,
|
||
telephones, and whiteboards.
|
||
</p><p>
|
||
Let's immediately qualify this by referring to the early days of
|
||
marketing a new invention, the telephone. The (urban?) legend has it that
|
||
the telephone was promoted as a means to listen to opera performances and
|
||
theater plays. The concept of a worldwide web of telephone wires allowing
|
||
anyone to call anyone any time was unimagined. How could anyone have seen
|
||
the consequences of the telephone on our lives? It didn't change our DNA,
|
||
but it is interwoven, "webbed," says the thesaurus, into our lives. Now,
|
||
we're beginning to weave a new generation of IP-enabled devices into our
|
||
culture. As we do this, we have to keep in mind the difficulties in
|
||
foreseeing the impact of the telephone and expect similar surprises with
|
||
"IP on Everything".
|
||
</p><p>
|
||
Moving on to BeOS, we have OS technology that combines many desirable
|
||
features for the new breed of applications. Unlike embedded systems
|
||
running under the hood of a car, these new appliances need strong
|
||
multimedia capabilities. BeOS offers a small footprint and a modern,
|
||
robust, modular, customizable solution for these applications. As
|
||
disclosed in several of last quarter's announcements, customers and
|
||
partners have validated our offering and we're planning a more formal
|
||
announcement of what we refer to as Stinger, a complete software solution
|
||
for Internet appliances. We'll be providing details at the upcoming
|
||
introduction event.
|
||
</p><p>
|
||
So far, we have an exciting emerging market and a product for it. Looking
|
||
at the market again, we see no 800-pound gorilla monopolizing it. Rather,
|
||
we see a very fluid situation, fast growth, and we see the opportunity to
|
||
become a mainstream player. That is why we've decided to shift our
|
||
resources to that opportunity, to the goal of establishing BeOS as the
|
||
premier OS platform for media- rich Internet devices. "Our resources," in
|
||
the previous sentence, includes the desktop BeOS. In support of our
|
||
Internet appliances effort, the desktop BeOS plays two roles, both vital.
|
||
The first role is the development system for Stinger-based products,
|
||
offering the advantages of a native environment, already well-tested,
|
||
and, if I may say so, well-liked. Then, by offering a free version of
|
||
BeOS available for download, we advertise our technology on the widest
|
||
billboard known to humankind, the Internet. The goals are to gain
|
||
visibility, market testing and feedback and to inspire developers to
|
||
create new types of Internet appliance devices using Be technology. As a
|
||
result, we'll continue to issue updates and new releases for the desktop
|
||
BeOS in support of its role in our appliances strategy. For example, as
|
||
new drivers and features are developed for Stinger-based products, BeOS
|
||
desktop will gain driver compatibility and features.
|
||
</p><p>
|
||
I realize there is concern that we'll "ditch" the desktop, and I accept
|
||
the fact that a shift in strategy always creates uncertainty. Only our
|
||
actions over time can allay those concerns.
|
||
</p><p>
|
||
Fortunately, it's not entirely up to us. We intend to work with
|
||
publishers and other partners to make commercial versions of BeOS 5
|
||
available through retail channels. This allows us to refocus the energies
|
||
we previously applied to our own retail distribution efforts. We've
|
||
received a number of calls from all over the world expressing interest in
|
||
BeOS 5. Several software developers are interested in bundling BeOS with
|
||
their applications and others want to publish and ship BeOS 5 itself.
|
||
I've even heard a comment to the effect one company wants to be the Red
|
||
Hat of the BeOS. I like the sentiment, and I'll let the legal eagles have
|
||
fun with the putative motto.
|
||
</p><p>
|
||
As I have been required to do in the past, I must inform you that many of
|
||
the statements I have made here are forward-looking in nature. That is,
|
||
statements that are not historical facts are "forward-looking
|
||
statements," including without limitation my statements regarding the
|
||
future growth of the Internet appliance market, future availability and
|
||
performance of Internet appliances and third party applications, plans
|
||
for product development and release, the future capabilities of our
|
||
products or other products mentioned herein, the market acceptance of our
|
||
products, and our ability to penetrate and capture the emerging Internet
|
||
appliance markets. Actual events or results may differ materially as a
|
||
result of risks facing Be Incorporated or actual results differing from
|
||
the assumptions underlying such statements. Such risks and assumptions
|
||
include, but are not limited to, risks related to the growth of the
|
||
market for Internet appliances, our ability to establish and maintain
|
||
strategic relationships, our ability to develop and engineer
|
||
modifications to BeOS, and the competition and market acceptance of BeOS.
|
||
All such forward-looking statements are expressly qualified in their
|
||
entirety by the "Risk Factors" and other cautionary statements included
|
||
in Be Incorporated's prospectus, filed pursuant to Rule 424(b) of the
|
||
Securities Act of 1933 on July 20, 1999 (Commission File No. 333- 77855),
|
||
and other public filings with the Securities and Exchange Commission.
|
||
</p></div></div><div id="footer"><hr /><div id="footerT">Prev: <a href="Issue5-3.html">Issue 5-3, January 19, 2000</a> Up: <a href="volume5.html">Volume 5: 2000</a> Next: <a href="Issue5-5.html">Issue 5-5, February 2, 2000</a> </div><div id="footerB"><div id="footerBL"><a href="Issue5-3.html" title="Issue 5-3, January 19, 2000"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a href="volume5.html" title="Volume 5: 2000"><img src="./images/navigation/up.png" alt="Up" /></a> <a href="Issue5-5.html" title="Issue 5-5, February 2, 2000"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="footerBR"><div><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div></div><div id="footerBC"><a href="http://www.access-company.com/home.html" title="ACCESS Co."><img alt="Access Company" src="./images/access_logo.png" /></a></div></div></div><div id="licenseFooter"><div id="licenseFooterBL"><a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/" title="Creative Commons License"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc-nd/3.0/88x31.png" /></a></div><div id="licenseFooterBR"><a href="./LegalNotice.html">Legal Notice</a></div><div id="licenseFooterBC"><span id="licenseText">This work is licensed under a
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative
|
||
Commons Attribution-Non commercial-No Derivative Works 3.0 License</a>.</span></div></div></body></html>
|