2017-11-01 2 views
3

Ich habe eine einfache C++ - Anwendung, die FFmpeg 3.2 verwendet, um einen H264 RTP-Stream zu empfangen. Um CPU zu sparen, mache ich den Dekodierungsteil mit dem Codec h264_cuvid. Mein FFmpeg 3.2 ist mit aktivierter hw-Beschleunigung kompiliert. wenn ich den Befehl in der Tat zu tun:Wie kann ich ein FFmpeg AVFrame mit Pixel-Format AV_PIX_FMT_CUDA in ein neues AVFrame mit Pixel-Format konvertieren AV_PIX_FMT_RGB

ffmpeg -hwaccels 

ich

cuvid 

Das bedeutet, dass mein FFmpeg Setup alles OK zu "sprechen" mit meiner NVIDIA-Karte hat. Die Frames, die mir die Funktion avcodec_decode_video2 liefert, haben das Pixelformat AV_PIX_FMT_CUDA. Ich muss diese Rahmen zu neuen mit AV_PIX_FMT_RGB konvertieren. Leider kann ich die Konvertierung nicht mit den wohlbekannten Funktionen sws_getContext und sws_scale durchführen, da das Pixelformat AV_PIX_FMT_CUDA nicht unterstützt wird. Wenn ich mit swscale versuchen bekomme ich den Fehler:

„CUDA nicht als Eingangspixelformat unterstützt wird“

Wissen Sie, wie ein FFmpeg AVFrame von AV_PIX_FMT_CUDA zu AV_PIX_FMT_RGB konvertieren? (Teile des Codes würden sehr geschätzt werden)

+0

Wenn alles, was Sie brauchen, mit Cuvid zu dekodieren, ich denke, es gibt keine Notwendigkeit, mit AV_PIX_FMT_CUDA umzugehen. Obwohl es dafür kein Beispiel gibt, könnte das offizielle Beispiel 'qsvdec.c' und' hw_decode.c' eine gute Referenz sein. Und der Decoder sollte hier das nv12-Format zum Host-Speicher zurückgeben. – halfelf

Antwort

0

Sie müssen vf_scale_npp verwenden, um dies zu tun. Sie können entweder nppscale_deinterleave oder abhängig von Ihren Bedürfnissen verwenden.

Beide gleichen Eingangsparameter hat, die AVFilterContext sind die NPPScaleStageContext mit nppscale_init, werden initialisieren sollte das Format Ihre in/out-Pixel nimmt und zwei AVFrame s, die natürlich Ihre Ein- und Ausgaberahmen sind.

Für weitere Informationen sehen Sie npplib\nppscale Definition, die die CUDA-beschleunigte Formatkonvertierung und Skalierung seit FFmpeg 3.1 tun wird.

Wie auch immer, ich empfehle, NVIDIA Video Codec SDK direkt für diesen Zweck zu verwenden.

+0

Hallo Hamed. Vielen Dank für deine Antwort. Ich werde das vf_scale_npp studieren. Die Funktionen static int nppscale_Deinterleave (AVFilterContext * ctx, NPPScaleStageContext * Bühne, AVFrame * out, AVFrame * in); statisch int nppscale_resize (AVFilterContext * ctx, NPPScaleStageContext * Bühne, AVFrame * out, AVFrame * in); scheinen wirklich vielversprechend. Ich werde mir bald Feedback geben. Nochmals vielen Dank – costef

+0

@costef Sie sind herzlich willkommen. Viel Glück. – Hamed

+0

Hallo Hamed. Ich habe es versucht, aber ohne Erfolg. Ich bekomme Erfolg von der Funktion "nppscale_init" aber Ausfall von "nppscale_deinterleave". Von diesem letzten bekomme ich den Fehlercode: [in @ 0x7fff69b97820] NPP deinterleave Fehler: -8 Anscheinend ist das Problem in meinem "in" AVFrame. Aber was ? Weißt du, was es bedeutet? Sie haben außerdem vorgeschlagen, das NVIDIA Video Codec SDK direkt für solche Konvertierungen zu verwenden. Ich bin bereit, es zu benutzen. FFmpeg fehlt hier an Dokumentation und guten Beispielen. Hast du ein Stück Code, vielleicht eine Funktion, die einen AVFrame von cuvid bekommt und einen neuen in AV_PIX_FMT_RGB zurückgibt? – costef

0

Ich bin kein ffmpeg Experte, aber ich hatte ein ähnliches Problem und es geschafft, es zu lösen. Ich bekam AV_PIX_FMT_NV12 von Cuvid (Mjpeg_cuvid Decoder) und wollte AV_PIX_FMT_CUDA für Cuda Verarbeitung.

Ich fand, dass die Einstellung des Pixel-Format unmittelbar vor der Decodierung des Frames funktionierte.

pCodecCtx->pix_fmt = AV_PIX_FMT_CUDA; // change format here 
    avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 
    // do something with pFrame->data[0] (Y) and pFrame->data[1] (UV) 

können Sie überprüfen, welche Pixelformate von Ihrem Decoder pix_fmts unterstützt:

AVCodec *pCodec = avcodec_find_decoder_by_name("mjpeg_cuvid"); 
    for (int i = 0; pCodec->pix_fmts[i] != AV_PIX_FMT_NONE; i++) 
      std::cout << pCodec->pix_fmts[i] << std::endl; 

Ich bin sicher, dass es ein besserer Weg, dies zu tun, aber ich habe dann this Liste die ganze Zahl zur Karte Pixelformat-IDs für von Menschen lesbare Pixelformate.

Wenn das nicht funktioniert, können Sie eine cudaMemcpy tun, um Ihre Pixel von Gerät zu übertragen Gastgeber:

cudaMemcpy(pLocalBuf pFrame->data[0], size, cudaMemcpyDeviceToHost); 

Die Umwandlung von YUV auf RGB/RGBA können viele Arten erfolgen. This example tut es mit der libavdevice API.

Verwandte Themen