Console Port |
Pad Port |
Direction |
---|---|---|
50020 |
50120 |
Console ↔ Pad |
The video streaming protocol, also known as vstrm
, is used to stream
compressed game video data from the Wii U to a GamePad, or to stream camera
data from a GamePad to the Wii U. It is using H.264 with a custom wrapper
around the VCL instead of NAL.
Each packet has an 8 byte header (4 is also possible but never seen), followed by an 8 byte extended header, followed by the compressed video data.
struct VstrmHeader {
u32 magic : 4;
u32 packet_type : 2;
u32 seq_id : 10;
u32 init : 1;
u32 frame_begin : 1;
u32 chunk_end : 1;
u32 frame_end : 1;
u32 has_timestamp : 1;
u32 payload_size : 11;
// If has_timestamp is set (almost always)
u32 timestamp : 32;
};
This header is then followed by an 8 byte extended header.
The extended header is an 8 byte area after the vstrm
header where options
can be set. Each option is represented by a byte, and options are read linearly
from the extended header until either 8 bytes were read or a 0x00
byte was
read (signaling the end of options). Here are the known options:
Option Byte |
Option Name |
Arg |
Description |
---|---|---|---|
0x00 |
End |
N |
End of options. |
0x80 |
IDR |
N |
Indicated that the frame is an IDR. |
0x81 |
Unimplemented |
Y |
Takes one byte of argument but does nothing. |
0x82 |
Frame Rate |
Y |
0 = 59.94Hz, 1 = 50Hz, 2 = 29.97Hz, 3 = 25Hz. |
0x83 |
Force Decoding |
N |
Forces decoding even if buffer is too small. |
0x84 |
Unset Force Flag |
N |
Unsets the force decoding flag. |
0x85 |
NumMbRowsInChunk |
Y |
Usually 6 (6 * 16px * 5 chunks = 480px). |
A single H.264 frame is obviously not sent in one vstrm
packet: the network
MTU is around 1800 bytes, making it impossible to transfer most frames. To
separate a frame into several packets, the vstrm
protocol does the
following:
Cut each frame into 5 equal chunks. Each chunk represents a 854x96 region of the decoded image (6 macroblock rows).
Send as many packets as needed for each chunk, but the last packet of a chunk
needs to have the chunk_end
flag set.
On top of that, the first packet of the first chunk of a frame has the
frame_begin
flag set, and the last packet of the last chunk of a frame has
the frame_end
flag set.
TODO: see src/video-streamer.cpp
.