Привет всем! Хочу поделиться небольшим личным проектом, который родился из чистой бытовой необходимости. Я давно хотел иметь возможность удаленно поглядывать на свою дачу, особенно когда уезжаю на несколько недель. Готовые решения в духе "умных камер" меня не совсем устраивают: то подписки дорогие, то Privacy Policy сомнительная, то функционал избыточный. В итоге я решил, что проще и надежнее будет написать свою собственную утилиту.

Идея проста: поставить на даче маломощный неттоп, подключить к нему обычную веб-камеру, которая будет транслировать видео в интернет, и смотреть трансляцию через телеграм, куда я и так захожу постоянно.

Выбор инструментов пал на два кита: Go и FFmpeg

  • Go (Golang) идеально подошел для этой задачи. Мне нужен один бинарный файл, без зависимостей, который можно просто скопировать на неттоп с любой ОС (в моем случае Linux) и запустить.

  • FFmpeg - я не стал изобретать велосипед и пытаться работать с камерой напрямую, а просто решил поручить всю работу FFmpeg, вызвав его из моей Go-программы.

Код получился на удивление компактным и читаемым.

package main

import (
	"fmt"
	"log"
	"os/exec"
	"runtime"
)

func main() {
	// URL RTMP-сервера назначения (в данном случае для Telegram)
	rtmpURL := "rtmps://dc4-1.rtmp.t.me/s/КЛЮЧ_ТРАНСЛЯЦИИ"

	// Получение имени устройства камеры в зависимости от ОС
	device := getCameraDevice()

	// Формирование аргументов командной строки для FFmpeg:
	args := []string{
		"-f", "v4l2", // Формат входного устройства (для Windows: "dshow")
		"-video_size", "1280x720",
		"-framerate", "30",
		"-i", device, // Источник видео
		"-c:v", "libx264", // Кодек видео
		"-preset", "veryfast", // Настройка скорости кодирования (быстрое)
		"-tune", "zerolatency", // Настройка для минимальной задержки
		"-pix_fmt", "yuv420p", // Формат пикселей (совместимый с большинством плееров)
		"-f", "flv", // Формат выходного контейнера (FLV)
		rtmpURL, // URL назначения для трансляции
	}

	// Создание объекта команды для запуска ffmpeg с подготовленными аргументами
	cmd := exec.Command("ffmpeg", args...)

	// Перенаправление стандартного вывода и вывода ошибок FFmpeg в лог программы
	// Это позволяет видеть диагностические сообщения FFmpeg в консоли
	cmd.Stdout = log.Writer()
	cmd.Stderr = log.Writer()

	// Информационное сообщение о начале трансляции
	fmt.Printf("Запуск трансляции на %s\n", rtmpURL)

	// Запуск команды FFmpeg и ожидание её завершения
	err := cmd.Run()
	if err != nil {
		// Аварийное завершение программы с выводом ошибки, если трансляция не удалась
		log.Fatalf("Ошибка трансляции: %v", err)
	}
}

// Функция для определения устройства камеры в зависимости от операционной системы
func getCameraDevice() string {
	// Использование runtime.GOOS для определения операционной системы
	switch runtime.GOOS {
	case "darwin": // macOS
		return "default" // Стандартное устройство захвата в macOS
	case "linux": // Linux
		return "/dev/video0" // Стандартный путь к устройству видеозахвата
	case "windows": // Windows
		return "video=Integrated Camera" // Имя устройства может отличаться. Пример для встроенной камеры
	default: // Другие ОС
		return "" // Пустая строка для неизвестных систем
	}
}

Как это все работает изнутри

1. Получаем адрес RTMP-сервера Telegram, куда нужно отправлять видео.

Для этого создаем закрытый канал в Telegram, кликаем по значку трансляций, жмем Трансляция с помощью...

копируем ссылку и ключ трансляции, и добавляем ссылку в программу

2. Функция getCameraDevice() определяет операционную систему и в зависимости от нее возвращает путь к камере. Для моего неттопа на Linux это будет /dev/video0.

3. Далее мы формируем команду для FFmpeg, которая говорит ему:

  • -f v4l2: Брать видео с устройства видеозахвата (в Linux).

  • -video_size 1280x720 -framerate 30: Использовать разрешение 720p и 30 кадров в секунду.

  • -i /dev/video0: Смотреть на первую подключенную камеру.

  • -c:v libx264 -preset veryfast -tune zerolatency: Закодировать видео в H.264 очень быстро и с минимальной задержкой - это критично для почти live-трансляции.

  • -f flv: Упаковать все в контейнер FLV, который идеально подходит для стриминга.

  • И отправить получившийся поток по указанному rtmpURL.

Программа запускает FFmpeg как внешний процесс и перенаправляет его логи в свой собственный вывод. Это очень удобно для отладки. Если что-то пойдет не так (например, камера недоступна или неверный URL), мы сразу увидим причину в консоли.

Запустил для проверки на своем ноутбуке, в качестве источника встроенная веб-камера

программа работает без ошибок, далее запускаю трансляцию в своем закрытом Telegram канале

Присутствует небольшая задержка, примерно 2-3 секунды.

Что получилось:

  • Одна команда на запуск. Никаких конфигов, лишних библиотек.

  • Программа работает неделями без перезапуска. Go-приложение не падает, а если упадет FFmpeg, то программу легко перезапустить через systemd.

  • Трансляция потребляет мало ресурсов. На неттопе нагрузка на CPU около 15-20%, что вполне приемлемо.

  • Трансляцию можно смотреть прямо в Telegram - на телефоне, ноутбуке, где угодно.