@AndrewRusinas

Как получить первый кадр из видео?

Пытаюсь извлечь первый кадр видео для использования его в качестве превью. Использую 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 ботов, но все они приводили к тому, что всё ломалось вообще для всех видео.

Буду признателен за любые советы.
  • Вопрос задан
  • 218 просмотров
Пригласить эксперта
Ответы на вопрос 1
@calculator212
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы