Note
🏷️ FR · Vue d'ensemble Application Android de streaming caméra en MJPEG avec serveur HTTP embarqué. Le téléphone capture les images, les compresse en JPEG, puis les expose sur le réseau local via un viewer web, un flux brut et plusieurs endpoints JSON utiles au monitoring.
Tip
🏷️ FR · Accès rapide
- Viewer :
GET /,GET /viewer,GET /monitor - Flux MJPEG :
GET /stream.mjpeg - Snapshot :
GET /snapshot.jpg - Batterie :
GET /api/battery - Statut :
GET /api/status
Important
🏷️ FR · Fonctionnalités
- 📡 Streaming MJPEG depuis le téléphone Android via
GET /stream.mjpeg - 🖥️ Viewer web intégré sur
GET /,GET /vieweretGET /monitor - 🎛️ Interface admin Compose : démarrage/arrêt, port, qualité JPEG, caméra avant/arrière, mode veille
- 🌐 Détection réseau : Wi-Fi, SSID, IP locale, URL viewer, URL flux, URL batterie
- 🔋 Monitoring batterie temps réel avec
isCharging, température et timestamp - 🧠 Service foreground
MjpegStreamingServiceavec WakeLock CPU optionnel
Note
🏷️ FR · Architecture dessinée
Flux réel dans le code : AdminViewModel démarre MjpegStreamingService, le service initialise CameraStreamController, publie les JPEG dans FrameStore, puis MjpegHttpServer sert le viewer, le flux MJPEG, les snapshots, les métriques et l'API batterie.
flowchart LR
A[📱 MainActivity<br/>UI Compose] --> B[🧭 AdminViewModel]
B --> C[⚙️ SettingsRepository]
B --> D[🌐 NetworkRepository]
B -->|start/stop/update| E[🔔 MjpegStreamingService]
E --> F[📷 CameraStreamController]
F -->|JPEG frames| G[(🗂️ FrameStore)]
E --> H[🖼️ ImageManagementService]
E --> I[🔋 Battery tracker]
E --> J[🌍 MjpegHttpServer]
J --> G
J --> H
J --> I
K[💻 Navigateur local / Apache] -->|HTTP| J
J -->|viewer, stream, JSON API| K
Tip
🏷️ FR · SDK & compatibilité Android
Configuration actuelle dans app/build.gradle.kts :
versionName:1.0versionCode:1minSdk:28(Android 9.0+)targetSdk:36(Android 14)compileSdk:36(Android 14)- Java/Kotlin JVM target :
11
Important
🏷️ FR · Permissions manifest
Permissions principales présentes dans app/src/main/AndroidManifest.xml :
android.permission.CAMERAandroid.permission.INTERNETandroid.permission.ACCESS_NETWORK_STATEandroid.permission.ACCESS_WIFI_STATEandroid.permission.ACCESS_FINE_LOCATIONandroid.permission.ACCESS_COARSE_LOCATIONandroid.permission.POST_NOTIFICATIONSandroid.permission.WAKE_LOCKandroid.permission.FOREGROUND_SERVICEandroid.permission.FOREGROUND_SERVICE_CAMERA
Note
🏷️ FR · Endpoints HTTP
Pages
GET /→ page monitoring/viewerGET /viewer→ page monitoring/viewerGET /monitor→ page monitoring/viewer
Flux & snapshots
GET /stream.mjpeg→ flux MJPEG multipartGET /snapshot.jpg→ image JPEG instantanéeGET /favicon.ico→ favicon PNG du viewer
API JSON
GET /api/status→ statut serveur/streamGET /api/battery→ batterie temps réel
{
"ok": true,
"levelPercent": 82,
"isCharging": true,
"temperatureC": 31.4,
"timestampMs": 1773571200000
}Tip
🏷️ FR · Usage rapide
- Installer et lancer l'application sur le téléphone.
- Donner les permissions caméra/localisation demandées.
- Dans l'admin, vérifier ou modifier le port puis appuyer sur Démarrer.
- Récupérer l'IP locale affichée dans la section réseau.
- Ouvrir un navigateur sur le même réseau :
http://<ip-telephone>:<port>/pour le monitoringhttp://<ip-telephone>:<port>/stream.mjpegpour le flux brut
- Vérifier l'API batterie sur
http://<ip-telephone>:<port>/api/battery.
Important
🏷️ FR · Exemple Apache VirtualHost vers l'IP locale du téléphone
Utilisez l'IP locale affichée par l'application, par exemple 192.168.1.50:8080.
Option A — redirection simple vers l'IP locale
<VirtualHost *:80>
ServerName camera.example.local
Redirect "/" "http://192.168.1.50:8080/"
</VirtualHost>Option B — reverse proxy complet recommandé
# Modules utiles : proxy proxy_http headers rewrite
<VirtualHost *:80>
ServerName camera.example.local
ProxyPreserveHost On
ProxyRequests Off
RequestHeader set X-Forwarded-Proto "http"
RequestHeader set X-Forwarded-Host "camera.example.local"
ProxyPass /stream.mjpeg http://192.168.1.50:8080/stream.mjpeg retry=0 connectiontimeout=5 timeout=300 keepalive=On
ProxyPassReverse /stream.mjpeg http://192.168.1.50:8080/stream.mjpeg
ProxyPass /snapshot.jpg http://192.168.1.50:8080/snapshot.jpg
ProxyPassReverse /snapshot.jpg http://192.168.1.50:8080/snapshot.jpg
ProxyPass /favicon.ico http://192.168.1.50:8080/favicon.ico
ProxyPassReverse /favicon.ico http://192.168.1.50:8080/favicon.ico
ProxyPass /api/ http://192.168.1.50:8080/api/
ProxyPassReverse /api/ http://192.168.1.50:8080/api/
ProxyPass / http://192.168.1.50:8080/
ProxyPassReverse / http://192.168.1.50:8080/
</VirtualHost>URL exposées par Apache :
http://camera.example.local/http://camera.example.local/stream.mjpeghttp://camera.example.local/snapshot.jpghttp://camera.example.local/api/statushttp://camera.example.local/api/battery
Note
🏷️ FR · Endpoints utiles en usage
- Viewer :
http://<ip-telephone>:<port>/,http://<ip-telephone>:<port>/viewer,http://<ip-telephone>:<port>/monitor - Flux :
http://<ip-telephone>:<port>/stream.mjpeg - Snapshot :
http://<ip-telephone>:<port>/snapshot.jpg - Favicon :
http://<ip-telephone>:<port>/favicon.ico - Status JSON :
http://<ip-telephone>:<port>/api/status - Batterie JSON :
http://<ip-telephone>:<port>/api/battery
Tip
🏷️ FR · Build local
Set-Location "D:\PATH\TO\CameraMjpeg"
.\gradlew.bat :app:assembleDebugInstallation debug ciblée sur un device ADB :
$apk = "D:\PATH\TO\CameraMjpeg\app\build\intermediates\apk\debug\app-debug.apk"
adb devices
adb -s <device-serial> install -r $apkWarning
🏷️ FR · Notes d'usage & vérification README
- Le titre HTML du viewer utilise dynamiquement le modèle du téléphone.
- Si
INSTALL_FAILED_USER_RESTRICTEDapparaît : activer Installation via USB dans les options développeur. - Si
INSTALL_FAILED_OLDER_SDKapparaît : le téléphone est en dessous deminSdk 24. - Vérifier après édition : rendu des callouts, affichage du diagramme Mermaid, cohérence de l'IP/port Apache, et exactitude des endpoints documentés.
Note
🏷️ EN · Overview Android app for MJPEG camera streaming with an embedded HTTP server. The phone captures frames, compresses them to JPEG, and exposes a local web viewer, raw stream, snapshots, and JSON monitoring endpoints.
Tip
🏷️ EN · Quick access
- Viewer:
GET /,GET /viewer,GET /monitor - MJPEG stream:
GET /stream.mjpeg - Snapshot:
GET /snapshot.jpg - Battery:
GET /api/battery - Status:
GET /api/status
Important
🏷️ EN · Features
- 📡 MJPEG streaming from the Android phone via
GET /stream.mjpeg - 🖥️ Built-in viewer on
GET /,GET /viewer, andGET /monitor - 🎛️ Compose admin UI: start/stop, port, JPEG quality, front/rear camera, keep-awake mode
- 🌐 Network detection: Wi-Fi, SSID, local IP, viewer URL, stream URL, battery API URL
- 🔋 Real-time battery monitoring with charging state, temperature, and timestamp
- 🧠 Foreground service
MjpegStreamingServicewith optional CPU WakeLock
Note
🏷️ EN · Architecture diagram
flowchart LR
A[📱 MainActivity<br/>Compose UI] --> B[🧭 AdminViewModel]
B --> C[⚙️ SettingsRepository]
B --> D[🌐 NetworkRepository]
B -->|start/stop/update| E[🔔 MjpegStreamingService]
E --> F[📷 CameraStreamController]
F -->|JPEG frames| G[(🗂️ FrameStore)]
E --> H[🖼️ ImageManagementService]
E --> I[🔋 Battery tracker]
E --> J[🌍 MjpegHttpServer]
J --> G
J --> H
J --> I
K[💻 Browser / Apache] -->|HTTP| J
J -->|viewer, stream, JSON API| K
Tip
🏷️ EN · Android SDK & compatibility
Current configuration in app/build.gradle.kts:
versionName:1.0versionCode:1minSdk:28(Android 9.0+)targetSdk:36(Android 14)compileSdk:36(Android 14)- Java/Kotlin JVM target:
11
Important
🏷️ EN · Manifest permissions
Main permissions declared in app/src/main/AndroidManifest.xml:
android.permission.CAMERAandroid.permission.INTERNETandroid.permission.ACCESS_NETWORK_STATEandroid.permission.ACCESS_WIFI_STATEandroid.permission.ACCESS_FINE_LOCATIONandroid.permission.ACCESS_COARSE_LOCATIONandroid.permission.POST_NOTIFICATIONSandroid.permission.WAKE_LOCKandroid.permission.FOREGROUND_SERVICEandroid.permission.FOREGROUND_SERVICE_CAMERA
Note
🏷️ EN · HTTP endpoints
- Pages:
GET /,GET /viewer,GET /monitor - Stream:
GET /stream.mjpeg - Snapshot:
GET /snapshot.jpg - Favicon:
GET /favicon.ico - JSON:
GET /api/status,GET /api/battery
{
"ok": true,
"levelPercent": 82,
"isCharging": true,
"temperatureC": 31.4,
"timestampMs": 1773571200000
}Tip
🏷️ EN · Quick start
- Install and launch the app on the phone.
- Grant the requested camera/location permissions.
- In the admin screen, verify or change the port, then tap Start.
- Copy the local IP displayed in the network section.
- Open a browser on the same network:
http://<phone-ip>:<port>/http://<phone-ip>:<port>/stream.mjpeg
- Check battery status on
http://<phone-ip>:<port>/api/battery.
Important
🏷️ EN · Apache VirtualHost example to the phone local IP
Replace 192.168.1.50:8080 with the local address shown in the app.
<VirtualHost *:80>
ServerName camera.example.local
ProxyPreserveHost On
ProxyRequests Off
ProxyPass /stream.mjpeg http://192.168.1.50:8080/stream.mjpeg retry=0 connectiontimeout=5 timeout=300 keepalive=On
ProxyPassReverse /stream.mjpeg http://192.168.1.50:8080/stream.mjpeg
ProxyPass /api/ http://192.168.1.50:8080/api/
ProxyPassReverse /api/ http://192.168.1.50:8080/api/
ProxyPass / http://192.168.1.50:8080/
ProxyPassReverse / http://192.168.1.50:8080/
</VirtualHost>Tip
🏷️ EN · Local build
Set-Location "D:\PATH\TO\CameraMjpeg"
.\gradlew.bat :app:assembleDebugDebug install on a specific ADB device:
$apk = "D:\PATH\TO\CameraMjpeg\app\build\intermediates\apk\debug\app-debug.apk"
adb devices
adb -s <device-serial> install -r $apkWarning
🏷️ EN · Usage notes
- The viewer HTML title uses dynamic phone model detection.
- If
INSTALL_FAILED_USER_RESTRICTEDappears, enable Install via USB in Developer options. - If
INSTALL_FAILED_OLDER_SDKappears, the device is belowminSdk 24.
Important
🏷️ FR · Services foreground
- Le service foreground caméra est déclaré dans le manifest :
<service
android:name=".service.CameraForegroundService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="camera" />- Il est démarré automatiquement par MainActivity lors du lancement de l'application.
- Il garantit la persistance du streaming MJPEG même en arrière-plan.
[!INFO] 🏷️ FR · Mode Android IDE Si l'IDE affiche le projet en mode "Projet" au lieu de "Android" :
- Ouvrez le projet depuis le dossier racine
CameraMjpeg.- Vérifiez la présence de
build.gradle.ktset du dossierapp/.- Cliquez sur "File" > "Sync Project with Gradle Files".
- Si besoin, fermez puis rouvrez le projet.
- Le mode "Android" doit apparaître dans la barre latérale.
🏷️ EN · Android IDE Mode If the IDE shows the project in "Project" mode instead of "Android":
- Open the project from the root folder
CameraMjpeg.- Check for
build.gradle.ktsand theapp/folder.- Click "File" > "Sync Project with Gradle Files".
- If needed, close and reopen the project.
- The "Android" mode should appear in the sidebar.