Как разделить видеофайл на небольшие фрагменты и загрузить на сервер?
Пешу пет-проект для саморазвития и столкнулся со следующей проблемой:
На сайте есть форма загрузки файлов. Все файлы разделяются на чанки и по очереди загружаются на сервер по api.
На первом чанке создаётся файл, а на последующих дополняется текст (из чанка) в конце файла.
Загружать фото/pdf в таком формате получается. А вот с архивами и видео (только эти форматы ещё проверил) не подходит. Архив вообще не открывается (даже ошибки нет), а видео максимум длится пару секунд (скорей всего это нормальный первый чанк созданный) и зависает.
PS: В идеале хочу в S3 хранилище загрузить. Но пока тестирую - загружаю локально.
Обработка чанков и их загрузка:
const uploadFile = async () => { let number_chunk = 1; let max_chunk = chunks.value.length; statusUpload.value = true; for (let chunk of chunks.value) { const upload = await uploadChunk(chunk, number_chunk, max_chunk); if (!upload) { console.log('Ошибка загрузки файла') break; } activeUploadChunk.value += 1; number_chunk += 1; } statusUpload.value = false; } |
const uploadFile = async () => { let number_chunk = 1; let max_chunk = chunks.value.length; statusUpload.value = true; for (let chunk of chunks.value) { const upload = await uploadChunk(chunk, number_chunk, max_chunk); if (!upload) { console.log('Ошибка загрузки файла') break; } activeUploadChunk.value += 1; number_chunk += 1; } statusUpload.value = false; }
Загрузка файла:
const uploadChunk = async (chunk, number_chunk, max_chunk) => { let formData = new FormData(); formData.append('name', file.value.files[0].name) formData.append('type', file.value.files[0].type) formData.append('number_chunk', number_chunk) formData.append('max_chunk', max_chunk) formData.append('chunk', chunk); const {data, error} = await useAsyncData(() => client('/api/videos/upload', { method: 'post', body: formData, })); return error; } |
const uploadChunk = async (chunk, number_chunk, max_chunk) => { let formData = new FormData(); formData.append('name', file.value.files[0].name) formData.append('type', file.value.files[0].type) formData.append('number_chunk', number_chunk) formData.append('max_chunk', max_chunk) formData.append('chunk', chunk); const {data, error} = await useAsyncData(() => client('/api/videos/upload', { method: 'post', body: formData, })); return error; }
Laravel метод загрузки:
public function upload(Request $request) { if ($request->hasFile('chunk')) { $data = $request->all(); $chunk = $request->file('chunk'); // Имя файла $fileName = $data['name']; $exlodeName = explode('.', $fileName); $fileExtension = $exlodeName[count($exlodeName) - 1]; $fileName = md5($fileName) . '.' . $fileExtension; $storage = Storage::disk('public'); try { if ($data['number_chunk'] === 1) { $save = $storage->put($fileName, new File($chunk)); } else { $save = $storage->append($fileName, file_get_contents($chunk)); } sleep(1); if ($save) { return response()->json([ 'type' => 'success', 'message' => 'Файл успешно загружен', ], 200); } } catch (Exception $e) { return response()->json([ 'type' => 'error', 'message' => 'Ошибка загрузки файла', ], 500); } } } |
public function upload(Request $request) { if ($request->hasFile('chunk')) { $data = $request->all(); $chunk = $request->file('chunk'); // Имя файла $fileName = $data['name']; $exlodeName = explode('.', $fileName); $fileExtension = $exlodeName[count($exlodeName) - 1]; $fileName = md5($fileName) . '.' . $fileExtension; $storage = Storage::disk('public'); try { if ($data['number_chunk'] === 1) { $save = $storage->put($fileName, new File($chunk)); } else { $save = $storage->append($fileName, file_get_contents($chunk)); } sleep(1); if ($save) { return response()->json([ 'type' => 'success', 'message' => 'Файл успешно загружен', ], 200); } } catch (Exception $e) { return response()->json([ 'type' => 'error', 'message' => 'Ошибка загрузки файла', ], 500); } } }
Вообще правильно ли я делаю или есть более удобный и правильный вариант (без плагинов/компонентов и т.п.)? Заранее спасибо.
Дополнительно:
Решено. Спасибо за наводку YepBro на счёт сверки файлов побайтово. Это дало понять что не правильно записывал файл.
Решение:
$save = $storage->append($fileNameBlob, file_get_contents($chunk)); |
$save = $storage->append($fileNameBlob, file_get_contents($chunk));
поменять на
$save = file_put_contents(storage_path('/app/public/' . $fileNameBlob), file_get_contents($chunk), FILE_APPEND | LOCK_EX); |
$save = file_put_contents(storage_path('/app/public/' . $fileNameBlob), file_get_contents($chunk), FILE_APPEND | LOCK_EX);
Флаг "LOCK_EX", наверное, необязателен. Но ради блокировки записи я его поставил.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для разделения видеофайла на небольшие фрагменты и их последующей загрузки на сервер, можно воспользоваться следующим подходом:
1. Используем библиотеку FFmpeg для разделения видеофайла на фрагменты. FFmpeg - это мощный инструмент для обработки видео и аудио файлов. Установите FFmpeg на свой компьютер.
2. Создайте PHP скрипт, который будет вызывать FFmpeg и разделять видеофайл на небольшие фрагменты. Ниже приведен пример кода:
$videoPath = 'путь_к_видеофайлу.mp4'; $outputPath = 'путь_к_папке_для_фрагментов/'; $fragmentDuration = 10; // длительность каждого фрагмента в секундах exec("ffmpeg -i $videoPath -c copy -segment_time $fragmentDuration -f segment $outputPath%d.mp4");
3. После того, как видеофайл будет разделен на фрагменты, вы можете загрузить их на сервер. Для этого воспользуйтесь стандартным методом загрузки файлов в PHP, например, с использованием функции move_uploaded_file.
4. При загрузке фрагментов на сервер, убедитесь, что у вас достаточно места для хранения всех фрагментов видеофайла.
5. После загрузки всех фрагментов на сервер, вы сможете объединить их обратно в единый видеофайл, если это необходимо.
Таким образом, с помощью указанных шагов вы сможете успешно разделить видеофайл на небольшие фрагменты и загрузить их на сервер.