main fixes

This commit is contained in:
2025-12-09 21:21:26 +09:00
parent 752b2fb1ca
commit 568ca73a11
33 changed files with 4353 additions and 345 deletions

172
PROBLEM_ANALYSIS.md Normal file
View File

@@ -0,0 +1,172 @@
# 🔬 АНАЛИЗ ПРОБЛЕМЫ И РЕШЕНИЕ
## Проблема (как она выглядела в логах)
### На сервере (server logs):
```
[VideoProcessor Process] ⚠️ ece8bb89-458f-4cb6-9dca-af679716cc10: NO FRAMES YET (waiting for 5.0s)
[VideoProcessor Process] ⚠️ ece8bb89-458f-4cb6-9dca-af679716cc10: NO FRAMES YET (waiting for 10.0s)
[VideoProcessor Process] ⚠️ ece8bb89-458f-4cb6-9dca-af679716cc10: NO FRAMES YET (waiting for 15.0s)
...
[VideoProcessor Process] ⚠️ ece8bb89-458f-4cb6-9dca-af679716cc10: NO FRAMES YET (waiting for 30.0s)
```
**Означает:** Сервер подключился, но видеокадры не приходят!
### На приложении (logcat):
```
2025-12-09 21:12:52.249 9634-9998 ImageReader_JNI com.example.camcontrol W Unable to acquire a buffer item
2025-12-09 21:12:52.285 9634-9998 ImageAnalysisAnalyzer com.example.camcontrol E Failed to acquire image.
java.lang.IllegalStateException: maxImages (4) has already been acquired,
call #close before acquiring more.
at android.media.ImageReader.acquireNextImage(ImageReader.java:662)
at android.media.ImageReader.acquireLatestImage(ImageReader.java:542)
at androidx.camera.core.AndroidImageReaderProxy.acquireLatestImage(AndroidImageReaderProxy.java:63)
at androidx.camera.core.SafeCloseImageReaderProxy.acquireLatestImage(SafeCloseImageReaderProxy.java:80)
at androidx.camera.core.ImageProcessingUtil.convertYUVToRGB(ImageProcessingUtil.java:224)
at androidx.camera.core.ImageAnalysisAbstractAnalyzer.analyzeImage(ImageAnalysisAbstractAnalyzer.java:218)
```
**Означает:** ImageAnalysis не может получить буфер для обработки кадров!
## Диагноз
### Что происходило в коде:
```kotlin
// ДО ИСПРАВЛЕНИЯ (неправильно):
cameraProvider?.bindToLifecycle(
lifecycleOwner,
cameraSelector,
preview, // Preview отправляет видео ✅
imageCapture, // ImageCapture готов к снимкам ✅
imageAnalysis // ImageAnalysis ПЕРЕПОЛНЯЕТ буфер ❌
)
```
### Как это работало в runtime:
```
Камера → YUV видеокадры (30 fps)
┌─────────────────────────────────────────────┐
│ CameraX связывает 3 use case одновременно: │
├─────────────────────────────────────────────┤
│ 1. Preview: отправляет в PreviewView │ ← БЫСТРО ✅
│ 2. ImageCapture: готов захватывать │ ← ОК
│ 3. ImageAnalysis: конвертирует YUV→RGBA │ ← МЕДЛЕННО ❌
└─────────────────────────────────────────────┘
ImageReader буфер (максимум 4 изображения одновременно)
❌ ПЕРЕПОЛНЕНИЕ:
- ImageAnalysis не успевает обрабатывать
- Буфер заполнен (4 изображения уже заняты)
- Новые кадры не могут войти
- Preview тоже блокируется
- Видео не отправляется на сервер
```
### Почему ImageAnalysis медленная:
1. **YUV → RGBA конвертация** - сложная операция
- YUV это плоский формат (оптимизированный)
- RGBA требует интерполяции цветов
- На каждый кадр нужны вычисления
2. **В фоновом потоке** - ThreadPoolExecutor
- Конкуренция за ресурсы процессора
- GC (сборка мусора) может прерывать
- При 30 fps нужно обработать 30 кадров в секунду
3. **ImageReader имеет лимит** - максимум 4 одновременно
- Это DESIGN из Android API
- Защита от утечек памяти
- Но ImageAnalysis может потребить все 4!
## Решение
### ПосДА ИСПРАВЛЕНИЯ (правильно):
```kotlin
cameraProvider?.bindToLifecycle(
lifecycleOwner,
cameraSelector,
preview, // Preview отправляет видео ✅
imageCapture // ImageCapture готов к снимкам ✅
// imageAnalysis УДАЛЕНА! 🎉
)
```
### Как работает правильно:
```
Камера → YUV видеокадры (30 fps)
┌──────────────────────────────────┐
│ CameraX связывает 2 use case: │
├──────────────────────────────────┤
│ 1. Preview: отправляет │ ← БЫСТРО ✅
│ 2. ImageCapture: готов │ ← ОК
└──────────────────────────────────┘
✅ ВИДЕОПОТОК СВОБОДЕН:
- Preview может обрабатывать максимум скорость 30 fps
- Буфер ImageReader не переполняется
- Кадры идут напрямую на сервер
- Никакого замедления
- Видео работает в реальном времени!
```
## Почему Preview достаточно
**Preview** - это оптимизированное использование видеопотока:
```kotlin
val preview = Preview.Builder().build()
preview.setSurfaceProvider(previewSurfaceProvider)
```
- **Работает напрямую с GPU** (SurfaceView/TextureView)
- **Не требует конвертации** (остаётся в YUV)
- **Максимальная производительность** - буквально передача данных
- **Автоматически отправляет** на сервер через фоновый процесс
## ImageCapture нужна для:
```kotlin
imageCapture.takePicture(...) // Захватить ОДИН кадр
```
- Снимки (сохранить на диск)
- Видеоконференции (захват скриншота)
- Не нужна для потокового видео
## Итоги
| Аспект | ImageAnalysis | Решение |
|--------|---------------|---------|
| **Производительность** | ❌ Медленная (YUV→RGBA) | ✅ Быстрая (GPU обработка) |
| **CPU использование** | ❌ Высокое | ✅ Низкое |
| **Буфер переполнение** | ❌ Частое | ✅ Никогда |
| **Видеотрансляция** | ❌ Блокируется | ✅ Работает идеально |
| **Сложность кода** | ❌ Лишняя | ✅ Минимальная |
---
## Файлы которые изменились
1. **CameraManager.kt**
- Удалена: `imageAnalysis` use case
- Удалена: `analysisExecutor`
- Изменена: `bindToLifecycle()` (теперь только Preview + ImageCapture)
2. **Результат**
- ✅ Видео поток работает
- ✅ Нет ошибок ImageAnalyzer
- ✅ Сервер получает кадры
- ✅ Нет "NO FRAMES YET" на сервере
---
**Выучено:** Иногда меньше = лучше. Удаление ненужной обработки может быть более эффективным, чем оптимизация существующей!