bytedeco / javacv

Java interface to OpenCV, FFmpeg, and more
Other
7.51k stars 1.58k forks source link

How to use hwaccel to open dxva2 acceleration in grabber? #1565

Closed 4714407 closed 3 years ago

4714407 commented 3 years ago

The following code doesn't seem to work

AVBufferRef hw_context=av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DXVA2); if ((ret=av_hwdevice_ctx_create(hw_context,AV_HWDEVICE_TYPE_DXVA2,(String)null,null,0))<0){ releaseUnsafe(); throw new Exception("av_hwdevice_ctx_create() error " + ret + ": Could not create hwdevice context."); } if (video_c.hwaccel_context(av_buffer_ref(hw_context))==null){ releaseUnsafe(); throw new Exception("hwaccel_context() error : Could not set hwaccel "+av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_DXVA2).getString()+" ."); }

saudet commented 3 years ago

Normally we just need to set the codec, like FFmpegFrameGrabber.setVideoCodecName("h264_dxva2").

/cc @n-kai-cj

4714407 commented 3 years ago

setVideoCodecName or setVideoCodec? I use the following method to view all codecs, without this codec Pointer pointer = new Pointer((Pointer)null); while ((c = av_codec_iterate(pointer)) != null) { if (av_codec_is_decoder(c)>0) logger.debug("{}:{} ", c.name().getString(),c.type()); }

saudet commented 3 years ago

Then your system doesn't support DXVA2, I guess...

4714407 commented 3 years ago

I have no problem using the following command line:

./ffmpeg -hwaccel dxva2 -c:v h264 -threads 0 -i d:\ test.mp4 -f null - -benchmark

4714407 commented 3 years ago

I checked with the following code and found no problem AVCodecHWConfig avCodecHWConfig=null; for (int i = 0;; i++) { avCodecHWConfig= avcodec_get_hw_config(codec, i); if (avCodecHWConfig == null) { logger.debug("codec{} not support hw",codec.name().getString()); break; }else{ if ((avCodecHWConfig.methods() & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)>0 && avCodecHWConfig.device_type() == hwdevice) { logger.debug("codec{} support{}",codec.name().getString(),av_hwdevice_get_type_name(hwdevice).getString()); break; } } } when hwdevice=AV_HWDEVICE_TYPE_DXVA2 print support

4714407 commented 3 years ago

I added the following code to the decoding logic( FFmpegFrameGrabber.java 1322 row), but AV hwframe transfer_ Data caused a JVM crash


int len = avcodec_decode_video2(video_c, picture, got_frame, pkt);

                    // Did we get a video frame?
                    if (len >= 0 && got_frame[0] != 0
                            && (!keyFrames || picture.pict_type() == AV_PICTURE_TYPE_I)) {

                        long pts = av_frame_get_best_effort_timestamp(picture);
                        AVRational time_base = video_st.time_base();
                        timestamp = 1000000L * pts * time_base.num() / time_base.den();
                        // best guess, AVCodecContext.frame_number = number of decoded frames...
                        frameNumber = (int)Math.round(timestamp * getFrameRate() / 1000000L);
                        frame.image = image_buf;
                        if (picture.format() == AV_PIX_FMT_DXVA2_VLD) {
                            /* retrieve data from GPU to CPU */
                            AVFrame hwframe = null;
                            if ((hwframe = av_frame_alloc()) == null) {
                                throw new Exception("av_frame_alloc() error: Could not allocate raw hwframe.");
                            }
                            if ((av_hwframe_transfer_data(hwframe, picture, 0)) < 0) {
                                throw new Exception("Error transferring the data to system memory");
                            }

                        }
saudet commented 3 years ago

We probably need to allocate memory for that frame...

4714407 commented 3 years ago

When I use the API method "avcodec_receive_frame" recommended by ffmpeg, everything is normal. If you have time, you can consider rewriting the decoding logic and replacing the deprecated method "avcodec_decode_video2".

@deprecated Use avcodec_send_packet() and avcodec_receive_frame().

saudet commented 3 years ago

Yes, that's on the to-do list, see issue #1498. If you'd like to work on that, it would be great!

4714407 commented 3 years ago

We probably need to allocate memory for that frame...

what frame?

4714407 commented 3 years ago

I have successfully used hwaccel to turn on dxva2 acceleration (refer to ffmpeg code).

saudet commented 3 years ago

You need to make sure the pixel format of images from FFmpeg and Java 2D is the same.

saudet commented 3 years ago

When I use the API method "avcodec_receive_frame" recommended by ffmpeg, everything is normal. If you have time, you can consider rewriting the decoding logic and replacing the deprecated method "avcodec_decode_video2".

@deprecated Use avcodec_send_packet() and avcodec_receive_frame().

I've switched to that new API in commit https://github.com/bytedeco/javacv/commit/c952a23cc33ace29688ce577ce116d65bb1146b4. Please give it a try with the snapshots: http://bytedeco.org/builds/

gaoyuchris commented 2 years ago

I have successfully used hwaccel to turn on dxva2 acceleration (refer to ffmpeg code).

@4714407 ,hello, I wonder if you can give me the demo of how to use the hwaccel to turn on dxva2 acceleration by javacv,. if not, can you tell me how to use the method "get_format" by javacv. many thanks