Streampunk / beamcoder

Node.js native bindings to FFmpeg.
GNU General Public License v3.0
397 stars 76 forks source link

GPU accelerated scale_npp, hw_frames context missing #43

Open jpietek opened 4 years ago

jpietek commented 4 years ago

Hi,

I'm trying to recreate the following ffmpeg graph in beamcoder: ./ffmpeg -loglevel verbose -y -c:v h264_cuvid -i input.ts -filter_complex "fps=30000/1001,hwupload_cuda,scale_npp=1920:1080:interp_algo=lanczos" -c:a copy -c:v h264_nvenc -f mpegts out.ts

The ffmpeg was built according to the instructions below, it works fine with ffmpeg itself. https://devblogs.nvidia.com/nvidia-ffmpeg-transcoding-guid

But with beamcoder filter having pixfmt nv12 at input and cuda at output + filter string: const scale_str = "hwupload_cuda,scale_npp=" + dst_width + ":" + dst_height + ':interp_algo=lanczos'

...it doesn't work:

[h264_nvenc @ 0x4ac5900] hw_frames_ctx must be set when using GPU frames as input
[h264_nvenc @ 0x4ac5900] Nvenc unloaded

Adding hwdownload and converting the pixfmt back to nv12 is fine, but the performance is degraded to a similar level as a regular cpu libav scale filter. Plain decode+encode (without scaling) works fine in Beamcoder too. Seems like it's not yet implemented in BC?

// TODO hw_frames_ctx
// TODO hw_device_ctx
    { "hwaccel_flags", nullptr, nullptr,
      encoding ? nullptr : getCodecCtxHwAccelFlags,
      encoding ? failEncoding : setCodecCtxHwAccelFlags, nullptr,
      encoding ? napi_default : (napi_property_attributes) (napi_writable | napi_enumerable), codec},

Any hints on how to port if from ffmpeg? At minimum I would like to add support for copying hw_frames_ctx of scale_npp and pass it to the encoder.

Thanks in advance! JP.

jpietek commented 4 years ago

FYI, I think I've figured it out, in encoder.cc:

     case AVERROR(EINVAL):
         // if hw context is present in frame, copy it to the encoder
         if(c->encoder->hw_frames_ctx == nullptr && (*it)->hw_frames_ctx != nullptr) {
            c->encoder->hw_frames_ctx = av_buffer_ref((*it)->hw_frames_ctx);
        }
       if ((ret = avcodec_open2(c->encoder, c->encoder->codec, nullptr))) {
         c->status = BEAMCODER_ERROR_ALLOC_ENCODER;
         c->errorMsg = avErrorMsg("Problem opening encoder: ", ret);
         return;
       }
       goto bump;