5.1 Live555 Streaming Media - fonnes/flexible_fec GitHub Wiki

5.1 Live555 Streaming Media

Live555 Streaming Media is a well-maintained collection of C++ libraries for streaming multimedia over RTP unicast and multicast in IP networks. In addition to streaming multimedia, it also offers playback options and metadata negotiation using protocols such as RTSP and SIP, and QoS monitoring via RTCP. Furthermore, Live555 is also used in the wild by well-known applications such as VideoLan and MPlayer. In addition to providing a complete RTP stack, Live555 also offers several schemes for packing video, audio and text in RTP. These schemes are defined in Internet Standard documents such as RFCs, for example RFC 6184 (Y.-K. Wang et al. 2011).

In this thesis, we implement the most recent FEC draft using Live555 Streaming Media as our base RTP-implementation, primarily because it offers most of what we need to conduct the experiments. This includes a complete RTP/RTCP stack and H.264 video streaming and receiving applications. Finlayson (2018), the CEO and founder of Live Networks Inc., recommends to extend Live555 via C++ subclassing rather than changing the existing codebase. One major benefit of this method is that we face no obligation under the Live555’s current license, LGPL. As a result, we follow this recommendation, which naturally results in our implementation being created in C++. Live555 supports all major operating systems, Windows, MacOS and Linux. We do, however, only have access to Mac and Linux machines. These operating systems are very similar because they are both based on the UNIX architecture. As a result, we develop the FEC implementation to support these platforms, and do not focus on Windows. On MacOS, we support the clang compiler, and on Linux, we support the gcc compiler.

5.1.1 Flow of Operation

Live555 is an event-based C++ library running an event loop in a singlethreaded task scheduler, eliminating the risk of race conditions and complexity of multi-threadedness. In this loop, the task scheduler looks for available tasks, either in the delayed queue, or the list of network read handlers. When a task is found, it is executed. In addition to delayed tasks and network read handlers, tasks can also be set by using watch variables or event triggers. These event handlers are applied whenever manual event triggering is needed.

Live555 utilizes three core components: sources, filters, and sinks. A filter is actually a source receiving data from another source, i.e., filtering or manipulating the data in some way. Media streams in Live555 are constructed by combining components into a pipeline. Each pipeline consists of primarily one sink, one source, and an optional set of filters. We provide a visual example of streaming H.264 video in live, in Figure 5.1.

The sink is the initiator of each pipeline. A sink requests a frame of data and sets off a chain of events, eventually retrieving the frame from the source. On the sender side, when a source is requested by a sink to fetch data, the source schedules a background task to fetch this data from a media resource. When the data is ready, the source fetches data and packs it into a frame, appropriate for the media resource type (i.e., H.264). When the frame is fetched, it is instantly delivered to the sink. The sink then encapsulates this frame into an RTP packet, and sends the packet over a network via a socket. On the receiver side, the same logic applies. However, the source fetches network packets when they are available using a socket. The source extracts the network packet payload and deliver this data as a frame to the sink. The sink then uses this data for different applications, such as playback or file recording.

Every source in Live555 is a child of the FramedSource class. This class has an important virtual method called doGetNextFrame. This method is implemented in the parent FramedSource class method getNextFrame. In a child class of FramedSource, this method is overridden to deliver a frame of appropriate data. Then either a filter or a sink calls the getNextFrame of its connected source. Upon execution, we register a afterGetting function in the source class. When the source has finished fetching the frame, it calls the afterGetting function which delivers the frame to the filter or sink.