diff mbox series

[FFmpeg-devel,1/3] avutil/frame: make frame copy functions hwframe aware

Message ID 20200327204303.29174-1-timo@rothenpieler.org
State Accepted
Headers show
Series [FFmpeg-devel,1/3] avutil/frame: make frame copy functions hwframe aware | expand

Checks

Context Check Description
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Timo Rothenpieler March 27, 2020, 8:43 p.m. UTC
---
 libavutil/frame.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

Comments

James Almer March 27, 2020, 8:53 p.m. UTC | #1
On 3/27/2020 5:43 PM, Timo Rothenpieler wrote:
> ---
>  libavutil/frame.c | 23 ++++++++++++++++++++---
>  1 file changed, 20 insertions(+), 3 deletions(-)
> 
> diff --git a/libavutil/frame.c b/libavutil/frame.c
> index e4038096c2..0c64f4a422 100644
> --- a/libavutil/frame.c
> +++ b/libavutil/frame.c
> @@ -25,6 +25,7 @@
>  #include "imgutils.h"
>  #include "mem.h"
>  #include "samplefmt.h"
> +#include "hwcontext.h"
>  
>  #if FF_API_FRAME_GET_SET
>  MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp)
> @@ -626,9 +627,22 @@ int av_frame_make_writable(AVFrame *frame)
>      tmp.channels       = frame->channels;
>      tmp.channel_layout = frame->channel_layout;
>      tmp.nb_samples     = frame->nb_samples;
> -    ret = av_frame_get_buffer(&tmp, 32);
> -    if (ret < 0)
> -        return ret;
> +
> +    if (frame->hw_frames_ctx) {
> +        ret = av_hwframe_get_buffer(frame->hw_frames_ctx, &tmp, 0);
> +        if (ret < 0)
> +            return ret;
> +
> +        tmp.hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);

This is already done by av_hwframe_get_buffer().

> +        if (!tmp.hw_frames_ctx) {
> +            av_frame_unref(&tmp);
> +            return AVERROR(ENOMEM);
> +        }
> +    } else {
> +        ret = av_frame_get_buffer(&tmp, 32);
> +        if (ret < 0)
> +            return ret;
> +    }
>  
>      ret = av_frame_copy(&tmp, frame);
>      if (ret < 0) {
> @@ -752,6 +766,9 @@ static int frame_copy_video(AVFrame *dst, const AVFrame *src)
>          dst->height < src->height)
>          return AVERROR(EINVAL);
>  
> +    if (src->hw_frames_ctx || dst->hw_frames_ctx)
> +        return av_hwframe_transfer_data(dst, src, 0);

Not all the hwcontext implementations support hw -> hw transfers, like
OpenCL and Vulkan.

OpenCL returns EINVAL but Vulkan ENOSYS, so that's fun. The former
should be changed i think.

> +
>      planes = av_pix_fmt_count_planes(dst->format);
>      for (i = 0; i < planes; i++)
>          if (!dst->data[i] || !src->data[i])
>
Timo Rothenpieler March 27, 2020, 9:03 p.m. UTC | #2
On 27.03.2020 21:53, James Almer wrote:
> On 3/27/2020 5:43 PM, Timo Rothenpieler wrote:
>> ---
>>   libavutil/frame.c | 23 ++++++++++++++++++++---
>>   1 file changed, 20 insertions(+), 3 deletions(-)
>>
>> diff --git a/libavutil/frame.c b/libavutil/frame.c
>> index e4038096c2..0c64f4a422 100644
>> --- a/libavutil/frame.c
>> +++ b/libavutil/frame.c
>> @@ -25,6 +25,7 @@
>>   #include "imgutils.h"
>>   #include "mem.h"
>>   #include "samplefmt.h"
>> +#include "hwcontext.h"
>>   
>>   #if FF_API_FRAME_GET_SET
>>   MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp)
>> @@ -626,9 +627,22 @@ int av_frame_make_writable(AVFrame *frame)
>>       tmp.channels       = frame->channels;
>>       tmp.channel_layout = frame->channel_layout;
>>       tmp.nb_samples     = frame->nb_samples;
>> -    ret = av_frame_get_buffer(&tmp, 32);
>> -    if (ret < 0)
>> -        return ret;
>> +
>> +    if (frame->hw_frames_ctx) {
>> +        ret = av_hwframe_get_buffer(frame->hw_frames_ctx, &tmp, 0);
>> +        if (ret < 0)
>> +            return ret;
>> +
>> +        tmp.hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);
> 
> This is already done by av_hwframe_get_buffer().

Indeed. Fixed locally.

>> +        if (!tmp.hw_frames_ctx) {
>> +            av_frame_unref(&tmp);
>> +            return AVERROR(ENOMEM);
>> +        }
>> +    } else {
>> +        ret = av_frame_get_buffer(&tmp, 32);
>> +        if (ret < 0)
>> +            return ret;
>> +    }
>>   
>>       ret = av_frame_copy(&tmp, frame);
>>       if (ret < 0) {
>> @@ -752,6 +766,9 @@ static int frame_copy_video(AVFrame *dst, const AVFrame *src)
>>           dst->height < src->height)
>>           return AVERROR(EINVAL);
>>   
>> +    if (src->hw_frames_ctx || dst->hw_frames_ctx)
>> +        return av_hwframe_transfer_data(dst, src, 0);
> 
> Not all the hwcontext implementations support hw -> hw transfers, like
> OpenCL and Vulkan.
> 
> OpenCL returns EINVAL but Vulkan ENOSYS, so that's fun. The former
> should be changed i think.

The copy would fail either way for hwframes, so I intentionally did not 
put any further checks here, and leave that kinda logic to 
av_hwframe_transfer_data.
diff mbox series

Patch

diff --git a/libavutil/frame.c b/libavutil/frame.c
index e4038096c2..0c64f4a422 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -25,6 +25,7 @@ 
 #include "imgutils.h"
 #include "mem.h"
 #include "samplefmt.h"
+#include "hwcontext.h"
 
 #if FF_API_FRAME_GET_SET
 MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp)
@@ -626,9 +627,22 @@  int av_frame_make_writable(AVFrame *frame)
     tmp.channels       = frame->channels;
     tmp.channel_layout = frame->channel_layout;
     tmp.nb_samples     = frame->nb_samples;
-    ret = av_frame_get_buffer(&tmp, 32);
-    if (ret < 0)
-        return ret;
+
+    if (frame->hw_frames_ctx) {
+        ret = av_hwframe_get_buffer(frame->hw_frames_ctx, &tmp, 0);
+        if (ret < 0)
+            return ret;
+
+        tmp.hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);
+        if (!tmp.hw_frames_ctx) {
+            av_frame_unref(&tmp);
+            return AVERROR(ENOMEM);
+        }
+    } else {
+        ret = av_frame_get_buffer(&tmp, 32);
+        if (ret < 0)
+            return ret;
+    }
 
     ret = av_frame_copy(&tmp, frame);
     if (ret < 0) {
@@ -752,6 +766,9 @@  static int frame_copy_video(AVFrame *dst, const AVFrame *src)
         dst->height < src->height)
         return AVERROR(EINVAL);
 
+    if (src->hw_frames_ctx || dst->hw_frames_ctx)
+        return av_hwframe_transfer_data(dst, src, 0);
+
     planes = av_pix_fmt_count_planes(dst->format);
     for (i = 0; i < planes; i++)
         if (!dst->data[i] || !src->data[i])