On 04/12/2018 01:46, Sun, Jing A wrote:
> Hi Mark,
> 
> Is there any issue that I need to fix for this patch please? 

See comments in the message you quoted below?  I think the most important point 
is that the existing timing information appears to contain all the information 
you want for VFR, so you probably shouldn't need the ad-hoc side-data type.

- Mark


> -----Original Message-----
> From: ffmpeg-devel [mailto:ffmpeg-devel-boun...@ffmpeg.org] On Behalf Of Sun, 
> Jing A
> Sent: Friday, November 23, 2018 5:37 PM
> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
> Subject: Re: [FFmpeg-devel] [PATCH 1/1] avcodec/vaapi_encode: add frame-skip 
> func
> 
> Hi Mark,
> 
> In some cases, that is useful. For example, an online content distributer, 
> who keeps encoding the captured video frames by ffmpeg and sending them out. 
> At times, there is no update of source, which makes one or several captured 
> source frames are exactly the same as the last one, and the distributer wants 
> to just skip such frames, without stopping the encoding process.
> 
> Regards,
> SUN, Jing
> 
> 
> -----Original Message-----
> From: ffmpeg-devel [mailto:ffmpeg-devel-boun...@ffmpeg.org] On Behalf Of Mark 
> Thompson
> Sent: Tuesday, November 20, 2018 4:07 AM
> To: ffmpeg-devel@ffmpeg.org
> Subject: Re: [FFmpeg-devel] [PATCH 1/1] avcodec/vaapi_encode: add frame-skip 
> func
> 
> On 19/11/18 09:04, Jing SUN wrote:
>> frame-skip is required to implement network bandwidth self-adaptive 
>> vaapi encoding.
>> To make a frame skipped, allocate its frame side data of 
>> AV_FRAME_DATA_SKIP_FRAME type and set its value to 1.
> 
> So if I'm reading this correctly the idea is to implement partial VFR by 
> having a special new side-data type which indicates where frames would have 
> been had the input actually matched the configured CFR behaviour?
> 
> Why is the user meant to create these special frames?  It seems to me that 
> the existing method of looking at the timestamps would be a better way to 
> find any gaps.
> 
> (Or, even better, add timestamps to VAAPI so that it can support VFR in a 
> sensible way rather than adding hacks like this to allow partial VFR with 
> weird constraints.)
> 
>> Signed-off-by: Jing SUN <jing.a....@intel.com>
>> ---
>>  libavcodec/vaapi_encode.c | 142 
>> ++++++++++++++++++++++++++++++++++++++++++++--
>>  libavcodec/vaapi_encode.h |   5 ++
>>  libavutil/frame.c         |   1 +
>>  libavutil/frame.h         |   5 ++
>>  4 files changed, 149 insertions(+), 4 deletions(-)
>>
>> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c 
>> index 2fe8501..a401d61 100644
>> --- a/libavcodec/vaapi_encode.c
>> +++ b/libavcodec/vaapi_encode.c
>> @@ -23,6 +23,7 @@
>>  #include "libavutil/common.h"
>>  #include "libavutil/log.h"
>>  #include "libavutil/pixdesc.h"
>> +#include "libavutil/intreadwrite.h"
>>  
>>  #include "vaapi_encode.h"
>>  #include "avcodec.h"
>> @@ -103,6 +104,47 @@ static int 
>> vaapi_encode_make_param_buffer(AVCodecContext *avctx,
>>      return 0;
>>  }
>>  
>> +static int vaapi_encode_check_if_skip(AVCodecContext *avctx,
>> +                                      VAAPIEncodePicture *pic) {
>> +    AVFrameSideData *fside = NULL;
>> +    VAAPIEncodeContext *ctx = avctx->priv_data;
>> +    VAAPIEncodePicture *cur = NULL;
>> +    int i = 0;
>> +
>> +    if (!pic || !pic->input_image)
>> +        return AVERROR(EINVAL);
>> +
>> +    fside = av_frame_get_side_data(pic->input_image, 
>> AV_FRAME_DATA_SKIP_FRAME);
>> +    if (fside)
>> +        pic->skipped_flag = AV_RL8(fside->data);
>> +    else
>> +        pic->skipped_flag = 0;
>> +
>> +    if (0 == pic->skipped_flag)
>> +        return 0;
>> +
>> +    if ((pic->type == PICTURE_TYPE_IDR) || (pic->type == PICTURE_TYPE_I)) {
>> +        av_log(avctx, AV_LOG_INFO, "Can't skip IDR/I pic 
>> %"PRId64"/%"PRId64".\n",
>> +               pic->display_order, pic->encode_order);
>> +        pic->skipped_flag = 0;
>> +        return 0;
>> +    }
>> +
>> +    for (cur = ctx->pic_start; cur; cur = cur->next) {
>> +        for (i=0; i < cur->nb_refs; ++i) {
>> +            if (cur->refs[i] == pic) {
>> +                av_log(avctx, AV_LOG_INFO, "Can't skip ref pic 
>> %"PRId64"/%"PRId64".\n",
>> +                       pic->display_order, pic->encode_order);
>> +                pic->skipped_flag = 0;
>> +                return 0;
>> +            }
>> +        }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>>  static int vaapi_encode_wait(AVCodecContext *avctx,
>>                               VAAPIEncodePicture *pic)  { @@ -418,6
>> +460,69 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>>          }
>>      }
>>  
>> +    err = vaapi_encode_check_if_skip(avctx, pic);
>> +    if (err != 0)
>> +        av_log(avctx, AV_LOG_ERROR, "Fail to check if skip.\n");
>> +
>> +#ifdef VAEncMiscParameterSkipFrame
>> +    if (pic->skipped_flag) {
>> +        av_log(avctx, AV_LOG_INFO, "Skip pic %"PRId64"/%"PRId64" as 
>> requested.\n",
>> +               pic->display_order, pic->encode_order);
>> +
>> +        ++ctx->skipped_pic_count;
>> +        pic->encode_issued = 1;
>> +
>> +        return 0;
>> +    } else if (ctx->skipped_pic_count > 0) {
>> +        VABufferID skip_param_id;
>> +        VAEncMiscParameterBuffer *misc_param;
>> +        VAEncMiscParameterSkipFrame *skip_param;
>> +
>> +        err = vaapi_encode_make_param_buffer(avctx, pic,
>> +                  VAEncMiscParameterBufferType, NULL,
>> +                  (sizeof(VAEncMiscParameterBuffer) +
>> +                  sizeof(VAEncMiscParameterSkipFrame)));
>> +        if (err < 0)
>> +            goto fail;
>> +
>> +        skip_param_id = pic->param_buffers[pic->nb_param_buffers-1];
>> +
>> +        vas = vaMapBuffer(ctx->hwctx->display,
>> +                          skip_param_id,
>> +                          (void **)&misc_param);
>> +        if (vas != VA_STATUS_SUCCESS) {
>> +            av_log(avctx, AV_LOG_ERROR, "Failed to map skip-frame buffer: "
>> +                   "%d (%s).\n", vas, vaErrorStr(vas));
>> +            err = AVERROR(EIO);
>> +            goto fail;
>> +        }
>> +
>> +        misc_param->type =
>> + (VAEncMiscParameterType)VAEncMiscParameterTypeSkipFrame;
> 
> You need to check VAConfigAttribEncSkipFrame to make sure this type is 
> actually supported before using it.
> 
>> +        skip_param = (VAEncMiscParameterSkipFrame *)misc_param->data;
>> +        skip_param->skip_frame_flag = 1;
>> +        skip_param->num_skip_frames = ctx->skipped_pic_count;
>> +        skip_param->size_skip_frames = 0;
>> +
>> +        vas = vaUnmapBuffer(ctx->hwctx->display, skip_param_id);
>> +        if (vas != VA_STATUS_SUCCESS) {
>> +            av_log(avctx, AV_LOG_ERROR, "Failed to unmap skip-frame buffer: 
>> "
>> +                   "%d (%s).\n", vas, vaErrorStr(vas));
>> +            err = AVERROR(EIO);
>> +            goto fail;
>> +        }
> 
> make_param_buffer can be called with the intended data directly - there is no 
> need for this map/unmap.
> 
>> +
>> +        ctx->skipped_pic_count = 0;
>> +    }
>> +#else
>> +    if (pic->skipped_flag) {
>> +        av_log(avctx, AV_LOG_INFO, "Skip-frame isn't supported and pic 
>> %"PRId64"/%"PRId64" isn't skipped.\n",
>> +               pic->display_order, pic->encode_order);
>> +
>> +        pic->skipped_flag = 0;
>> +        ctx->skipped_pic_count = 0;
>> +    }
>> +#endif
>> +
>>      vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context,
>>                           pic->input_surface);
>>      if (vas != VA_STATUS_SUCCESS) {
>> @@ -500,9 +605,28 @@ static int vaapi_encode_output(AVCodecContext *avctx,
>>      VAStatus vas;
>>      int err;
>>  
>> -    err = vaapi_encode_wait(avctx, pic);
>> -    if (err < 0)
>> -        return err;
>> +    if (!pic->skipped_flag) {
>> +        err = vaapi_encode_wait(avctx, pic);
>> +        if (err < 0)
>> +            return err;
>> +    } else {
>> +        av_frame_free(&pic->input_image);
>> +        pic->encode_complete = 1;
>> +
>> +        err = av_new_packet(pkt, 0);
>> +        if (err < 0)
>> +            goto fail;
>> +
>> +        pkt->pts = pic->pts;
>> +
>> +        av_buffer_unref(&pic->output_buffer_ref);
>> +        pic->output_buffer = VA_INVALID_ID;
>> +
>> +        av_log(avctx, AV_LOG_DEBUG, "Output 0 byte for pic 
>> %"PRId64"/%"PRId64".\n",
>> +               pic->display_order, pic->encode_order);
> 
> Why is it helpful to create a zero-byte packet in this case?  Since no frame 
> was encoded, I think no packet should be produced.
> 
>> +
>> +        return 0;
>> +    }
>>  
>>      buf_list = NULL;
>>      vas = vaMapBuffer(ctx->hwctx->display, pic->output_buffer, @@
>> -523,6 +647,9 @@ static int vaapi_encode_output(AVCodecContext *avctx,
>>              goto fail_mapped;
>>  
>>          memcpy(pkt->data, buf->buf, buf->size);
>> +
>> +        memset(buf->buf, 0, buf->size);
>> +        buf->size = 0;
> 
> Seems unrelated?
> 
>>      }
>>  
>>      if (pic->type == PICTURE_TYPE_IDR) @@ -556,7 +683,12 @@ fail:
>>  static int vaapi_encode_discard(AVCodecContext *avctx,
>>                                  VAAPIEncodePicture *pic)  {
>> -    vaapi_encode_wait(avctx, pic);
>> +    if (!pic->skipped_flag) {
>> +        vaapi_encode_wait(avctx, pic);
>> +    } else {
>> +        av_frame_free(&pic->input_image);
>> +        pic->encode_complete = 1;
>> +    }
>>  
>>      if (pic->output_buffer_ref) {
>>          av_log(avctx, AV_LOG_DEBUG, "Discard output for pic "
>> @@ -1994,6 +2126,8 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
>>          }
>>      }
>>  
>> +    ctx->skipped_pic_count = 0;
>> +
>>      return 0;
>>  
>>  fail:
>> diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h 
>> index 965fe65..bcee0b6 100644
>> --- a/libavcodec/vaapi_encode.h
>> +++ b/libavcodec/vaapi_encode.h
>> @@ -92,6 +92,8 @@ typedef struct VAAPIEncodePicture {
>>  
>>      int          nb_slices;
>>      VAAPIEncodeSlice *slices;
>> +
>> +    uint8_t skipped_flag;
>>  } VAAPIEncodePicture;
>>  
>>  typedef struct VAAPIEncodeProfile {
>> @@ -246,6 +248,9 @@ typedef struct VAAPIEncodeContext {
>>      int gop_counter;
>>      int p_counter;
>>      int end_of_stream;
>> +
>> +    // Skipped frame info
>> +    unsigned int skipped_pic_count;
>>  } VAAPIEncodeContext;
>>  
>>  enum {
>> diff --git a/libavutil/frame.c b/libavutil/frame.c index
>> 9b3fb13..c5fa205 100644
>> --- a/libavutil/frame.c
>> +++ b/libavutil/frame.c
>> @@ -840,6 +840,7 @@ const char *av_frame_side_data_name(enum 
>> AVFrameSideDataType type)
>>      case AV_FRAME_DATA_QP_TABLE_PROPERTIES:         return "QP table 
>> properties";
>>      case AV_FRAME_DATA_QP_TABLE_DATA:               return "QP table data";
>>  #endif
>> +    case AV_FRAME_DATA_SKIP_FRAME:                  return "Skip frame";
>>      }
>>      return NULL;
>>  }
>> diff --git a/libavutil/frame.h b/libavutil/frame.h index
>> 66f27f4..8ef6475 100644
>> --- a/libavutil/frame.h
>> +++ b/libavutil/frame.h
>> @@ -166,6 +166,11 @@ enum AVFrameSideDataType {
>>       * function in libavutil/timecode.c.
>>       */
>>      AV_FRAME_DATA_S12M_TIMECODE,
>> +
>> +    /**
>> +     * VAAPI Encode skip-frame indicator.
>> +     */
>> +    AV_FRAME_DATA_SKIP_FRAME,
>>  };
>>  
>>  enum AVActiveFormatDescription {
>>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to