Files
cam_control_android/TESTING_GUIDE.md
2025-12-09 21:21:26 +09:00

14 KiB
Raw Permalink Blame History

🎥 CamControl - Исправления Видеопотока

Статус: ГОТОВО К ТЕСТИРОВАНИЮ

Проект успешно скомпилирован и содержит все исправления для отправки видео на сервер.


📋 Что было исправлено

Проблема

Приложение показывало превью камеры локально, но видео вообще не отправлялось на сервер.

Причины

  1. CameraManager захватывал только превью, но не обрабатывал видеофреймы
  2. MainActivity запускал камеру, но не передавал фреймы в ViewModel
  3. WebSocketManager использовал хрупкую рефлексию для бинарных данных
  4. Цепь обработки: Камера → Фреймы → Сервер была разорвана

Решение

  • Добавлен ImageAnalysis в CameraManager для захвата фреймов
  • Добавлен callback onFrame в MainActivity для передачи фреймов в ViewModel
  • Исправлена отправка бинарных данных в WebSocketManager (окончательная рефлексия → okio.ByteString)
  • Улучшено логирование для отслеживания процесса

📁 Измененные файлы

1 CameraManager.kt (Основное изменение)

Добавлено:

  • ImageAnalysis для захвата видеофреймов
  • Метод processFrame() для обработки каждого фрейма
  • Callback onFrame для отправки фреймов наружу
  • analysisExecutor для асинхронной обработки

Ключевые строки:

// Захват фреймов
val imageAnalysis = ImageAnalysis.Builder()
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
    .build()
    .apply {
        setAnalyzer(analysisExecutor) { imageProxy ->
            processFrame(imageProxy)
        }
    }

// Обработка каждого фрейма
private fun processFrame(imageProxy: ImageProxy) {
    val frameData = ByteArray(buffer.remaining())
    buffer.get(frameData)
    onFrameAvailable?.invoke(frameData)
}

2 MainActivity.kt (Критическое изменение)

Добавлено:

  • Callback onFrame при запуске камеры
  • Передача фреймов в ViewModel через sendVideoFrame()

Ключевые строки:

cameraManager.startCamera(
    lifecycleOwner,
    pv.surfaceProvider,
    onError = { err -> Log.e("CameraManager", "Camera error: $err") },
    onFrame = { frameData ->
        viewModel.sendVideoFrame(frameData)  // ← ГЛАВНОЕ!
    }
)

3 WebSocketManager.kt (Техническое улучшение)

Изменено:

  • Заменена рефлексия на стандартный API okio
  • Улучшена надежность и производительность

Ключевые строки:

// Было (рефлексия):
val byteStringClass = Class.forName("okhttp3.ByteString")
val ofMethod = byteStringClass.getMethod("of", ByteArray::class.java)
val byteString = ofMethod.invoke(null, data)
val sendMethod = WebSocket::class.java.getMethod("send", byteStringClass)
sendMethod.invoke(webSocket, byteString)

// Стало (clean API):
import okio.ByteString.Companion.toByteString
val byteString = data.toByteString()
webSocket?.send(byteString)

4 StreamViewModel.kt (Логирование)

Улучшено:

  • Логирование FPS (фреймов в секунду)
  • Логирование объема переданных данных
  • Трассировка исключений при ошибках

5 AndroidManifest.xml (Очистка)

Удалены ненужные разрешения:

  • SEND_SMS
  • RECORD_AUDIO
  • ACCESS_COARSE_LOCATION
  • ACCESS_FINE_LOCATION

🚀 Как тестировать

Шаг 1: Убедитесь, что сервер работает

python manage.py runserver 192.168.0.112:8000

Шаг 2: Запустите приложение

./gradlew installDebug
# Или используйте Android Studio: Run > Run 'app'

Шаг 3: Введите параметры подключения

  • Server IP: 192.168.0.112
  • Server Port: 8000
  • Room ID: HhfoHArOGcT
  • Password: 1

Шаг 4: Проверьте логи

adb logcat | grep -E "CameraManager|WebSocket|StreamViewModel"

Ожидаемые логи:

CameraManager: Camera started successfully with video streaming
StreamViewModel: Connected to server
CameraManager: Processing 25 frames/5s, sending to server
WebSocket: Binary data sent: 12345 bytes
StreamViewModel: FPS: 25, Total bytes sent: 308640

Шаг 5: Проверьте, что видео получено на сервере


🔍 Диагностика

Если видео не отправляется

Проверить логи:

# Все логи приложения
adb logcat | grep com.example.camcontrol

# Только ошибки
adb logcat | grep ERROR

# Только WebSocket
adb logcat | grep WebSocket

# Только CameraManager
adb logcat | grep CameraManager

Что проверить:

  1. ✓ WebSocket подключен: Connected! Response code=101
  2. ✓ Камера запущена: Camera started successfully
  3. ✓ Фреймы отправляются: Binary data sent: X bytes
  4. ✓ Нет исключений: ошибок в logcat

Если подключение не работает

Проверьте:

  1. IP адрес сервера доступен: ping 192.168.0.112
  2. Сервер слушает на правильном порту: netstat -ln | grep 8000
  3. Сетевая конфигурация Android: app/src/main/res/xml/network_security_config.xml

📊 Структура потока видео

┌──────────────────────────────────────────────────────┐
│ Android Device                                       │
├──────────────────────────────────────────────────────┤
│                                                      │
│  ┌─────────────┐                                     │
│  │   Camera    │ (задняя камера)                    │
│  └──────┬──────┘                                     │
│         │                                            │
│         │ RGBA_8888 frames                          │
│         ▼                                            │
│  ┌─────────────────────────────────┐               │
│  │ CameraManager.processFrame()     │               │
│  │ - Extract pixel data            │               │
│  │ - Convert to ByteArray          │               │
│  │ - Invoke onFrameAvailable       │               │
│  └──────┬──────────────────────────┘               │
│         │                                            │
│         │ ByteArray (frame data)                    │
│         ▼                                            │
│  ┌──────────────────────────────────────────────┐  │
│  │ MainActivity                                   │  │
│  │ - Receive frame in onFrame callback          │  │
│  │ - Call viewModel.sendVideoFrame(frameData)   │  │
│  └──────┬───────────────────────────────────────┘  │
│         │                                            │
│         │ ByteArray (frame data)                    │
│         ▼                                            │
│  ┌────────────────────────────────────────────────┐ │
│  │ StreamViewModel                                 │ │
│  │ - sendVideoFrame(frameData)                     │ │
│  │ - wsManager.sendBinary(frameData)              │ │
│  │ - Update statistics (FPS, bytes sent)          │ │
│  └────────┬─────────────────────────────────────┘ │
│           │                                         │
│           │ okio.ByteString                        │
│           ▼                                         │
│  ┌────────────────────────────────────────────────┐ │
│  │ WebSocketManager                                │ │
│  │ - Convert to okio.ByteString                    │ │
│  │ - webSocket.send(byteString)                    │ │
│  └────────┬─────────────────────────────────────┘ │
│           │                                         │
└───────────┼─────────────────────────────────────────┘
            │
            │ WebSocket Binary Frame
            ▼
┌──────────────────────────────────────────────────────┐
│ Server (192.168.0.112:8000)                          │
│ - Receive frame                                       │
│ - Decode frame                                        │
│ - Display video                                       │
└──────────────────────────────────────────────────────┘

💡 Оптимизация (для будущего)

1. Кодирование видео

Сейчас отправляются raw RGBA фреймы (~3 МБ/сек при 30fps, 1920x1080)

Что сделать:

  • Использовать H.264 кодирование (видео кодек)
  • Или VP9/AV1 для лучшего качества
  • Это уменьшит пропускную способность в 10-100 раз

Код:

import androidx.camera.video.VideoCapture
import androidx.camera.video.Recording

// Использовать VideoCapture вместо ImageAnalysis
val videoCapture = VideoCapture.withOutput(...)

2. Масштабирование

  • Уменьшить разрешение перед отправкой
  • Добавить регулировку качества

3. Буферизация

  • Добавить очередь фреймов при медленной сети
  • Пропускать фреймы при отставании

📝 История изменений

Дата Изменение
2025-12-03 Найдена проблема: видео не отправляется на сервер
2025-12-03 Добавлен ImageAnalysis в CameraManager
2025-12-03 Добавлен callback onFrame в MainActivity
2025-12-03 Исправлена отправка бинарных данных в WebSocketManager
2025-12-03 Проект успешно скомпилирован

FAQ

Q: Почему видео не показывается на сервере? A: Проверьте, что:

  1. WebSocket подключен (logcat: "Connected! Response code=101")
  2. Приложение запустило камеру (logcat: "Camera started successfully")
  3. Логи показывают "Binary data sent" (фреймы отправляются)

Q: Почему столько данных отправляется? A: Отправляются raw RGBA фреймы без кодирования. Это 3-4 МБ/сек. Используйте H.264 видеокодирование для сжатия (см. раздел "Оптимизация").

Q: Можно ли изменить разрешение камеры? A: Да, добавьте в CameraManager:

val imageAnalysis = ImageAnalysis.Builder()
    .setTargetResolution(android.util.Size(640, 480))  // Меньшее разрешение
    .build()

Q: Как отладить проблемы с WebSocket? A: Используйте фильтр в logcat:

adb logcat | grep "WebSocket"

🎯 Следующие шаги

  1. Скомпилировать проект (./gradlew build)
  2. Запустить на устройстве
  3. Проверить логи в logcat
  4. Убедиться, что видео отправляется на сервер
  5. 📋 Оптимизировать качество видео и битрейт
  6. 📋 Добавить кодирование видео (H.264)
  7. 📋 Реализовать переподключение при разрыве

Создано: 2025-12-03
Статус: Готово к тестированию
Контакт: Trevor (тестирующий)