Yes, two weeks since the last updates. You guys must have been wondering where we were?!
As it is, we were heads down spending oodles and oodles of time researching the various possible solutions to stream video. Lots and lots of time. Hours and hours. Actually every waking hour for two weeks Enough to suspend every other life activity (including cancelling Chinese classes for this week!).
Without video streaming, there's little in way of tele-presence... But the challenges of video streaming makes every little other problem in our project trivial.
On the Android platform, there's little in way of built-in solutions, especially solutions that would let us stream and be OpenSource so we could integrate it into our project. Found IP Camera For Android [http://code.google.com/p/ipcamera-for-android/], a project that promised h.264 streaming out of the camera. However it didn't work with our platform for reasons that were at that time quite nebulous.
So we temporarily gave up on "IP Camera for Android".
We then spent a larger chunk of time researching how to get ffmpeg to work on Android which required getting familiar with cross-compilation to the ARM platform. The result, sadly, even after exploring all avenues we could think of to access the low-level video4linux interface (/dev/video0) on the Haipad was just random noise.
So we then went back to IP Camera for Android and really understand how it worked so we could make the simple required fix...
Fundamentally, to understand the issue with the output generated by the Android encoder we have to understand that a video file is two things: the encoded stream (using a codec, in this case H.264 AVC) and the "container" of that content that can be decoded can contains information to describe the video stream. In the case of the MP4 container format, that description comes into the form of "atoms" or "boxes" of information.
The problem is that the output produced by the Android encoder is not designed for streaming; this means that those boxes are not written until the stream has been fully written out to disk. This also means that the header information that would let a codec parse the output is not available until the end; in the case of H.264 the quite essential information we want is the SPS (Sequence Parameter Set) and PSS (Picture Parameter Set (PPS)).
The nice hack that "IP Camera for Android" uses is to create a sample video on disk and reads the SPS and PSS information from that. Since that output between encoded videos at the same resolution coming from the same encoder is consistent, that same information can be reused for other video streams.
For streaming, it captures the video then inserts a "StreamingKernel" between the encoder output (which luckily we can redirect to a local socket), skips the incomplete MP4 header, inserts the previously read SPS and PSS and constructs a more streamable VLC stream, another video container format. The VLC stream is made up of the individual H.264 frames wrapped in VLC "tags" served from an embedded WebServer

to a flash based video player (!!) on the client side.
Yes, this means your phone can run a webserver that serves real-time encoded video! When you think about that, it's kind of pretty awesome to realize that we live in the future...
The problem was that the software made some simple but erroneous assumptions about the format of both the sample video and the length of the MP4 header. Actual encoded video data starts after an "atom/box" called "mdat". The mdat actual position varies depending on what the encoder is producing - the original code set the header size is 32 bytes while post-2.1 devices are 44 bytes.
As fixing the size of that header is annoying, we modified the code to read byte per byte from the stream until we get to mdat and then actually doing the streaming. In addition, we've made changes to reduce the number of costly data copies and temporary buffers to "streamline the streaming".
The result is still not entirely satisfactory due to the latency that seems to be introduced by buffering inside the encoder... But it's a big step forward.
This is quite a detour into the depths of Android and streaming. It did give us valuable experience with the platform and we can now use that experience as a building block for other interesting projects. But it also came at the cost of lots of time and energy that could have been used making progress elsewhere in the competition project...
So now we have to pick all the pieces we've done in one coherent whole...
Yes, two weeks without updates. You guys must have been wondering where we were?!
As it is, we were heads down spending oodles and oodles of time researching the various possible solutions to stream video. Lots and lots of time. Hours and hours. Actually every waking hour for two weeks... Enough to suspend every other life activity (including cancelling Chinese classes for this week!).
Without video streaming, there's little in way of tele-presence... But the challenges of video streaming make every little other problem in our project look trivial.
On the Android platform, there's little in way of built-in solutions... Especially solutions that would let us stream and be OpenSource so we could integrate it into our project. Early on, we found IP Camera For Android, a project that promised h.264 streaming out of the camera. However it didn't work with our platform for reasons that were at that time quite nebulous.
So we temporarily gave up on "IP Camera for Android".
We then spent a larger chunk of time researching how to get ffmpeg (C++ OpenSource suite of video encoders used in many, many embedded products) to work on Android which required getting familiar with cross-compilation to the ARM platform. The result, sadly, even after exploring all avenues we could think of to access the low-level video4linux interface (/dev/video0) on the Haipad was just random noise.
So we then went back to IP Camera for Android and really understand how it worked so we could make the simple required fix...
Fundamentally, to understand the issue with the output generated by the Android encoder we have to understand that a video file is two things:
1) the encoded stream (using a codec, in this case H.264 AVC) and
2) the "container" of that content that contains information to describe the video stream.
In the case of the MP4 container format, that description comes into the form of "atoms" or "boxes" of information.
The problem is that the output produced by the Android encoder is not designed for streaming; this means that those "boxes" are not written until the stream has been fully written out to disk. This also means that the header information that would let a codec parse the output is not available until the end, which isn't practical when streaming video. In the case of H.264, the quite essential information we want is called the SPS (Sequence Parameter Set) and PSS (Picture Parameter Set (PPS)), arrays of bytes that serve as parameters to the H.264 AVC codec.
The nice hack that "IP Camera for Android" uses is to create a sample video on disk and read the SPS and PSS information from that prior to stremaing. Since the output between encoded videos at the same resolution coming from the same encoder is consistent, that same information can be reused for other video streams.
For streaming, "IP Camera for Android" captures the video streams by redirecting the encoder output to a local socket. That socket is read by "StreamingKernel" whose primary task is to skip the incomplete MP4 header and break down the stream into frames. The "Streamer" then inserts the previously read SPS and PSS and constructs a more streamable VLC output (VLC is another video container format). The VLC stream is made up of the individual H.264 frames wrapped in VLC "tags" served from an embedded WebServer
to a flash based video player
on the client side.
Yes, this means modern Android phone can run a webserver that serves real-time encoded video!
When you think about that, it's kind of pretty awesome to realize that we live in the future...
The original problem was that the software made some simple but erroneous assumptions about the format of both the sample video and the length of the MP4 header. Actual encoded video data starts after an "atom/box" called "mdat". The mdat actual position varies depending on what the encoder is producing - the original code set the header size at 32 bytes while post-2.1 Android devices encoders header length is 44 bytes...
As fixing the size of that header is annoying, we modified the code to read byte per byte from the stream until we get to mdat and then actually doing the streaming. In addition, we've made changes to reduce the number of costly data copies and temporary buffers to "streamline the streaming".
The result is still not entirely satisfactory due to the latency that seems to be introduced by buffering inside the encoder... But it's a big step forward.
This is quite a detour into the depths of Android and streaming. It did give us valuable experience with the platform and we can now use that experience as a building block for other interesting projects. But it also came at the cost of lots of time and energy that could have been used making progress elsewhere in the competition project...
So now we have to pick all the pieces we've done in one coherent whole...
You can follow or find more details on Github and the wiki as we try to put all the pieces together into a demoable final project. More updates on other aspects of the project soon...