Android Support¶
MediaX includes a native H.264 backend for Android built on the NDK's AMediaCodec API, allowing Android devices to transmit and receive RFC 6184 H.264 RTP streams using the same RtpPayloader/RtpDepayloader interfaces used everywhere else in MediaX.
Overview¶
- Hardware-accelerated H.264 encode/decode via
AMediaCodec(video/avc) - Byte-buffer input/output mode — no
ANativeWindowdependency, since Qt does not expose a public API to obtain one from aQVideoWidget - Implements RFC 6184 packetization/depacketization (Single NAL Unit Mode and FU-A fragmentation)
- Decoded/encoded YUV is converted via
mediax::video::ColourSpaceFactory, matching theCallback()/Receive()convention of every other MediaX H.264 backend - No GStreamer dependency
- Ported from the Android-only
gva-app-bmsstreaming implementation (AndroidH264Encoder/AndroidH264DecoderandRtpH264Packetizer/RtpH264Receiver)
Building for Android¶
Android support is enabled automatically when configuring with the Android NDK's CMake toolchain file — there is no separate BUILD_ANDROID option:
cmake -B build \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-26 \
-DBUILD_QT6=ON ..
make -C build -j$(nproc)
When CMake detects ANDROID, MediaX:
- Defines
MEDIAX_HAS_ANDROID=1 - Compiles
h264/android/rtp_h264_android_payloader.cc,rtp_h264_android_depayloader.ccandandroid_probe.cc - Links against the NDK
mediandk(AMediaCodec) library - Links Bionic's combined libc (no separate
libpthreadsince Android 5.0)
Transmitting H.264 Video¶
#include "h264/android/rtp_h264_android_payloader.h"
mediax::rtp::h264::android::RtpH264AndroidPayloader payloader;
mediax::rtp::StreamInformation stream_info;
stream_info.session_name = "android-h264";
stream_info.hostname = "239.192.1.1";
stream_info.port = 5004;
stream_info.width = 1280;
stream_info.height = 720;
stream_info.framerate = 30;
// Frames passed to Transmit() must be tightly-packed NV12
stream_info.encoding = mediax::rtp::ColourspaceType::kColourspaceNv12;
payloader.SetStreamInfo(stream_info);
mediax::rtp::h264::android::AndroidEncoderConfig config;
config.bitrate_bps = 2000000;
config.framerate = 30;
config.i_frame_interval_secs = 2;
payloader.SetEncoderConfig(config);
payloader.SetMtu(1400);
payloader.Open();
// Send NV12 frames captured from the device camera
std::vector<uint8_t> nv12_buffer(1280 * 720 * 3 / 2);
payloader.Transmit(nv12_buffer.data(), true);
payloader.Close();
Receiving H.264 Video¶
#include "h264/android/rtp_h264_android_depayloader.h"
mediax::rtp::h264::android::RtpH264AndroidDepayloader depayloader;
mediax::rtp::StreamInformation stream_info;
stream_info.hostname = "239.192.1.1";
stream_info.port = 5004;
stream_info.width = 1280;
stream_info.height = 720;
stream_info.encoding = mediax::rtp::ColourspaceType::kColourspaceH264Part10;
depayloader.SetStreamInfo(stream_info);
depayloader.Open();
depayloader.Start();
mediax::rtp::RtpFrameData frame_data{};
if (depayloader.Receive(&frame_data, 1000)) {
// frame_data.cpu_buffer contains decoded RGB24 data
}
depayloader.Stop();
depayloader.Close();
Capability Probing¶
Use AndroidH264Probe to check whether the device exposes a usable hardware encoder/decoder before opening a stream:
#include "h264/android/android_probe.h"
if (mediax::rtp::h264::android::AndroidH264Probe::HasH264Encoder()) {
// Safe to construct RtpH264AndroidPayloader
}
if (mediax::rtp::h264::android::AndroidH264Probe::HasH264Decoder()) {
// Safe to construct RtpH264AndroidDepayloader
}
Qt6 Integration¶
The Qt6 layer provides thin QObject wrappers for Android streaming:
mediax::qt6::QtRtpAndroidPayloader— transmit wrapper aroundRtpH264AndroidPayloadermediax::qt6::QtRtpAndroidDepayloader— receive wrapper aroundRtpH264AndroidDepayloader
Multicast Reception on Android¶
Android's Wi-Fi chipset/driver power-saving filter silently drops incoming multicast frames at the driver level, even though a socket's IP_ADD_MEMBERSHIP join reports success. mediax::qt6::QtAndroidMulticastLock is an RAII wrapper around WifiManager.MulticastLock that must be held for as long as the app is receiving multicast traffic (SAP discovery, RTP video reception). Senders (QtSapAnnouncer, QtRtpAndroidPayloader) do not need it since only inbound multicast is affected.
#include "qt6/QtAndroidMulticastLock.h"
// Acquire once before starting any multicast receiver
mediax::qt6::QtAndroidMulticastLock multicast_lock("MediaXReceiver");
multicast_lock.acquire();
// ... start QtSapListener / QtRtpAndroidDepayloader ...
// Released automatically when multicast_lock goes out of scope,
// or explicitly via multicast_lock.release()
This is the only Android/JNI-specific code in MediaX's Qt6 layer — the core (non-Qt) library stays JNI-free.
Limitations¶
Note
- No
ANativeWindowsurface rendering path — decoded frames are always returned as CPU-side RGB24 buffers via byte-buffer mode. - Requires Android API level with NDK
AMediaCodecsupport (API 21+; API 26+ recommended for the most reliable encoder behaviour).
See Also¶
- H.264 Video — other H.264 hardware backends (VAAPI, NVENC, OpenH264, V4L2 M2M)
- Qt6 API Reference — Qt6 widget wrappers
- Hardware Acceleration — platform/backend support matrix