So extrahieren Sie einen Videoframe mit einer NVIDIA-Karte

Ich möchte mit einer NVIDIA-Karte einen Frame aus dem h264-Videostream extrahieren.
Zuerst müssen wir diesen Stream über den h264_cuvid-Decoder dekodieren:

ffmpeg -hwaccel cuvid -c:v h264_cuvid -i ...

Soweit ich weiß, können wir derzeit keinen Videoframe extrahieren, indem wir nur eine NVIDIA-Karte in FFmpeg verwenden, da diese Funktion nicht existiert, ebenso wie kein Codec wie mjpeg_nvenc oder etwas anderes existiert. Bitte korrigieren Sie mich, wenn ich falsch liege.

Ich denke, wir sollten in der Lage sein, einen Videostream auf der NVIDIA-Karte zu decodieren und dann einen Frame über den CPU-Codec zu extrahieren, zum Beispiel mjpeg:

ffmpeg -hwaccel cuvid -c:v h264_cuvid -i video_source -vcodec mjpeg -vframes 1 /tmp/frame.jpg

In diesem Fall erhalten wir den folgenden Fehler:

Konvertieren zwischen den vom Filter 'Parsed_null_0' und dem Filter 'auto_scaler_0' unterstützten Formaten nicht möglich.
Fehler beim Reinitialisieren der Filter!
Frame konnte nicht in das Filternetzwerk eingefügt werden: Funktion nicht implementiert

NVIDIA dekodiert Videos in das Pixelformat NV12 (standardmäßig) oder NV21, und es ist kein geeignetes Format für den mjpeg-Codec. Bitte korrigiert mich auch, wenn ich falsch liege.
Versuchen wir, die Ausgabeauflösung zu ändern und das Pixelformat über scale_npp in yuvj420p zu konvertieren, da mjpeg-Codes dies unterstützen:

ffmpeg -hwaccel cuvid -c:v h264_cuvid -i video_source -vcodec mjpeg -vf "hwupload_cuda,scale_npp=w=1024:h=70:format=nv12:interp_algo=lanczos,hwdownload,format=yuvj420p" -vframes 1 /tmp/ Rahmen.jpg

Ich habe den gleichen Fehler:

Konvertieren zwischen den vom Filter 'Parsed_null_0' und dem Filter 'auto_scaler_0' unterstützten Formaten nicht möglich.
Fehler beim Reinitialisieren der Filter!
Frame konnte nicht in das Filternetzwerk eingefügt werden: Funktion nicht implementiert

Laut der FFmpeg-Dokumentation wird die Formatkonvertierung nicht unterstützt: " Beachten Sie, dass die automatische Formatverhandlung und -konvertierung für Hardware-Frames noch nicht unterstützt wird "

Wie dekodiert man einen eingegebenen h264-Stream über den h264_cuvid-Decoder, konvertiert dann das dekodierte Videopixelformat in yuvj420p und extrahiert einen Frame über den mjpeg-Codec?
Oder teilen Sie bitte Ihre Gedanken mit, wie Sie einen Frame aus einem Videostream mit Decodierung oder Decodierung und Codierung auf einer NVIDIA-Karte in ein beliebiges Bildformat extrahieren können.

scale_npp unterstützt yuv420p.
@Gyan Danke für den Kommentar! Ich habe den folgenden Befehl ausprobiert: ffmpeg -hwaccel cuvid -c:v h264_cuvid -i video_source -vcodec mjpeg -vf "hwupload_cuda,scale_npp=w=1024:h=70:format=nv12:interp_algo=lanczos,hwdownload,format=yuv420p" -vframes 1 /tmp/frame.jpg Und erhalte den gleichen Fehler: „Konvertieren zwischen den Formaten, die vom Filter ‚Parsed_null_0‘ und dem Filter ‚auto_scaler_0‘ unterstützt werden, ist nicht möglich "
Das Format in scale_npp muss auf yuv420p geändert werden
@Gyan Danke! Ich habe die Formate im Befehl auf yuv420p geändert: ffmpeg -hwaccel cuvid -c:v h264_cuvid -i video_source -vcodec mjpeg -vf "hwupload_cuda,scale_npp=w=1024:h=70:format=yuv420p:interp_algo=lanczos,hwdownload, format=yuv420p" -vframes 1 /tmp/frame.jpg Leider hat es nicht geholfen und ich bekam den gleichen Fehler.
Ich habe keine kompatible Karte zum Testen, aber die decodierten Frames sollten sich bereits auf der GPU befinden, ist also hwupload erforderlich?
@Gyan Vielen Dank! Der korrekte Befehl mit Größenänderung beim Dekodierungsschritt lautet: ffmpeg -hwaccel cuvid -c:v h264_cuvid -resize 1024x70 -i video_source -vf "scale_npp=format=yuv420p,hwdownload,format=yuv420p" -vframes 1 -y /tmp/frame .jpg Können Sie bitte eine Antwort schreiben? Ich werde es akzeptieren.

Antworten (2)

Da der Video-Bitstream auf der GPU decodiert wird, ist kein CUDA-Upload erforderlich.

Befehl mit Formatkonvertierung ist

ffmpeg -hwaccel cuvid -c:v h264_cuvid -resize 1024x70 -i video_source \
       -vf "scale_npp=format=yuv420p,hwdownload,format=yuv420p" \
       -pix_fmt yuvj420p -color_range 2 -vframes 1 -y /tmp/frame.jpg

Tatsächlich können wir einen Videoframe nur mit der NVIDIA-Karte über den Filter thumbnail_cuda extrahieren. Denn es ist notwendig, FFmpeg zu konfigurieren mit:

--enable-cuda-sdk --enable-filter=scale_cuda --enable-filter=thumbnail_cuda

Wir können die Größe der Frames beim Dekodierungsschritt ändern, dann ist es nicht erforderlich, den scale_npp-Filter zu verwenden. Wenn wir den Filter thumbnail_cuda verwenden, können wir NV12 als Ausgabeformat festlegen, um eine zusätzliche Konvertierung des Pixelformats zu verhindern. NV12 wird in yuvj420p ohne yuv420p in der Mitte konvertiert.

Der FFmpeg-Befehl zum Ausführen für einen h264-Stream sieht wie folgt aus:

ffmpeg -hwaccel cuvid -c:v h264_cuvid -resize 120x70 -i video_source \
       -vf "thumbnail_cuda=2,hwdownload,format=nv12" \
       -vframes 1 frame.jpg

Wenn wir mpeg2, hevc, vp8 usw. decodieren müssen, sollten wir einen geeigneten Decoder aus der Liste auswählen:

ffmpeg -decoders | grep cuvid

 V..... h264_cuvid           Nvidia CUVID H264 decoder (codec h264)
 V..... hevc_cuvid           Nvidia CUVID HEVC decoder (codec hevc)
 V..... mjpeg_cuvid          Nvidia CUVID MJPEG decoder (codec mjpeg)
 V..... mpeg1_cuvid          Nvidia CUVID MPEG1VIDEO decoder (codec mpeg1video)
 V..... mpeg2_cuvid          Nvidia CUVID MPEG2VIDEO decoder (codec mpeg2video)
 V..... mpeg4_cuvid          Nvidia CUVID MPEG4 decoder (codec mpeg4)
 V..... vc1_cuvid            Nvidia CUVID VC1 decoder (codec vc1)
 V..... vp8_cuvid            Nvidia CUVID VP8 decoder (codec vp8)
 V..... vp9_cuvid            Nvidia CUVID VP9 decoder (codec vp9)