368 lines
9.8 KiB
Markdown
368 lines
9.8 KiB
Markdown
|
|
# convertToDash()
|
|||
|
|
|
|||
|
|
Главная функция для конвертации видео в адаптивные форматы DASH и HLS.
|
|||
|
|
|
|||
|
|
## Сигнатура
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
async function convertToDash(
|
|||
|
|
options: DashConvertOptions
|
|||
|
|
): Promise<DashConvertResult>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Параметры
|
|||
|
|
|
|||
|
|
### `DashConvertOptions`
|
|||
|
|
|
|||
|
|
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|
|||
|
|
|----------|-----|--------------|--------------|----------|
|
|||
|
|
| `input` | `string` | ✅ | - | Путь к входному видео файлу |
|
|||
|
|
| `outputDir` | `string` | ✅ | - | Директория для выходных файлов |
|
|||
|
|
| `segmentDuration` | `number` | ❌ | `2` | Длительность сегмента в секундах |
|
|||
|
|
| `profiles` | `VideoProfile[]` | ❌ | автовыбор | Массив профилей качества |
|
|||
|
|
| `customProfiles` | `string[]` | ❌ | автовыбор | Профили как строки (например, `['720', '1080@60']`) |
|
|||
|
|
| `codec` | `CodecType` | ❌ | `'dual'` | Кодек: `'h264'`, `'av1'` или `'dual'` |
|
|||
|
|
| `format` | `StreamingFormat` | ❌ | `'both'` | Формат: `'dash'`, `'hls'` или `'both'` |
|
|||
|
|
| `useNvenc` | `boolean` | ❌ | auto | Использовать NVENC (автоопределение) |
|
|||
|
|
| `quality` | `QualitySettings` | ❌ | auto | Настройки качества (CQ/CRF) |
|
|||
|
|
| `generateThumbnails` | `boolean` | ❌ | `true` | Генерировать превью-спрайт |
|
|||
|
|
| `thumbnailConfig` | `ThumbnailConfig` | ❌ | см. ниже | Конфигурация превью |
|
|||
|
|
| `generatePoster` | `boolean` | ❌ | `true` | Генерировать постер |
|
|||
|
|
| `posterTimecode` | `string` | ❌ | `'00:00:01'` | Таймкод постера |
|
|||
|
|
| `parallel` | `boolean` | ❌ | `true` | Параллельное кодирование |
|
|||
|
|
| `onProgress` | `function` | ❌ | - | Колбэк для прогресса |
|
|||
|
|
|
|||
|
|
## Возвращаемое значение
|
|||
|
|
|
|||
|
|
### `DashConvertResult`
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
interface DashConvertResult {
|
|||
|
|
manifestPath: string; // Путь к DASH манифесту
|
|||
|
|
hlsManifestPath?: string; // Путь к HLS манифесту (если format='hls' или 'both')
|
|||
|
|
segments: string[]; // Пути к сегментам
|
|||
|
|
thumbnailPath?: string; // Путь к спрайту превью
|
|||
|
|
posterPath?: string; // Путь к постеру
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Примеры
|
|||
|
|
|
|||
|
|
### Базовое использование
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { convertToDash } from '@grom13/adaptive-video-converter';
|
|||
|
|
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log('DASH манифест:', result.manifestPath);
|
|||
|
|
console.log('HLS манифест:', result.hlsManifestPath);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С кастомными профилями
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
customProfiles: ['360', '720', '1080']
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С высоким FPS
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './gameplay.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
customProfiles: ['720@60', '1080@60', '1440@120']
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Выбор кодека
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// Только H.264
|
|||
|
|
await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
codec: 'h264'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Только AV1
|
|||
|
|
await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
codec: 'av1'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Оба кодека (по умолчанию)
|
|||
|
|
await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
codec: 'dual'
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Выбор формата
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// Только DASH
|
|||
|
|
await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
format: 'dash'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Только HLS
|
|||
|
|
await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
format: 'hls',
|
|||
|
|
codec: 'h264' // HLS лучше работает с H.264
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Оба формата (по умолчанию)
|
|||
|
|
await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
format: 'both'
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С отслеживанием прогресса
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
onProgress: (progress) => {
|
|||
|
|
console.log(`Прогресс: ${progress.percent}%`);
|
|||
|
|
console.log(`Этап: ${progress.stage}`);
|
|||
|
|
console.log(`Профиль: ${progress.currentProfile}`);
|
|||
|
|
console.log(`ETA: ${progress.eta}s`);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С настройками качества
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
quality: {
|
|||
|
|
h264: {
|
|||
|
|
cq: 28, // CQ для GPU
|
|||
|
|
crf: 23 // CRF для CPU (фоллбек)
|
|||
|
|
},
|
|||
|
|
av1: {
|
|||
|
|
cq: 35,
|
|||
|
|
crf: 35
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С кастомной конфигурацией превью
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
thumbnailConfig: {
|
|||
|
|
width: 320, // Ширина превью
|
|||
|
|
height: 180, // Высота превью
|
|||
|
|
interval: 2, // Интервал в секундах
|
|||
|
|
columns: 10, // Колонок в спрайте
|
|||
|
|
rows: 10 // Строк в спрайте
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С кастомным постером
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
posterTimecode: '00:02:30' // Постер с 2:30
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Без превью и постера
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
generateThumbnails: false,
|
|||
|
|
generatePoster: false
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С предварительной проверкой системы
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import {
|
|||
|
|
convertToDash,
|
|||
|
|
checkFFmpeg,
|
|||
|
|
checkMP4Box,
|
|||
|
|
checkNvenc
|
|||
|
|
} from '@grom13/adaptive-video-converter';
|
|||
|
|
|
|||
|
|
// Проверки перед конвертацией
|
|||
|
|
try {
|
|||
|
|
await checkFFmpeg();
|
|||
|
|
await checkMP4Box();
|
|||
|
|
const hasNvenc = await checkNvenc();
|
|||
|
|
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
useNvenc: hasNvenc // Явное указание
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log('Успешно!', result.manifestPath);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Ошибка:', error.message);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Последовательное кодирование (без параллелизма)
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
parallel: false // Медленнее, но меньше нагрузка
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### С кастомными профилями (объектами)
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import type { VideoProfile } from '@grom13/adaptive-video-converter';
|
|||
|
|
|
|||
|
|
const customProfiles: VideoProfile[] = [
|
|||
|
|
{
|
|||
|
|
name: '720p',
|
|||
|
|
width: 1280,
|
|||
|
|
height: 720,
|
|||
|
|
videoBitrate: '2500k',
|
|||
|
|
audioBitrate: '128k',
|
|||
|
|
fps: 30
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: '1080p',
|
|||
|
|
width: 1920,
|
|||
|
|
height: 1080,
|
|||
|
|
videoBitrate: '5000k',
|
|||
|
|
audioBitrate: '192k',
|
|||
|
|
fps: 30
|
|||
|
|
}
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
profiles: customProfiles
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Обработка ошибок
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
try {
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log('✅ Успешно');
|
|||
|
|
} catch (error) {
|
|||
|
|
if (error.message.includes('FFmpeg not found')) {
|
|||
|
|
console.error('FFmpeg не установлен');
|
|||
|
|
} else if (error.message.includes('MP4Box not found')) {
|
|||
|
|
console.error('MP4Box не установлен');
|
|||
|
|
} else if (error.message.includes('File not found')) {
|
|||
|
|
console.error('Входной файл не найден');
|
|||
|
|
} else {
|
|||
|
|
console.error('Ошибка конвертации:', error.message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Поведение по умолчанию
|
|||
|
|
|
|||
|
|
Если не указаны параметры:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output'
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Эквивалентно:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const result = await convertToDash({
|
|||
|
|
input: './video.mp4',
|
|||
|
|
outputDir: './output',
|
|||
|
|
segmentDuration: 2,
|
|||
|
|
codec: 'dual',
|
|||
|
|
format: 'both',
|
|||
|
|
useNvenc: true, // если доступен
|
|||
|
|
generateThumbnails: true,
|
|||
|
|
generatePoster: true,
|
|||
|
|
posterTimecode: '00:00:01',
|
|||
|
|
parallel: true,
|
|||
|
|
customProfiles: автовыбор на основе исходного видео
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Автовыбор профилей
|
|||
|
|
|
|||
|
|
Если `profiles` и `customProfiles` не указаны:
|
|||
|
|
|
|||
|
|
| Исходное разрешение | Выбранные профили |
|
|||
|
|
|---------------------|-------------------|
|
|||
|
|
| ≤ 720p | 360p, 480p, 720p |
|
|||
|
|
| 1080p | 360p, 720p, 1080p |
|
|||
|
|
| 1440p | 720p, 1080p, 1440p |
|
|||
|
|
| 2160p (4K) | 1080p, 1440p, 2160p |
|
|||
|
|
|
|||
|
|
FPS профилей соответствует исходному видео (максимум 120fps).
|
|||
|
|
|
|||
|
|
## Структура вывода
|
|||
|
|
|
|||
|
|
После вызова `convertToDash()` создается следующая структура:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
output/
|
|||
|
|
└── video/
|
|||
|
|
├── manifest.mpd # DASH манифест
|
|||
|
|
├── master.m3u8 # HLS мастер-плейлист (если format='hls' или 'both')
|
|||
|
|
├── 720p-h264/ # Сегменты профиля
|
|||
|
|
│ ├── 720p-h264_init.mp4
|
|||
|
|
│ ├── 720p-h264_1.m4s
|
|||
|
|
│ └── ...
|
|||
|
|
├── 720p-av1/
|
|||
|
|
├── 1080p-h264/
|
|||
|
|
├── 1080p-av1/
|
|||
|
|
├── thumbnails.jpg # Спрайт превью
|
|||
|
|
├── thumbnails.vtt # WebVTT метки
|
|||
|
|
├── poster.jpg # Постер
|
|||
|
|
└── conversion.log # Лог конвертации
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## См. также
|
|||
|
|
|
|||
|
|
- [Утилиты](/api/utilities) — Вспомогательные функции
|
|||
|
|
- [Профили](/api/profiles) — Работа с профилями
|
|||
|
|
- [Типы](/api/types) — Все TypeScript типы
|