Пытаюсь извлечь первый кадр видео для использования его в качестве превью. Использую go и ffmpeg.
Получилась вот такая простая функция:
func extractFirstFrame(video []byte) ([]byte, error) {
videoReader := bytes.NewReader(video)
cmd := exec.Command(
"ffmpeg",
"-i", "pipe:0",
"-vframes", "1",
"-an",
"-c:v", "png",
"-f", "rawvideo",
"pipe:1",
)
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, fmt.Errorf("ошибка создания stdin pipe: %v", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("ошибка создания stdout pipe: %v", err)
}
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("ошибка запуска FFmpeg: %v", err)
}
// stderr, err := cmd.StderrPipe()
// if err != nil {
// return nil, fmt.Errorf("ошибка создания stderr pipe: %v", err)
// }
// Чтение логов FFmpeg
// go func() {
// slurp, _ := io.ReadAll(stderr)
// fmt.Printf("FFmpeg logs: %s\n", slurp)
// }()
go func() {
defer stdin.Close()
io.Copy(stdin, videoReader)
}()
imageBytes, err := io.ReadAll(stdout)
if err != nil {
return nil, fmt.Errorf("ошибка чтения результата: %v", err)
}
err = os.WriteFile("PIZDA EBANAYA.jpg", imageBytes, 0644)
if err != nil {
log.Fatalf("Ошибка при записи файла: %v", err)
}
if err := cmd.Wait(); err != nil {
return nil, fmt.Errorf("ошибка выполнения FFmpeg: %v", err)
}
return imageBytes, nil
}
Для контекста, я использую эту функцию в обработчике эндпоинта, который принимает FormData:
form_data, err := c.FormFile("video")
file, err := form_data.Open()
bytes, err := io.ReadAll(file)
preview, err := extractFirstFrame(bytes)
Отправляю с клиента вот так:
uploadVideo(video: Blob, onProgress?: ProgressCallback): Response<UploadVideoResponse> {
if (!feed_id) throw new Error("feed_id is required")
const formData = new FormData()
formData.append('video', video)
return instance.post(`/${version}//videos`, formData, {
onUploadProgress(progress) {
onProgress?.(progress)
},
headers: {
'Content-Type': 'multipart/form-data'
},
})
},
То есть всё достаточно примитивно, однако...
По какой-то причине это срабатывает не для всех видео. Для некоторых видео ffmpeg выдаёт вот такую ошибку:
ffmpeg version 7.0.2-full_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libaribb24 --enable-libaribcaption --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libxevd --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxeve --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libcodec2 --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil 59. 8.100 / 59. 8.100
libavcodec 61. 3.100 / 61. 3.100
libavformat 61. 1.100 / 61. 1.100
libavdevice 61. 1.100 / 61. 1.100
libavfilter 10. 1.100 / 10. 1.100
libswscale 8. 1.100 / 8. 1.100
libswresample 5. 1.100 / 5. 1.100
libpostproc 58. 1.100 / 58. 1.100
[mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562ff0e80] stream 0, offset 0x30: partial file
[mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562ff0e80] Could not find codec parameters for stream 1 (Video: h264 (avc1 / 0x31637661), none, 720x1280, 3093 kb/s): unspecified pixel format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'pipe:0':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
creation_time : 2024-08-09T20:00:29.000000Z
Duration: 00:00:06.80, start: 0.000000, bitrate: N/A
Stream #0:0[0x1](eng): Audio: aac (mp4a / 0x6134706D), 22050 Hz, stereo, fltp, 74 kb/s (default)
Metadata:
creation_time : 2024-08-09T20:00:23.000000Z
handler_name : SoundHandle
vendor_id : [0][0][0][0]
Stream #0:1[0x2](eng): Video: h264 (avc1 / 0x31637661), none, 720x1280, 3093 kb/s, 30 fps, 30 tbr, 90k tbn (default)
Metadata:
creation_time : 2024-08-09T20:00:23.000000Z
handler_name : VideoHandle
vendor_id : [0][0][0][0]
Stream mapping:
Stream #0:1 -> #0:0 (h264 (native) -> mjpeg (native))
[mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562ff0e80] stream 1, offset 0x5d: partial file
[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562fda2c0] Error during demuxing: Invalid data found when processing input
Cannot determine format of input 0:1 after EOF
[vf#0:0 @ 000002a5636c0ec0] Task finished with error code: -1094995529 (Invalid data found when processing input)
[vf#0:0 @ 000002a5636c0ec0] Terminating thread with return code -1094995529 (Invalid data found when processing input)
[vost#0:0/mjpeg @ 000002a5636c0400] Could not open encoder before EOF
[vost#0:0/mjpeg @ 000002a5636c0400] Task finished with error code: -22 (Invalid argument)
[vost#0:0/mjpeg @ 000002a5636c0400] Terminating thread with return code -22 (Invalid argument)
[out#0/image2 @ 000002a562ff5640] Nothing was written into output file, because at least one of its streams received no packets.
frame= 0 fps=0.0 q=0.0 Lsize= 0KiB time=N/A bitrate=N/A speed=N/A
Conversion failed!
При том, что ровно это же видео через командную строку (
ffmpeg -i .\video_2024-08-10_00-03-00.mp4 -vf "select=eq(n\,0)" -q:v 3 output_image.jpg
)обрабатывается совершенно нормально, я получаю ожидаемый результат.
Почему-то вызывают ошибку видео, снятые на телефон, либо рилсы, скачанные из инстаграма. Думал, что проблема исключительно с вертикальными видео, но нет, вертикальное видео из интернета нормально обработалось.
Формат всех видео .mp4, поэтому я в замешательстве что может быть не так и почему через терминал всё обрабатывается нормально. Отправка FormData в целом должна гарантировать сохранность метаданных, да и опять же, одни обрабатываются, другие нет, с чего бы? Размер тоже не имеет значения.
Попробовал с десяток различных рекомендаций от AI ботов, но все они приводили к тому, что всё ломалось вообще для всех видео.
Буду признателен за любые советы.